Merge release branch 22.x into main
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..f3206a4
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,37 @@
+/src/ @protocolbuffers/protobuf-compiler
+
+/src/google/protobuf/compiler/cpp @protocolbuffers/protobuf-cpp
+
+/csharp/ @protocolbuffers/protobuf-csharp
+/src/google/protobuf/compiler/csharp/ @protocolbuffers/protobuf-csharp
+
+/docs/ @protocolbuffers/protobuf-docs
+/examples/ @protocolbuffers/protobuf-docs
+
+/java/ @protocolbuffers/protobuf-java
+/src/google/protobuf/compiler/java/ @protocolbuffers/protobuf-java
+
+/java/kotlin-lite/ @protocolbuffers/protobuf-kotlin
+/java/kotlin/ @protocolbuffers/protobuf-kotlin
+
+/objectivec/ @protocolbuffers/protobuf-objc
+/src/google/protobuf/compiler/objectivec/ @protocolbuffers/protobuf-objc
+
+/php/ @protocolbuffers/protobuf-php
+/src/google/protobuf/compiler/php/ @protocolbuffers/protobuf-php
+
+/python/ @protocolbuffers/protobuf-python
+/src/google/protobuf/compiler/python/ @protocolbuffers/protobuf-python
+
+/ruby/ @protocolbuffers/protobuf-ruby
+/src/google/protobuf/compiler/ruby/ @protocolbuffers/protobuf-ruby
+
+/build_defs/ @protocolbuffers/protobuf-btr
+/cmake/ @protocolbuffers/protobuf-btr
+/pkg/ @protocolbuffers/protobuf-btr
+/toolchain/ @protocolbuffers/protobuf-btr
+/conformance/ @protocolbuffers/protobuf-btr
+/kokoro/ @protocolbuffers/protobuf-btr
+/third_party/ @protocolbuffers/protobuf-btr
+*.bazel @protocolbuffers/protobuf-btr
+/.github/ @protocolbuffers/protobuf-btr
diff --git a/.github/actions/bash/action.yml b/.github/actions/bash/action.yml
deleted file mode 100644
index d105a44..0000000
--- a/.github/actions/bash/action.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-name: 'Non-Bazel Bash Run'
-description: 'Run a bash script for Protobuf CI testing with a non-Bazel build system'
-inputs:
- credentials:
- required: true
- description: "The GCP credentials to use for reading the docker image"
- type: string
- command:
- required: true
- description: A command to run in the docker image
-
-runs:
- using: 'composite'
- steps:
- - name: Setup Runner
- uses: ./.github/actions/internal/setup-runner
-
- - name: Update stale files using Bazel
- uses: ./.github/actions/bazel
- with:
- credentials: ${{ inputs.credentials }}
- bazel-cache: regenerate-stale-files
- bash: ./regenerate_stale_files.sh $BAZEL_FLAGS
-
- - name: Run
- shell: bash
- run: ${{ inputs.command }}
diff --git a/.github/actions/bazel-docker/action.yml b/.github/actions/bazel-docker/action.yml
deleted file mode 100644
index af1104e..0000000
--- a/.github/actions/bazel-docker/action.yml
+++ /dev/null
@@ -1,75 +0,0 @@
-name: 'Docker Bazel Run'
-description: 'Run a Bazel-based docker image for Protobuf CI testing'
-inputs:
- credentials:
- required: true
- description: "The GCP credentials to use for reading the docker image"
- type: string
- image:
- required: false
- default: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:5.1.1-aec4d74f2eb6938fc53ef7d9a79a4bf2da24abc1
- description: "The docker image to use"
- type: string
- bazel-cache:
- required: true
- description: >
- A unique path for the Bazel cache. This will trigger the generation
- of a BAZEL_CACHE environment variable inside the container that provides
- the appropriate flags for any bazel command.
- type: string
- bazel:
- required: false
- description: "The Bazel command to run"
- type: string
- bash:
- required: false
- description: "A bash command to run. $BAZEL_FLAGS will be available to use for bazel runs."
- type: string
-
-runs:
- using: 'composite'
- steps:
- - name: Authenticate
- id: auth
- uses: ./.github/actions/internal/gcloud-auth
- with:
- credentials: ${{ inputs.credentials }}
-
- - name: Setup Runner
- uses: ./.github/actions/internal/setup-runner
-
- - name: Setup Bazel
- id: bazel
- uses: ./.github/actions/internal/bazel-setup
- with:
- credentials-file: /workspace/$(basename ${{ steps.auth.outputs.credentials-file }})
- bazel-cache: ${{ inputs.bazel-cache }}
-
- - name: Hook up repository Cache
- shell: bash
- run: echo "BAZEL_FLAGS=$BAZEL_FLAGS --repository_cache='/workspace/${{ env.REPOSITORY_CACHE_PATH }}'" >> $GITHUB_ENV
-
- - name: Validate inputs
- if: ${{ (inputs.bash && inputs.bazel) || (!inputs.bash && !inputs.bazel) }}
- shell: bash
- run: echo "Invalid specification of both non-Bazel and Bazel command"; exit 1
-
- - name: Run Bash Docker
- uses: ./.github/actions/internal/docker-run
- if: ${{ inputs.bash }}
- with:
- image: ${{ inputs.image }}
- run-flags: --entrypoint "/bin/bash"
- command: -l -c "${{ inputs.bash }}"
-
- - name: Run Bazel Docker
- uses: ./.github/actions/internal/docker-run
- if: ${{ !inputs.bash }}
- with:
- image: ${{ inputs.image }}
- command: ${{ inputs.bazel }} ${{ env.BAZEL_FLAGS }}
-
- - name: Save Bazel repository cache
- # Only allow repository cache updates during post-submits.
- if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_target' }}
- uses: ./.github/actions/internal/repository-cache-save
diff --git a/.github/actions/bazel/action.yml b/.github/actions/bazel/action.yml
deleted file mode 100644
index 952dfad..0000000
--- a/.github/actions/bazel/action.yml
+++ /dev/null
@@ -1,134 +0,0 @@
-name: 'Docker Bazel Run'
-description: 'Run a Bazel-based docker image for Protobuf CI testing'
-inputs:
- credentials:
- required: true
- description: The GCP credentials to use for reading the docker image
- type: string
- bazel-cache:
- required: true
- description: >
- A unique path for the Bazel cache. This will trigger the generation
- of a BAZEL_CACHE environment variable inside the container that provides
- the appropriate flags for any bazel command.
- type: string
- version:
- required: false
- description: A pinned Bazel version to use
- default: '5.1.1'
- type: string
- bazel:
- required: false
- description: The Bazel command to run
- type: string
- bash:
- required: false
- description: >
- A bash command to run. $BAZEL_FLAGS and $BAZEL_STARTUP_FLAGS will be
- available to use for bazel runs.
- type: string
-
-runs:
- using: 'composite'
- steps:
- - name: Authenticate
- id: auth
- uses: ./.github/actions/internal/gcloud-auth
- with:
- credentials: ${{ inputs.credentials }}
-
- - name: Setup Runner
- uses: ./.github/actions/internal/setup-runner
-
- - name: Setup Bazel
- id: bazel
- uses: ./.github/actions/internal/bazel-setup
- with:
- credentials-file: ${{ steps.auth.outputs.credentials-file }}
- bazel-cache: ${{ inputs.bazel-cache }}
-
- - name: Get Linux bazelisk path
- if: runner.os == 'Linux'
- shell: bash
- run: echo "BAZELISK_PATH=~/.cache/bazelisk" >> $GITHUB_ENV
-
- - name: Get MacOS bazelisk path
- if: runner.os == 'macOS'
- shell: bash
- run: echo "BAZELISK_PATH=~/Library/Caches/bazelisk" >> $GITHUB_ENV
-
- - name: Get Windows bazelisk path
- if: runner.os == 'Windows'
- shell: bash
- run: echo "BAZELISK_PATH=$LOCALAPPDATA\bazelisk" >> $GITHUB_ENV
-
- - name: Cache Bazelisk
- if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_target' }}
- uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: ${{ env.BAZELISK_PATH }}
- key: bazel-${{ runner.os }}-${{ inputs.version }}
-
- - name: Restore Bazelisk
- if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
- uses: actions/cache/restore@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: ${{ env.BAZELISK_PATH }}
- key: bazel-${{ runner.os }}-${{ inputs.version }}
-
- - name: Hook up repository Cache
- shell: bash
- run: echo "BAZEL_FLAGS=$BAZEL_FLAGS --repository_cache=$(pwd)/${{ env.REPOSITORY_CACHE_PATH }}" >> $GITHUB_ENV
-
- - name: Validate inputs
- if: ${{ (inputs.bash && inputs.bazel) || (!inputs.bash && !inputs.bazel) }}
- shell: bash
- run: echo "Invalid specification of both non-Bazel and Bazel command"; exit 1
-
- - name: Pin Bazel version
- shell: bash
- run: echo "USE_BAZEL_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
-
- - name: Output Bazel version
- shell: bash
- run: bazelisk version
-
- # Bazel has multiple Xcode calls with hardcoded timeouts. Many of these
- # end up timing out on our github runners, causing flakes on every mac
- # build that invoked Bazel. To work around this, we manually invoke these
- # calls before running Bazel to make sure they end up in Xcode's cache for
- # quicker runs later. All of these calls are obtained from xcrun calls in
- # https://github.com/bazelbuild/bazel/blob/e8a69f5d5acaeb6af760631490ecbf73e8a04eeb/tools/cpp/osx_cc_configure.bzl.
- # See https://github.com/bazelbuild/bazel/issues/17437 for more details.
- # TODO(b/269503614) Remove this once Bazel provides an official solution.
- - name: Warm up Xcode
- if: ${{ runner.os == 'macOS' }}
- shell: bash
- run: |
- mkdir -p mac_bazel_workaround
- bazelisk ${{ steps.bazel.outputs.bazel-startup-flags }} build @bazel_tools//tools/osx:xcode_locator.m $BAZEL_FLAGS
- XCODE_LOCATOR_FLAGS="--sdk macosx clang -mmacosx-version-min=10.9 -fobjc-arc -framework CoreServices -framework Foundation"
- SINGLE_ARCH_COMPILE_FLAGS="--sdk macosx clang -mmacosx-version-min=10.9 -std=c++11 -lc++ -O3"
- COMPILE_FLAGS="$SINGLE_ARCH_COMPILE_FLAGS -arch arm64 -arch x86_64 -Wl,-no_adhoc_codesign -Wl,-no_uuid -O3"
- time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $XCODE_LOCATOR_FLAGS -o mac_bazel_workaround/xcode-locator-bin $(bazel info output_base)/external/bazel_tools/tools/osx/xcode_locator.m
- time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $SINGLE_ARCH_COMPILE_FLAGS -o mac_bazel_workaround/libtool_check_unique $(bazel info output_base)/external/bazel_tools/tools/objc/libtool_check_unique.cc
- time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $COMPILE_FLAGS -o mac_bazel_workaround/libtool_check_unique $(bazel info output_base)/external/bazel_tools/tools/objc/libtool_check_unique.cc
- time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $SINGLE_ARCH_COMPILE_FLAGS -o mac_bazel_workaround/wrapped_clang $(bazel info output_base)/external/bazel_tools/tools/osx/crosstool/wrapped_clang.cc
- time env -i DEVELOPER_DIR=$DEVELOPER_DIR xcrun $COMPILE_FLAGS -o mac_bazel_workaround/wrapped_clang $(bazel info output_base)/external/bazel_tools/tools/osx/crosstool/wrapped_clang.cc
-
- - name: Run Bash
- if: ${{ inputs.bash }}
- run: ${{ inputs.bash }}
- shell: bash
-
- - name: Run Bazel
- if: ${{ !inputs.bash }}
- run: >-
- bazelisk ${{ steps.bazel.outputs.bazel-startup-flags }}
- ${{ inputs.bazel }} $BAZEL_FLAGS
- shell: bash
-
- - name: Save Bazel repository cache
- # Only allow repository cache updates during post-submits.
- if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_target'}}
- uses: ./.github/actions/internal/repository-cache-save
diff --git a/.github/actions/ccache/action.yml b/.github/actions/ccache/action.yml
deleted file mode 100644
index 2d70550..0000000
--- a/.github/actions/ccache/action.yml
+++ /dev/null
@@ -1,63 +0,0 @@
-name: 'CCache Setup'
-description: 'Run a Bazel-based docker image for Protobuf CI testing'
-inputs:
- cache-prefix:
- required: true
- description: A unique prefix to prevent cache pollution
- type: string
- support-modules:
- required: false
- description: Whether or not we need to support modules. This can result in extra cache misses.
-
-runs:
- using: 'composite'
- steps:
- - name: Configure ccache environment variables
- shell: bash
- run: |
- echo "CCACHE_BASEDIR=${{ github.workspace }}" >> $GITHUB_ENV
- echo "CCACHE_DIR=${{ github.workspace }}/.ccache" >> $GITHUB_ENV
- echo "CCACHE_COMPRESS=true" >> $GITHUB_ENV
- echo "CCACHE_COMPRESSLEVEL=5" >> $GITHUB_ENV
- echo "CCACHE_MAXSIZE=100M" >> $GITHUB_ENV
- echo "CCACHE_SLOPPINESS=clang_index_store,include_file_ctime,include_file_mtime,file_macro,time_macros" >> $GITHUB_ENV
- echo "CCACHE_DIRECT=true" >> $GITHUB_ENV
- echo "CCACHE_CMAKE_FLAGS=-Dprotobuf_ALLOW_CCACHE=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache" >> $GITHUB_ENV
-
- - name: Setup ccache on Windows
- if: ${{ runner.os == 'Windows' }}
- uses: ./.github/actions/internal/ccache-setup-windows
- - name: Setup ccache on Mac
- if: ${{ runner.os == 'macOS' }}
- shell: bash
- run: brew install ccache
-
- - name: Setup fixed path ccache caching
- uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: |
- .ccache/**
- !.ccache/lock
- !.ccache/tmp
- # Always push to a cache key unique to this commit.
- key: ${{ format('ccache-{0}-{1}-{2}', inputs.cache-prefix, github.ref_name, github.sha) }}
- # Select a cache to restore from with the follow order of preference:
- # 1) The exact same commit we're running over
- # 2) The latest cache from the current ref branch
- # 3) The latest push to the base ref of a pull request
- restore-keys: |
- ${{ format('ccache-{0}-{1}-{2}', inputs.cache-prefix, github.ref_name, github.sha) }}
- ${{ format('ccache-{0}-{1}', inputs.cache-prefix, github.ref_name) }}
- ${{ format('ccache-{0}-{1}', inputs.cache-prefix, github.base_ref) }}
-
- - name: Enable module support
- if: ${{ inputs.support-modules }}
- shell: bash
- run: |
- echo "CCACHE_SLOPPINESS=$CCACHE_SLOPPINESS,modules" >> $GITHUB_ENV
- echo "CCACHE_DEPEND=true" >> $GITHUB_ENV
-
- - name: Zero out ccache
- if: ${{ runner.os != 'Linux' }}
- shell: bash
- run: ccache -z
diff --git a/.github/actions/cross-compile-protoc/action.yml b/.github/actions/cross-compile-protoc/action.yml
deleted file mode 100644
index 23660af..0000000
--- a/.github/actions/cross-compile-protoc/action.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-name: 'Cross-compile protoc'
-description: 'Produces a cross-compiled protoc binary for a target architecture'
-inputs:
- credentials:
- required: true
- description: The GCP credentials to use for reading the docker image
- type: string
- architecture:
- required: true
- description: The target architecture to build for
- type: string
-outputs:
- protoc:
- description: "Cross-compiled protoc location. Also output to $PROTOC"
- value: ${{ steps.output.outputs.protoc }}
-
-runs:
- using: 'composite'
- steps:
- - name: Cross compile protoc for ${{ inputs.architecture }}
- uses: ./.github/actions/bazel-docker
- with:
- credentials: ${{ inputs.credentials }}
- bazel-cache: xcompile-protoc/${{ inputs.architecture }}
- bash: |
- bazel build //:protoc --config=${{ inputs.architecture }} $BAZEL_FLAGS
- cp bazel-bin/protoc .
-
- - name: Set protoc environment variable
- shell: bash
- run: echo "PROTOC=protoc-${{ inputs.architecture }}" >> $GITHUB_ENV
-
- - name: Extract binary
- id: output
- shell: bash
- run: |
- mv protoc $PROTOC
- echo "protoc=$PROTOC" >> $GITHUB_OUTPUT
diff --git a/.github/actions/docker/action.yml b/.github/actions/docker/action.yml
deleted file mode 100644
index 54de3f9..0000000
--- a/.github/actions/docker/action.yml
+++ /dev/null
@@ -1,50 +0,0 @@
-name: 'Docker Non-Bazel Run'
-description: 'Run a docker image for Protobuf CI testing with a non-Bazel build system'
-inputs:
- credentials:
- required: true
- description: "The GCP credentials to use for reading the docker image"
- type: string
- command:
- required: true
- description: A command to run in the docker image
- image:
- required: false
- default: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:5.1.1-aec4d74f2eb6938fc53ef7d9a79a4bf2da24abc1
- description: "The docker image to use"
- type: string
- platform:
- required: false
- description: "The platform to use for the image"
- type: string
- skip-staleness-check:
- required: false
- description: "Skip staleness checks"
- type: boolean
-
-runs:
- using: 'composite'
- steps:
- - name: Setup Runner
- uses: ./.github/actions/internal/setup-runner
-
- - name: Update stale files using Bazel
- if: ${{ !inputs.skip-staleness-check }}
- uses: ./.github/actions/bazel-docker
- with:
- image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:5.1.1-aec4d74f2eb6938fc53ef7d9a79a4bf2da24abc1
- credentials: ${{ inputs.credentials }}
- bazel-cache: regenerate-stale-files
- bash: ./regenerate_stale_files.sh $BAZEL_FLAGS
-
- - name: Generate docker flags
- if: inputs.platform
- shell: bash
- run: echo "DOCKER_RUN_FLAGS=--platform ${{inputs.platform}}" >> $GITHUB_ENV
-
- - name: Run Docker
- uses: ./.github/actions/internal/docker-run
- with:
- image: ${{ inputs.image }}
- command: ${{ inputs.command }}
- run-flags: ${{ env.DOCKER_RUN_FLAGS }}
diff --git a/.github/actions/internal/bazel-setup/action.yml b/.github/actions/internal/bazel-setup/action.yml
deleted file mode 100644
index 0ef5d5a..0000000
--- a/.github/actions/internal/bazel-setup/action.yml
+++ /dev/null
@@ -1,75 +0,0 @@
-name: Setup Bazel
-description: Setup a Bazel environment for Protobuf CI testing
-inputs:
- credentials-file:
- required: true
- description: The GCP credentials file to use for caching
- type: string
- bazel-cache:
- required: true
- description: A unique path for the Bazel cache.
- type: string
-
-outputs:
- bazel-flags:
- description: Bazel flags that should be sent to all Bazel invocations
- value: ${{ steps.output.outputs.bazel-flags }}
- bazel-startup-flags:
- description: Bazel startup flags that should be sent to all Bazel invocations
- value: ${{ steps.output.outputs.bazel-startup-flags }}
-
-runs:
- using: 'composite'
- steps:
- - name: Initialize BAZEL environment variable
- shell: bash
- run: echo "BAZEL=bazelisk" >> $GITHUB_ENV
-
- - name: Initialize Windows startup flags
- if: runner.os == 'Windows'
- shell: bash
- run: echo "BAZEL_STARTUP_FLAGS=--output_user_root=C:/tmp --windows_enable_symlinks" >> $GITHUB_ENV
-
- - name: Initialize Bazel flags
- shell: bash
- run: echo "BAZEL_FLAGS=--keep_going --test_output=errors --test_timeout=600" >> $GITHUB_ENV
-
- - name: Initialize Windows-specific Bazel flags
- if: runner.os == 'Windows'
- shell: bash
- run: echo "BAZEL_FLAGS=$BAZEL_FLAGS --enable_runfiles" >> $GITHUB_ENV
-
- - name: Initialize MacOS-specific Bazel flags
- if: runner.os == 'macOS'
- shell: bash
- run: |
- echo "BAZEL_FLAGS=$BAZEL_FLAGS --xcode_version_config=//.github:host_xcodes" >> $GITHUB_ENV
- echo "DEVELOPER_DIR=${{ env.DEVELOPER_DIR || '/Applications/Xcode_14.1.app/Contents/Developer' }}" >> $GITHUB_ENV
-
- - name: Configure Bazel caching
- # Skip bazel cache for local act runs due to issue with credential files
- # and nested docker images
- if: ${{ inputs.bazel-cache && !github.event.act_local_test }}
- shell: bash
- run: >-
- echo "BAZEL_FLAGS=$BAZEL_FLAGS
- --google_credentials=${{ inputs.credentials-file }}
- --remote_cache=https://storage.googleapis.com/protobuf-bazel-cache/protobuf/gha/${{ inputs.bazel-cache }}" >> $GITHUB_ENV
-
- - name: Configure Bazel cache writing
- # External runs should never write to our caches.
- if: ${{ github.event_name != 'pull_request_target' && inputs.bazel-cache && !github.event.act_local_test }}
- shell: bash
- run: echo "BAZEL_FLAGS=$BAZEL_FLAGS --remote_upload_local_results" >> $GITHUB_ENV
-
- - name: Output Bazel flags
- id: output
- shell: bash
- run: |
- echo "bazel-flags=$BAZEL_FLAGS" >> $GITHUB_OUTPUT
- echo "bazel-startup-flags=$BAZEL_STARTUP_FLAGS" >> $GITHUB_OUTPUT
-
- - name: Restore Bazel repository cache
- uses: ./.github/actions/internal/repository-cache-restore
- with:
- bazel-cache: ${{ inputs.bazel-cache }}
diff --git a/.github/actions/internal/ccache-setup-windows/action.yml b/.github/actions/internal/ccache-setup-windows/action.yml
deleted file mode 100644
index 7b9f992..0000000
--- a/.github/actions/internal/ccache-setup-windows/action.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-name: 'CCache Setup'
-description: 'Setup ccache for us in Windows CI'
-inputs:
- ccache-version:
- required: false
- default: '4.7.4'
- description: A pinned version of ccache
- type: string
-
-runs:
- using: 'composite'
- steps:
- - name: Setup MSVC
- uses: ilammy/msvc-dev-cmd@cec98b9d092141f74527d0afa6feb2af698cfe89 # v1.12.1
- with:
- arch: x64
- vsversion: '2019'
-
- - name: Setup ccache path
- shell: bash
- run: |
- echo "CCACHE_EXE_PATH=$LOCALAPPDATA\ccache-${{ inputs.ccache-version }}-windows-x86_64" >> $GITHUB_ENV
- echo "$LOCALAPPDATA\ccache-${{ inputs.ccache-version }}-windows-x86_64" >> $GITHUB_PATH
-
- - name: Add ccache to Powershell path
- shell: pwsh
- run: echo "%LOCALAPPDATA%\ccache-${{ inputs.ccache-version }}-windows-x86_64" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
-
- - name: Setup caching of ccache download
- if: ${{ github.event_name != 'pull_request' && github.event_name != 'pull_request_target' }}
- id: ccache-cache
- uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: ${{ env.CCACHE_EXE_PATH }}
- key: ccache-exe-${{ inputs.ccache-version }}
-
- - name: Restore ccache download
- if: ${{ github.event_name == 'pull_request' || github.event_name == 'pull_request_target' }}
- id: ccache-restore
- uses: actions/cache/restore@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: ${{ env.CCACHE_EXE_PATH }}
- key: ccache-exe-${{ inputs.ccache-version }}
-
- - name: Download ccache
- shell: bash
- if: ${{ steps.ccache-cache.outputs.cache-hit != 'true' && steps.ccache-restore.outputs.cache-hit != 'true'}}
- run: |
- cd $LOCALAPPDATA
- curl -kLSs "https://github.com/ccache/ccache/releases/download/v${{ inputs.ccache-version }}/ccache-${{ inputs.ccache-version }}-windows-x86_64.zip" -o ccache.zip
- unzip ccache.zip
- rm ccache.zip
- ccache --version
-
- - name: Configure ccache environment variables
- shell: pwsh
- run: |
- Write-Host $Env:GITHUB_REF
- $cllocation = (Get-Command cl.exe).Path
- echo "CCACHE_COMPILER=$cllocation" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
- echo "CCACHE_COMPILERTYPE=msvc" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append
-
- - name: Configure Windows-specific ccache environment variables
- shell: bash
- # Windows caches are about 2x larger than other platforms.
- run: |
- echo "CCACHE_COMPRESSLEVEL=10" >> $GITHUB_ENV
- echo "CCACHE_MAXSIZE=200M" >> $GITHUB_ENV
diff --git a/.github/actions/internal/docker-run/action.yml b/.github/actions/internal/docker-run/action.yml
deleted file mode 100644
index 1cc1489..0000000
--- a/.github/actions/internal/docker-run/action.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-name: 'Run Docker'
-description: 'Run a docker image for Protobuf CI testing'
-inputs:
- image:
- required: true
- description: "The docker image to use"
- type: string
- command:
- required: true
- description: "A raw docker command to run"
- type: string
- run-flags:
- required: false
- description: "Additional flags to pass to docker run"
- type: string
-
- # WARNING: loading from cache appears to be slower than pull!
- docker-cache:
- required: false
- description: "Enabled caching of pulled docker images."
-
-runs:
- using: 'composite'
- steps:
- - name: Authenticate for GAR use
- shell: bash
- run: gcloud auth configure-docker -q us-docker.pkg.dev
-
- - name: Setup QEMU for possible emulation
- uses: docker/setup-qemu-action@e81a89b1732b9c48d79cd809d8d81d79c4647a18 # v2.1.0
-
- - name: Check docker cache
- if: ${{ inputs.docker-cache }}
- id: check-docker-cache
- uses: actions/cache@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: ci/docker/
- key: ${{ inputs.image }}
-
- - name: Pull and store if cache miss
- shell: bash
- if: ${{ inputs.docker-cache && steps.check-docker-cache.outputs.cache-hit != 'true' }}
- run: >
- time docker pull -q ${{ inputs.image }} &&
- mkdir -p ci/docker/$(dirname ${{ inputs.image }}) &&
- time docker image save ${{ inputs.image }} --output ./ci/docker/${{ inputs.image }}.tar
-
- - name: Use the cached image on cache hit
- shell: bash
- if: ${{ inputs.docker-cache && steps.check-docker-cache.outputs.cache-hit == 'true' }}
- run: time docker image load --input ./ci/docker/${{ inputs.image }}.tar
-
- - name: Pull fresh docker image
- shell: bash
- if: ${{ !inputs.docker-cache }}
- run: time docker pull -q ${{ inputs.image }}
-
- - name: Run docker
- shell: bash
- run: >
- time docker run ${{ inputs.run-flags}} -v${{ github.workspace }}:/workspace
- ${{ inputs.image }} ${{ inputs.command }}
diff --git a/.github/actions/internal/gcloud-auth/action.yml b/.github/actions/internal/gcloud-auth/action.yml
deleted file mode 100644
index 189619d..0000000
--- a/.github/actions/internal/gcloud-auth/action.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-name: 'Authenticate for GCP'
-description: 'Authenticate a workflow for Protobuf CI testing'
-inputs:
- credentials:
- required: true
- description: "The GCP credentials to use for GCP"
- type: string
-
-outputs:
- credentials-file:
- description: "Credentials file generated for GCP"
- value: ${{ steps.output.outputs.credentials-file }}
-
-runs:
- using: 'composite'
- steps:
- - name: Authenticate to Google Cloud
- id: auth
- uses: google-github-actions/auth@ef5d53e30bbcd8d0836f4288f5e50ff3e086997d # v1.0.0
- with:
- credentials_json: ${{ inputs.credentials }}
- - name: Set up Cloud SDK
- uses: google-github-actions/setup-gcloud@d51b5346f85640ec2aa2fa057354d2b82c2fcbce # v1.0.1
- - name: Use gcloud CLI
- shell: bash
- run: gcloud info
-
- - name: Store credentials path
- shell: bash
- run: echo "CREDENTIALS_FILE=${{ steps.auth.outputs.credentials_file_path }}" >> $GITHUB_ENV
-
- - name: Fix credentials path (Windows)
- if: ${{ runner.os == 'Windows' }}
- # Bash commands in windows don't like the backslash in the file path.
- # Assume we're running in the root directory and grab the base name.
- shell: bash
- run: echo "CREDENTIALS_FILE="$(basename ${CREDENTIALS_FILE//\\//}) >> $GITHUB_ENV
-
- - name: Output credentials file
- id: output
- shell: bash
- run: echo "credentials-file=${{ env.CREDENTIALS_FILE }}" >> $GITHUB_OUTPUT
diff --git a/.github/actions/internal/repository-cache-restore/action.yml b/.github/actions/internal/repository-cache-restore/action.yml
deleted file mode 100644
index a5b4a0a..0000000
--- a/.github/actions/internal/repository-cache-restore/action.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-name: Restore Repository Cache
-description: Restore the Bazel repository cache from our github action cache
-inputs:
- bazel-cache:
- required: true
- description: A unique path for the Bazel cache.
- type: string
-
-# By design, these actions will restore the latest cache for this branch/os,
-# and only save a new version if something has changed. Initially this will
-# cause a lot of churn, since each test has a slightly different set of
-# repositories to download. Over time though, since we don't upload no-op
-# changes, this should converge to a stable set of 3 caches per branch. Every
-# run will update the current cache with a new test's repositories, until there
-# are no unique ones left.
-#
-# This saves asymptotic space, since each one of these can get up to ~500 MB
-# and Github prunes the cache after 10 GB.
-runs:
- using: 'composite'
- steps:
- - name: Setup Bazel repository cache variables
- shell: bash
- run: |
- REPOSITORY_CACHE_BASE=repository-cache-${{ github.base_ref || github.ref_name }}-${{ runner.os }}
- echo "REPOSITORY_CACHE_BASE=$REPOSITORY_CACHE_BASE" >> $GITHUB_ENV
- echo "REPOSITORY_CACHE_NAME=$REPOSITORY_CACHE_BASE-${{ inputs.bazel-cache}}-${{ github.sha }}" >> $GITHUB_ENV
- echo "REPOSITORY_CACHE_PATH=.repository-cache" >> $GITHUB_ENV
-
- - name: Restore Bazel repository cache
- id: restore-cache
- uses: actions/cache/restore@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: ${{ github.workspace }}/${{ env.REPOSITORY_CACHE_PATH }}
- key: ${{ env.REPOSITORY_CACHE_NAME }}
- restore-keys: ${{ env.REPOSITORY_CACHE_BASE }}
-
- - name: Initialize BAZEL environment variable
- if: ${{ steps.restore-cache.cache-hit }}
- shell: bash
- run: echo "REPOSITORY_CACHE_HASH=${{ hashFiles(format('{0}/**', env.REPOSITORY_CACHE_PATH)) }}" >> $GITHUB_ENV
diff --git a/.github/actions/internal/repository-cache-save/action.yml b/.github/actions/internal/repository-cache-save/action.yml
deleted file mode 100644
index 1324b2b..0000000
--- a/.github/actions/internal/repository-cache-save/action.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: Restore Repository Cache
-description: Restore the Bazel repository cache from our github action cache
-
-# Note: this action will only work if repository-cache-restore has already
-# been called. All bazel actions should specify the repository_cache parameter
-# using REPOSITORY_CACHE_PATH.
-#
-# We intentionally upload to REPOSITORY_CACHE_BASE to prevent a flood of new
-# caches on any change. Only 1 job per os in each test run will be allowed to
-# update the cache because they're all trying to write to the same location.
-runs:
- using: 'composite'
- steps:
- - name: Save modified Bazel repository cache
- if: ${{ env.REPOSITORY_CACHE_HASH != hashFiles(format('{0}/**', env.REPOSITORY_CACHE_PATH)) }}
- uses: actions/cache/save@627f0f41f6904a5b1efbaed9f96d9eb58e92e920 # v3.2.4
- with:
- path: ${{ github.workspace }}/${{ env.REPOSITORY_CACHE_PATH }}
- key: ${{ env.REPOSITORY_CACHE_BASE }}-${{ github.sha }}
diff --git a/.github/actions/internal/setup-runner/action.yml b/.github/actions/internal/setup-runner/action.yml
deleted file mode 100644
index 64afdc3..0000000
--- a/.github/actions/internal/setup-runner/action.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-name: Setup CI Runner
-# TODO(b/267357823) Consider moving this to it's own repository so we can
-# include the call to actions/checkout.
-description: Setup any platform-specific adjustments we need to make for CI
-runs:
- using: 'composite'
- steps:
- - name: Fix Windows line breaks
- if: runner.os == 'Windows'
- shell: bash
- run: find . -type f -print0 | xargs -0 d2u 2>/dev/null
-
- - name: Install bazelrc files
- shell: bash
- run: |
- cp ci/*.bazelrc .
- cp -f ${{ runner.os }}.bazelrc .bazelrc
diff --git a/.github/workflows/clear_caches.yml b/.github/workflows/clear_caches.yml
index 3ea213d..f7d7bce 100644
--- a/.github/workflows/clear_caches.yml
+++ b/.github/workflows/clear_caches.yml
@@ -2,8 +2,8 @@
on:
schedule:
- # Run every 1st of the month at 10 AM UTC (2 AM PDT)
- - cron: 0 10 1 * *
+ # Run every 4 months at 10 AM UTC (2 AM PDT)
+ - cron: 0 10 1 */4 *
# manual
workflow_dispatch:
diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml
index 26b4a32..84b0706 100644
--- a/.github/workflows/codespell.yml
+++ b/.github/workflows/codespell.yml
@@ -24,4 +24,4 @@
with:
check_filenames: true
skip: ./.git,./third_party,./conformance/third_party,*.snk,*.pb,*.pb.cc,*.pb.h,./src/google/protobuf/testdata,./objectivec/Tests,./python/compatibility_tests/v2.5.0/tests/google/protobuf/internal,./.github/workflows/codespell.yml
- ignore_words_list: "alow,alse,atleast,ba,chec,cleare,copyable,cloneable,dedup,dur,errorprone,falsy,files',fo,fundementals,hel,importd,inout,leapyear,nd,nin,ois,ons,parseable,process',ro,te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od,optin,streem,sur,falsy"
+ ignore_words_list: "alow,alse,atleast,ba,chec,cleare,copyable,cloneable,crate,dedup,dur,errorprone,falsy,files',fo,fundementals,hel,importd,inout,leapyear,nd,nin,ois,ons,parseable,process',ro,te,testof,ue,unparseable,wasn,wee,gae,keyserver,objext,od,optin,streem,sur,falsy,cleary"
diff --git a/.github/workflows/staleness_check.yml b/.github/workflows/staleness_check.yml
index 022d64e..f04621e 100644
--- a/.github/workflows/staleness_check.yml
+++ b/.github/workflows/staleness_check.yml
@@ -4,6 +4,7 @@
schedule:
# Run daily at 10 AM UTC (2 AM PDT)
- cron: 0 10 * * *
+ workflow_dispatch:
permissions: {}
jobs:
@@ -16,6 +17,7 @@
name: Test staleness ${{ matrix.os.name }} ${{ matrix.branch}}
runs-on: ${{ matrix.os.value }}
+ if: ${{ github.event.repository.full_name == 'protocolbuffers/protobuf' || matrix.branch == 'main '}}
steps:
- name: Checkout ${{ matrix.branch }}
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
@@ -23,7 +25,7 @@
ref: ${{ matrix.branch}}
- name: Run all staleness tests
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: staleness_check/${{ matrix.branch}}_${{ matrix.os.value }}
diff --git a/.github/workflows/staleness_refresh.yml b/.github/workflows/staleness_refresh.yml
index 8f083fd..c53e4ed 100644
--- a/.github/workflows/staleness_refresh.yml
+++ b/.github/workflows/staleness_refresh.yml
@@ -8,6 +8,7 @@
# The 21.x branch predates support for auto-generation, so we make sure
# to exclude it.
- '!21.x'
+ workflow_dispatch:
permissions: {}
jobs:
@@ -31,4 +32,4 @@
- name: Configure name and email address in Git
run: cd ${{ github.workspace }} && git config user.name "Protobuf Team Bot" && git config user.email "protobuf-team-bot@google.com"
- name: Commit and push update
- run: cd ${{ github.workspace }} && ./push_auto_update.sh
+ run: cd ${{ github.workspace }} && ./ci/push_auto_update.sh
diff --git a/.github/workflows/test_cpp.yml b/.github/workflows/test_cpp.yml
index c46a723..9dc1f50 100644
--- a/.github/workflows/test_cpp.yml
+++ b/.github/workflows/test_cpp.yml
@@ -44,7 +44,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel-docker
+ uses: protocolbuffers/protobuf-ci/bazel-docker@v1
with:
image: ${{ matrix.image }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -80,7 +80,6 @@
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/emulation:${{ matrix.arch }}-3af05275178e16af30961976af126eabbbb2c733
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
- skip-staleness-check: true
entrypoint: bash
command: >
-c "set -ex;
@@ -123,12 +122,12 @@
ref: ${{ inputs.safe-checkout }}
- name: Setup ccache
- uses: ./.github/actions/ccache
+ uses: protocolbuffers/protobuf-ci/ccache@v1
with:
cache-prefix: linux-cmake-${{ matrix.name }}
- name: Run tests
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/cmake@sha256:e0eb6c69b7551d89f0dbdbe11906077a1d501229c28db39623b945e0c5d7029a
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -145,12 +144,12 @@
ref: ${{ inputs.safe-checkout }}
- name: Setup ccache
- uses: ./.github/actions/ccache
+ uses: protocolbuffers/protobuf-ci/ccache@v1
with:
cache-prefix: linux-cmake-install
- name: Run tests
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/cmake@sha256:e0eb6c69b7551d89f0dbdbe11906077a1d501229c28db39623b945e0c5d7029a
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -174,12 +173,12 @@
ref: ${{ inputs.safe-checkout }}
- name: Setup ccache
- uses: ./.github/actions/ccache
+ uses: protocolbuffers/protobuf-ci/ccache@v1
with:
cache-prefix: linux-cmake-32-bit
- name: Run tests
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/32bit@sha256:f99f051daa8b12f4ebad5927f389bc71372f771ab080290ab451cbaf1648f9ea
platform: linux/386
@@ -212,7 +211,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel: test ${{ matrix.bazel }}
@@ -254,14 +253,14 @@
ref: ${{ inputs.safe-checkout }}
- name: Setup ccache
- uses: ./.github/actions/ccache
+ uses: protocolbuffers/protobuf-ci/ccache@v1
with:
cache-prefix: ${{ matrix.name }}
# Install phase.
- name: Configure CMake for install
if: matrix.install-flags
- uses: ./.github/actions/bash
+ uses: protocolbuffers/protobuf-ci/bash@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: cmake . ${{ matrix.install-flags }} ${{ env.CCACHE_CMAKE_FLAGS }}
@@ -283,7 +282,7 @@
run: cmake --build . --target clean && rm CMakeCache.txt
- name: Configure CMake
- uses: ./.github/actions/bash
+ uses: protocolbuffers/protobuf-ci/bash@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: cmake . ${{ matrix.flags }} ${{ env.CCACHE_CMAKE_FLAGS }}
diff --git a/.github/workflows/test_csharp.yml b/.github/workflows/test_csharp.yml
index 1fe79d4..c9e651e 100644
--- a/.github/workflows/test_csharp.yml
+++ b/.github/workflows/test_csharp.yml
@@ -18,7 +18,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel-docker
+ uses: protocolbuffers/protobuf-ci/bazel-docker@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/csharp:3.1.415-6.0.100-508417e5215994ade7585d28ba3aad681a25fa5d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -57,7 +57,7 @@
- name: Build protobuf C# tests under x86_64 docker image
# Tests are built "dotnet publish" because we want all the dependencies to the copied to the destination directory
# (we want to avoid references to ~/.nuget that won't be available in the subsequent docker run)
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -74,7 +74,7 @@
# running under current user's UID and GID. To be able to do that, we need to provide a home directory for the user
# otherwise the UID would be homeless under the docker container and pip install wouldn't work. For simplicity,
# we just run map the user's home to a throwaway temporary directory
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: mcr.microsoft.com/dotnet/sdk:6.0.100-bullseye-slim-arm64v8
skip-staleness-check: true
diff --git a/.github/workflows/test_java.yml b/.github/workflows/test_java.yml
index cea3223..f169794 100644
--- a/.github/workflows/test_java.yml
+++ b/.github/workflows/test_java.yml
@@ -39,7 +39,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel-docker
+ uses: protocolbuffers/protobuf-ci/bazel-docker@v1
with:
image: ${{ matrix.image }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -55,7 +55,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Build protoc
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: java_linux_linkage
diff --git a/.github/workflows/test_objectivec.yml b/.github/workflows/test_objectivec.yml
index 4093b18..019bd4c 100644
--- a/.github/workflows/test_objectivec.yml
+++ b/.github/workflows/test_objectivec.yml
@@ -36,13 +36,13 @@
ref: ${{ inputs.safe-checkout }}
- name: Setup ccache
- uses: ./.github/actions/ccache
+ uses: protocolbuffers/protobuf-ci/ccache@v1
with:
cache-prefix: objectivec_${{ matrix.platform }}_${{ matrix.xc_config }}
support-modules: true
- name: Run tests
- uses: ./.github/actions/bash
+ uses: protocolbuffers/protobuf-ci/bash@v1
env:
CC: ${{ github.workspace }}/ci/clang_wrapper
CXX: ${{ github.workspace }}/ci/clang_wrapper++
@@ -78,7 +78,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Pod lib lint
- uses: ./.github/actions/bash
+ uses: protocolbuffers/protobuf-ci/bash@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
command: |
@@ -107,7 +107,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel: test ${{ matrix.config.flags }} ${{ matrix.bazel_targets }}
diff --git a/.github/workflows/test_php.yml b/.github/workflows/test_php.yml
index fda266f..e3dbe4f 100644
--- a/.github/workflows/test_php.yml
+++ b/.github/workflows/test_php.yml
@@ -43,7 +43,7 @@
submodules: recursive
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php:${{ matrix.version }}-508417e5215994ade7585d28ba3aad681a25fa5d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -78,14 +78,14 @@
- name: Cross compile protoc for i386
id: cross-compile
- uses: ./.github/actions/cross-compile-protoc
+ uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:5.1.1-6361b3a6e5c97e9951d03a4de28542fc45f1adab
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-i386
- name: Run tests
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: ${{ env.image }}
skip-staleness-check: true
@@ -110,14 +110,14 @@
- name: Cross compile protoc for aarch64
id: cross-compile
- uses: ./.github/actions/cross-compile-protoc
+ uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:5.1.1-6361b3a6e5c97e9951d03a4de28542fc45f1adab
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-aarch64
- name: Run tests
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/php-aarch64:0cc100b6e03d14c1e8f71ae794dc162ed122fe31@sha256:77b70feba68dced1f0fd21b52a08d3d2e0c5c797bfe68435a0038ce87ecfd310
platform: linux/arm64
@@ -159,7 +159,7 @@
run: php --version | grep ${{ matrix.version }} || (echo "Invalid PHP version - $(php --version)" && exit 1)
- name: Run tests
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: php_macos/${{ matrix.version }}
@@ -173,7 +173,7 @@
popd
- name: Run conformance tests
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: php_macos/${{ matrix.version }}
diff --git a/.github/workflows/test_php_ext.yml b/.github/workflows/test_php_ext.yml
index 901512c..993e0da 100644
--- a/.github/workflows/test_php_ext.yml
+++ b/.github/workflows/test_php_ext.yml
@@ -12,45 +12,50 @@
contents: read # to fetch code (actions/checkout)
jobs:
- build-php:
- name: Build
+ package:
+ name: Package
runs-on: ubuntu-latest
- container: ${{ matrix.php-image }}
- strategy:
- matrix:
- php-image:
- - php:7.4-cli
- - php:8.1-cli
- # TODO(b/266868629) Dockerize these instead of installing all the
- # dependencies on each run.
steps:
- - name: Install python3
- run: |
- apt-get update -q
- apt-get install -qy python3
- - name: Install bazel
- run: |
- apt-get install -qy wget
- mkdir $HOME/bin
- wget -O $HOME/bin/bazel https://github.com/bazelbuild/bazel/releases/download/5.3.2/bazel-5.3.2-linux-x86_64
- chmod a+x $HOME/bin/bazel
- - name: Install git
- run: |
- apt-get install -qy --no-install-recommends git
- name: Checkout
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
with:
ref: ${{ inputs.safe-checkout }}
- submodules: recursive
- - name: Create package
- run: |
- cd $GITHUB_WORKSPACE
- rm -rf bazel-bin/php/protobuf-*.tgz
- $HOME/bin/bazel build php:release
+
+ - name: Package extension
+ uses: protocolbuffers/protobuf-ci/bazel@v1
+ with:
+ credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
+ bazel-cache: php_ext/${{ matrix.version }}
+ bash: >
+ bazel build //php:release $BAZEL_FLAGS;
+ cp bazel-bin/php/protobuf-*.tgz .
+
+ - uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce
+ with:
+ name: protobuf-php-release
+ path: protobuf-*.tgz
+
+ build:
+ needs: [package]
+ strategy:
+ fail-fast: false # Don't cancel all jobs if one fails.
+ matrix:
+ include:
+ - php-image: php:7.4-cli
+ version: "7.4.18-dbg"
+ - php-image: php:8.1-cli
+ version: "8.1.14"
+ name: Build ${{ matrix.version }}
+ runs-on: ubuntu-latest
+ container: ${{ matrix.php-image }}
+ steps:
+ - uses: actions/download-artifact@9bc31d5ccc31df68ecc42ccf4149144866c47d8a
+ with:
+ name: protobuf-php-release
- name: Compile extension
run: |
cd /tmp
- MAKE="make -j$(nproc)" pecl install $GITHUB_WORKSPACE/bazel-bin/php/protobuf-*.tgz
+ MAKE="make -j$(nproc)" pecl install $GITHUB_WORKSPACE/protobuf-*.tgz
- name: Enable extension
run: docker-php-ext-enable protobuf
- name: Inspect extension
diff --git a/.github/workflows/test_python.yml b/.github/workflows/test_python.yml
index 3547635..36f4e5a 100644
--- a/.github/workflows/test_python.yml
+++ b/.github/workflows/test_python.yml
@@ -37,7 +37,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel-docker
+ uses: protocolbuffers/protobuf-ci/bazel-docker@v1
with:
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/python:{0}-508417e5215994ade7585d28ba3aad681a25fa5d', matrix.version) }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -65,7 +65,6 @@
- name: Checkout pending changes
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
with:
- submodules: recursive
ref: ${{ inputs.safe-checkout }}
- name: Pin Python version
@@ -83,7 +82,7 @@
source venv/bin/activate
- name: Run tests
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
env:
KOKORO_PYTHON_VERSION: ${{ matrix.version }}
with:
diff --git a/.github/workflows/test_ruby.yml b/.github/workflows/test_ruby.yml
index 31b8f79..33906f5 100644
--- a/.github/workflows/test_ruby.yml
+++ b/.github/workflows/test_ruby.yml
@@ -32,7 +32,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel-docker
+ uses: protocolbuffers/protobuf-ci/bazel-docker@v1
with:
image: ${{ matrix.image || format('us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:{0}-{1}-508417e5215994ade7585d28ba3aad681a25fa5d', matrix.ruby, matrix.bazel) }}
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
@@ -50,14 +50,14 @@
- name: Cross compile protoc for aarch64
id: cross-compile
- uses: ./.github/actions/cross-compile-protoc
+ uses: protocolbuffers/protobuf-ci/cross-compile-protoc@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/common/linux/bazel:5.1.1-6361b3a6e5c97e9951d03a4de28542fc45f1adab
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
architecture: linux-aarch64
- name: Run tests
- uses: ./.github/actions/docker
+ uses: protocolbuffers/protobuf-ci/docker@v1
with:
image: arm64v8/ruby:2.7.3-buster
skip-staleness-check: true
@@ -84,7 +84,6 @@
- name: Checkout pending changes
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
with:
- submodules: recursive
ref: ${{ inputs.safe-checkout }}
- name: Pin Ruby version
@@ -96,7 +95,7 @@
run: ruby --version | grep ${{ matrix.version }} || (echo "Invalid Ruby version - $(ruby --version)" && exit 1)
- name: Run tests
- uses: ./.github/actions/bazel
+ uses: protocolbuffers/protobuf-ci/bazel@v1
with:
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
bazel-cache: ruby_macos/${{ matrix.version }}
@@ -124,7 +123,7 @@
with:
ref: ${{ inputs.safe-checkout }}
- name: Run tests
- uses: ./.github/actions/bazel-docker
+ uses: protocolbuffers/protobuf-ci/bazel-docker@v1
with:
image: us-docker.pkg.dev/protobuf-build/containers/test/linux/ruby:${{ matrix.ruby }}-${{ matrix.bazel }}-508417e5215994ade7585d28ba3aad681a25fa5d
credentials: ${{ secrets.GAR_SERVICE_ACCOUNT }}
diff --git a/.github/workflows/test_runner.yml b/.github/workflows/test_runner.yml
index a99d090..ce3268a 100644
--- a/.github/workflows/test_runner.yml
+++ b/.github/workflows/test_runner.yml
@@ -21,8 +21,8 @@
branches:
- main
- '[0-9]+.x'
- # The 21.x branch still uses Kokoro
- - '!21.x'
+ # The 21.x and 22.x branches still use Kokoro
+ - '!2[12].x'
# For testing purposes so we can stage this on the `gha` branch.
- gha
@@ -31,8 +31,8 @@
branches:
- main
- '[0-9]+.x'
- # The 21.x branch still uses Kokoro
- - '!21.x'
+ # The 21.x and 22.x branches still use Kokoro
+ - '!2[12].x'
# For testing purposes so we can stage this on the `gha` branch.
- gha
@@ -41,7 +41,7 @@
branches:
- main
- '[0-9]+.x'
- # The 21.x branch still uses Kokoro
+ # The 21.x branch still use Kokoro
- '!21.x'
# For testing purposes so we can stage this on the `gha` branch.
- gha
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 544ce94..c042073 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,29 +1,18 @@
# Minimum CMake required
-cmake_minimum_required(VERSION 3.5)
+cmake_minimum_required(VERSION 3.10)
if(protobuf_VERBOSE)
message(STATUS "Protocol Buffers Configuring...")
endif()
-# CMake policies
-cmake_policy(SET CMP0022 NEW)
-# On MacOS use @rpath/ for target's install name prefix path
-if (POLICY CMP0042)
- cmake_policy(SET CMP0042 NEW)
-endif ()
-# Clear VERSION variables when no VERSION is given to project()
-if(POLICY CMP0048)
- cmake_policy(SET CMP0048 NEW)
-endif()
# MSVC runtime library flags are selected by an abstraction.
+# New in CMake 3.15: https://cmake.org/cmake/help/latest/policy/CMP0091.html
if(POLICY CMP0091)
cmake_policy(SET CMP0091 NEW)
endif()
-# Honor visibility properties for all target types.
-if(POLICY CMP0063)
- cmake_policy(SET CMP0063 NEW)
-endif()
-# option() honor variables
+
+# option() honors normal variables
+# New in CMake 3.13: https://cmake.org/cmake/help/latest/policy/CMP0077.html
if (POLICY CMP0077)
cmake_policy(SET CMP0077 NEW)
endif (POLICY CMP0077)
diff --git a/README.md b/README.md
index 3bfeb0f..c84ab2b 100644
--- a/README.md
+++ b/README.md
@@ -3,14 +3,12 @@
Copyright 2008 Google Inc.
-[Protocol Buffers documentation](https://developers.google.com/protocol-buffers/)
-
Overview
--------
Protocol Buffers (a.k.a., protobuf) are Google's language-neutral,
platform-neutral, extensible mechanism for serializing structured data. You
-can find [protobuf's documentation on the Google Developers site](https://developers.google.com/protocol-buffers/).
+can learn more about it in [protobuf's documentation](https://protobuf.dev).
This README file contains protobuf installation instructions. To install
protobuf, you need to install the protocol compiler (used to compile .proto
@@ -64,7 +62,7 @@
-----------
The best way to learn how to use protobuf is to follow the [tutorials in our
-developer guide](https://developers.google.com/protocol-buffers/docs/tutorials).
+developer guide](https://protobuf.dev/getting-started).
If you want to learn from code examples, take a look at the examples in the
[examples](examples) directory.
@@ -72,11 +70,16 @@
Documentation
-------------
-The complete documentation is available via the [Protocol Buffers documentation](https://developers.google.com/protocol-buffers/).
+The complete documentation is available at the [Protocol Buffers doc site](https://protobuf.dev).
+
+Support Policy
+--------------
+
+Read about our [version support policy](https://protobuf.dev/version-support/)
+to stay current on support timeframes for the language libraries.
Developer Community
-------------------
To be alerted to upcoming changes in Protocol Buffers and connect with protobuf developers and users,
[join the Google Group](https://groups.google.com/g/protobuf).
-
diff --git a/WORKSPACE b/WORKSPACE
index 2301093..af7d63a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -136,4 +136,4 @@
load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_register_toolchains")
rules_rust_dependencies()
-rust_register_toolchains()
+rust_register_toolchains(edition = "2021")
diff --git a/build_defs/upb.patch b/build_defs/upb.patch
index 809fb70..ec1f28b 100644
--- a/build_defs/upb.patch
+++ b/build_defs/upb.patch
@@ -9,4 +9,22 @@
# end:github_only
def _upbc(stage):
-
\ No newline at end of file
+
+--- cmake/build_defs.bzl
++++ cmake/build_defs.bzl
+@@ -25,7 +25,7 @@
+
+ """Bazel support functions related to CMake support."""
+
+-def staleness_test(name, outs, generated_pattern, target_files = None, **kwargs):
++def staleness_test(name, outs, generated_pattern, target_files = None, tags = [], **kwargs):
+ """Tests that checked-in file(s) match the contents of generated file(s).
+
+ The resulting test will verify that all output files exist and have the
+@@ -72,5 +72,6 @@ def staleness_test(name, outs, generated_pattern, target_files = None, **kwargs)
+ deps = [
+ Label("//cmake:staleness_test_lib"),
+ ],
++ tags = ["staleness_test"] + tags,
+ **kwargs
+ )
diff --git a/push_auto_update.sh b/ci/push_auto_update.sh
similarity index 94%
rename from push_auto_update.sh
rename to ci/push_auto_update.sh
index 9972da6..641525c 100755
--- a/push_auto_update.sh
+++ b/ci/push_auto_update.sh
@@ -8,7 +8,7 @@
set -ex
# Cd to the repo root.
-cd $(dirname -- "$0")
+cd $(dirname -- "$0")/..
previous_commit_title=$(git log -1 --pretty='%s')
@@ -42,4 +42,4 @@
git pull --rebase
git add -A
git diff --staged --quiet || git commit -am "$commit_message"
-git push
+git push || echo "Conflicting commit hit, retrying in next job..."
diff --git a/cmake/tests.cmake b/cmake/tests.cmake
index 27f2eac..2608060 100644
--- a/cmake/tests.cmake
+++ b/cmake/tests.cmake
@@ -131,7 +131,8 @@
)
add_test(NAME lite-test
- COMMAND lite-test ${protobuf_GTEST_ARGS})
+ COMMAND lite-test ${protobuf_GTEST_ARGS}
+ WORKING_DIRECTORY ${protobuf_SOURCE_DIR})
add_custom_target(full-test
COMMAND tests
@@ -139,7 +140,8 @@
WORKING_DIRECTORY ${protobuf_SOURCE_DIR})
add_test(NAME full-test
- COMMAND tests ${protobuf_GTEST_ARGS})
+ COMMAND tests ${protobuf_GTEST_ARGS}
+ WORKING_DIRECTORY ${protobuf_SOURCE_DIR})
# For test purposes, remove headers that should already be installed. This
# prevents accidental conflicts and also version skew (since local headers take
diff --git a/conformance/binary_json_conformance_suite.cc b/conformance/binary_json_conformance_suite.cc
index 90991f1..21b6592 100644
--- a/conformance/binary_json_conformance_suite.cc
+++ b/conformance/binary_json_conformance_suite.cc
@@ -1431,12 +1431,12 @@
TestIllegalTags();
- int64 kInt64Min = -9223372036854775808ULL;
- int64 kInt64Max = 9223372036854775807ULL;
- uint64 kUint64Max = 18446744073709551615ULL;
- int32 kInt32Max = 2147483647;
- int32 kInt32Min = -2147483648;
- uint32 kUint32Max = 4294967295UL;
+ int64_t kInt64Min = -9223372036854775808ULL;
+ int64_t kInt64Max = 9223372036854775807ULL;
+ uint64_t kUint64Max = 18446744073709551615ULL;
+ int32_t kInt32Max = 2147483647;
+ int32_t kInt32Min = -2147483648;
+ uint32_t kUint32Max = 4294967295UL;
TestValidDataForType(
FieldDescriptor::TYPE_DOUBLE,
@@ -2318,11 +2318,11 @@
{
TestAllTypesProto3 message;
message.set_optional_double(
- WireFormatLite::DecodeDouble(int64{0x7FFA123456789ABC}));
+ WireFormatLite::DecodeDouble(int64_t{0x7FFA123456789ABC}));
RunValidJsonTestWithProtobufInput("DoubleFieldNormalizeQuietNan", REQUIRED,
message, "optional_double: nan");
message.set_optional_double(
- WireFormatLite::DecodeDouble(uint64{0xFFFBCBA987654321}));
+ WireFormatLite::DecodeDouble(uint64_t{0xFFFBCBA987654321}));
RunValidJsonTestWithProtobufInput("DoubleFieldNormalizeSignalingNan",
REQUIRED, message,
"optional_double: nan");
diff --git a/conformance/conformance_test.cc b/conformance/conformance_test.cc
index e5d2907..aba07a0 100644
--- a/conformance/conformance_test.cc
+++ b/conformance/conformance_test.cc
@@ -162,12 +162,19 @@
}
string ConformanceTestSuite::ConformanceRequestSetting::GetTestName() const {
- string rname = prototype_message_.GetDescriptor()->file()->syntax() ==
- FileDescriptor::SYNTAX_PROTO3
- ? "Proto3"
- : "Proto2";
+ string rname;
+ switch (prototype_message_.GetDescriptor()->file()->syntax()) {
+ case FileDescriptor::SYNTAX_PROTO3:
+ rname = ".Proto3.";
+ break;
+ case FileDescriptor::SYNTAX_PROTO2:
+ rname = ".Proto2.";
+ break;
+ default:
+ break;
+ }
- return absl::StrCat(ConformanceLevelToString(level_), ".", rname, ".",
+ return absl::StrCat(ConformanceLevelToString(level_), rname,
InputFormatString(input_format_), ".", test_name_, ".",
OutputFormatString(output_format_));
}
diff --git a/csharp/BUILD.bazel b/csharp/BUILD.bazel
index 23fbe41..2af7d06 100644
--- a/csharp/BUILD.bazel
+++ b/csharp/BUILD.bazel
@@ -65,9 +65,11 @@
srcs = [
":srcs",
"src/Google.Protobuf.sln",
+ "//conformance:conformance_csharp_proto",
"//csharp/src/Google.Protobuf.Conformance:srcs",
],
cmd = """
+ cp $(rootpath //conformance:conformance_csharp_proto) `dirname $(location src/Google.Protobuf.sln)`/Google.Protobuf.Conformance/
pushd `dirname $(location src/Google.Protobuf.sln)`/..
dotnet restore src/Google.Protobuf.sln
dotnet build -c Release src/Google.Protobuf.sln
diff --git a/csharp/generate_protos.sh b/csharp/generate_protos.sh
index cd682c2..17b1640 100755
--- a/csharp/generate_protos.sh
+++ b/csharp/generate_protos.sh
@@ -79,3 +79,8 @@
$PROTOC -Iexamples -Isrc --csharp_out=csharp/src/AddressBook \
--csharp_opt=file_extension=.pb.cs \
examples/addressbook.proto
+
+# Conformance tests
+$PROTOC -I. --csharp_out=csharp/src/Google.Protobuf.Conformance \
+ --csharp_opt=file_extension=.pb.cs \
+ conformance/conformance.proto
diff --git a/csharp/src/Google.Protobuf.Conformance/BUILD.bazel b/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
index 12ad0f7..0b5e2c8 100644
--- a/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
+++ b/csharp/src/Google.Protobuf.Conformance/BUILD.bazel
@@ -1,3 +1,4 @@
+load("//:protobuf.bzl", "internal_csharp_proto_library")
load("//build_defs:internal_shell.bzl", "inline_sh_binary")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
@@ -37,7 +38,6 @@
filegroup(
name = "srcs",
srcs = [
- "Conformance.cs",
"Program.cs",
"Google.Protobuf.Conformance.csproj",
],
@@ -88,7 +88,6 @@
srcs = [
"BUILD.bazel",
"Google.Protobuf.Conformance.csproj",
- "Conformance.cs",
"Program.cs",
],
strip_prefix = strip_prefix.from_root(""),
diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
similarity index 78%
rename from csharp/src/Google.Protobuf.Conformance/Conformance.cs
rename to csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
index 77fd9c9..3b4ff53 100644
--- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs
+++ b/csharp/src/Google.Protobuf.Conformance/Conformance.pb.cs
@@ -1,6 +1,6 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
-// source: conformance.proto
+// source: conformance/conformance.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021, 8981
#region Designer generated code
@@ -11,11 +11,11 @@
using scg = global::System.Collections.Generic;
namespace Conformance {
- /// <summary>Holder for reflection information generated from conformance.proto</summary>
+ /// <summary>Holder for reflection information generated from conformance/conformance.proto</summary>
public static partial class ConformanceReflection {
#region Descriptor
- /// <summary>File descriptor for conformance.proto</summary>
+ /// <summary>File descriptor for conformance/conformance.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
@@ -24,34 +24,35 @@
static ConformanceReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
- "ChFjb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2UiHQoKRmFpbHVyZVNl",
- "dBIPCgdmYWlsdXJlGAEgAygJIuMCChJDb25mb3JtYW5jZVJlcXVlc3QSGgoQ",
- "cHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25fcGF5bG9hZBgCIAEo",
- "CUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9hZBgI",
- "IAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0GAMgASgOMhcuY29u",
- "Zm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5cGUYBCABKAkSMAoN",
- "dGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNlLlRlc3RDYXRlZ29y",
- "eRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsyHy5jb25mb3JtYW5j",
- "ZS5Kc3BiRW5jb2RpbmdDb25maWcSHAoUcHJpbnRfdW5rbm93bl9maWVsZHMY",
- "CSABKAhCCQoHcGF5bG9hZCLhAQoTQ29uZm9ybWFuY2VSZXNwb25zZRIVCgtw",
- "YXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6ZV9lcnJvchgGIAEoCUgA",
- "EhcKDXJ1bnRpbWVfZXJyb3IYAiABKAlIABIaChBwcm90b2J1Zl9wYXlsb2Fk",
- "GAMgASgMSAASFgoManNvbl9wYXlsb2FkGAQgASgJSAASEQoHc2tpcHBlZBgF",
- "IAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRleHRfcGF5bG9h",
- "ZBgIIAEoCUgAQggKBnJlc3VsdCI3ChJKc3BiRW5jb2RpbmdDb25maWcSIQoZ",
- "dXNlX2pzcGJfYXJyYXlfYW55X2Zvcm1hdBgBIAEoCCpQCgpXaXJlRm9ybWF0",
- "Eg8KC1VOU1BFQ0lGSUVEEAASDAoIUFJPVE9CVUYQARIICgRKU09OEAISCAoE",
- "SlNQQhADEg8KC1RFWFRfRk9STUFUEAQqjwEKDFRlc3RDYXRlZ29yeRIUChBV",
- "TlNQRUNJRklFRF9URVNUEAASDwoLQklOQVJZX1RFU1QQARINCglKU09OX1RF",
- "U1QQAhIkCiBKU09OX0lHTk9SRV9VTktOT1dOX1BBUlNJTkdfVEVTVBADEg0K",
- "CUpTUEJfVEVTVBAEEhQKEFRFWFRfRk9STUFUX1RFU1QQBUIhCh9jb20uZ29v",
- "Z2xlLnByb3RvYnVmLmNvbmZvcm1hbmNlYgZwcm90bzM="));
+ "Ch1jb25mb3JtYW5jZS9jb25mb3JtYW5jZS5wcm90bxILY29uZm9ybWFuY2Ui",
+ "HQoKRmFpbHVyZVNldBIPCgdmYWlsdXJlGAEgAygJIuMCChJDb25mb3JtYW5j",
+ "ZVJlcXVlc3QSGgoQcHJvdG9idWZfcGF5bG9hZBgBIAEoDEgAEhYKDGpzb25f",
+ "cGF5bG9hZBgCIAEoCUgAEhYKDGpzcGJfcGF5bG9hZBgHIAEoCUgAEhYKDHRl",
+ "eHRfcGF5bG9hZBgIIAEoCUgAEjgKF3JlcXVlc3RlZF9vdXRwdXRfZm9ybWF0",
+ "GAMgASgOMhcuY29uZm9ybWFuY2UuV2lyZUZvcm1hdBIUCgxtZXNzYWdlX3R5",
+ "cGUYBCABKAkSMAoNdGVzdF9jYXRlZ29yeRgFIAEoDjIZLmNvbmZvcm1hbmNl",
+ "LlRlc3RDYXRlZ29yeRI+ChVqc3BiX2VuY29kaW5nX29wdGlvbnMYBiABKAsy",
+ "Hy5jb25mb3JtYW5jZS5Kc3BiRW5jb2RpbmdDb25maWcSHAoUcHJpbnRfdW5r",
+ "bm93bl9maWVsZHMYCSABKAhCCQoHcGF5bG9hZCL6AQoTQ29uZm9ybWFuY2VS",
+ "ZXNwb25zZRIVCgtwYXJzZV9lcnJvchgBIAEoCUgAEhkKD3NlcmlhbGl6ZV9l",
+ "cnJvchgGIAEoCUgAEhcKDXRpbWVvdXRfZXJyb3IYCSABKAlIABIXCg1ydW50",
+ "aW1lX2Vycm9yGAIgASgJSAASGgoQcHJvdG9idWZfcGF5bG9hZBgDIAEoDEgA",
+ "EhYKDGpzb25fcGF5bG9hZBgEIAEoCUgAEhEKB3NraXBwZWQYBSABKAlIABIW",
+ "Cgxqc3BiX3BheWxvYWQYByABKAlIABIWCgx0ZXh0X3BheWxvYWQYCCABKAlI",
+ "AEIICgZyZXN1bHQiNwoSSnNwYkVuY29kaW5nQ29uZmlnEiEKGXVzZV9qc3Bi",
+ "X2FycmF5X2FueV9mb3JtYXQYASABKAgqUAoKV2lyZUZvcm1hdBIPCgtVTlNQ",
+ "RUNJRklFRBAAEgwKCFBST1RPQlVGEAESCAoESlNPThACEggKBEpTUEIQAxIP",
+ "CgtURVhUX0ZPUk1BVBAEKo8BCgxUZXN0Q2F0ZWdvcnkSFAoQVU5TUEVDSUZJ",
+ "RURfVEVTVBAAEg8KC0JJTkFSWV9URVNUEAESDQoJSlNPTl9URVNUEAISJAog",
+ "SlNPTl9JR05PUkVfVU5LTk9XTl9QQVJTSU5HX1RFU1QQAxINCglKU1BCX1RF",
+ "U1QQBBIUChBURVhUX0ZPUk1BVF9URVNUEAVCLwofY29tLmdvb2dsZS5wcm90",
+ "b2J1Zi5jb25mb3JtYW5jZaICC0NvbmZvcm1hbmNlYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Conformance.WireFormat), typeof(global::Conformance.TestCategory), }, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.FailureSet), global::Conformance.FailureSet.Parser, new[]{ "Failure" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceRequest), global::Conformance.ConformanceRequest.Parser, new[]{ "ProtobufPayload", "JsonPayload", "JspbPayload", "TextPayload", "RequestedOutputFormat", "MessageType", "TestCategory", "JspbEncodingOptions", "PrintUnknownFields" }, new[]{ "Payload" }, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.ConformanceResponse), global::Conformance.ConformanceResponse.Parser, new[]{ "ParseError", "SerializeError", "TimeoutError", "RuntimeError", "ProtobufPayload", "JsonPayload", "Skipped", "JspbPayload", "TextPayload" }, new[]{ "Result" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Conformance.JspbEncodingConfig), global::Conformance.JspbEncodingConfig.Parser, new[]{ "UseJspbArrayAnyFormat" }, null, null, null, null)
}));
}
@@ -89,7 +90,8 @@
/// </summary>
[pbr::OriginalName("JSON_IGNORE_UNKNOWN_PARSING_TEST")] JsonIgnoreUnknownParsingTest = 3,
/// <summary>
- /// Test jspb wire format. Only used inside Google. Opensource testees just skip it.
+ /// Test jspb wire format. Only used inside Google. Opensource testees just
+ /// skip it.
/// </summary>
[pbr::OriginalName("JSPB_TEST")] JspbTest = 4,
/// <summary>
@@ -360,51 +362,107 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pb::ByteString ProtobufPayload {
- get { return payloadCase_ == PayloadOneofCase.ProtobufPayload ? (pb::ByteString) payload_ : pb::ByteString.Empty; }
+ get { return HasProtobufPayload ? (pb::ByteString) payload_ : pb::ByteString.Empty; }
set {
payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
payloadCase_ = PayloadOneofCase.ProtobufPayload;
}
}
+ /// <summary>Gets whether the "protobuf_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasProtobufPayload {
+ get { return payloadCase_ == PayloadOneofCase.ProtobufPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "protobuf_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearProtobufPayload() {
+ if (HasProtobufPayload) {
+ ClearPayload();
+ }
+ }
/// <summary>Field number for the "json_payload" field.</summary>
public const int JsonPayloadFieldNumber = 2;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string JsonPayload {
- get { return payloadCase_ == PayloadOneofCase.JsonPayload ? (string) payload_ : ""; }
+ get { return HasJsonPayload ? (string) payload_ : ""; }
set {
payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
payloadCase_ = PayloadOneofCase.JsonPayload;
}
}
+ /// <summary>Gets whether the "json_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasJsonPayload {
+ get { return payloadCase_ == PayloadOneofCase.JsonPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "json_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearJsonPayload() {
+ if (HasJsonPayload) {
+ ClearPayload();
+ }
+ }
/// <summary>Field number for the "jspb_payload" field.</summary>
public const int JspbPayloadFieldNumber = 7;
/// <summary>
- /// Only used inside google. Opensource testees just skip it.
+ /// Only used inside Google. Opensource testees just skip it.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string JspbPayload {
- get { return payloadCase_ == PayloadOneofCase.JspbPayload ? (string) payload_ : ""; }
+ get { return HasJspbPayload ? (string) payload_ : ""; }
set {
payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
payloadCase_ = PayloadOneofCase.JspbPayload;
}
}
+ /// <summary>Gets whether the "jspb_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasJspbPayload {
+ get { return payloadCase_ == PayloadOneofCase.JspbPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "jspb_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearJspbPayload() {
+ if (HasJspbPayload) {
+ ClearPayload();
+ }
+ }
/// <summary>Field number for the "text_payload" field.</summary>
public const int TextPayloadFieldNumber = 8;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string TextPayload {
- get { return payloadCase_ == PayloadOneofCase.TextPayload ? (string) payload_ : ""; }
+ get { return HasTextPayload ? (string) payload_ : ""; }
set {
payload_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
payloadCase_ = PayloadOneofCase.TextPayload;
}
}
+ /// <summary>Gets whether the "text_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasTextPayload {
+ get { return payloadCase_ == PayloadOneofCase.TextPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "text_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearTextPayload() {
+ if (HasTextPayload) {
+ ClearPayload();
+ }
+ }
/// <summary>Field number for the "requested_output_format" field.</summary>
public const int RequestedOutputFormatFieldNumber = 3;
@@ -443,8 +501,8 @@
private global::Conformance.TestCategory testCategory_ = global::Conformance.TestCategory.UnspecifiedTest;
/// <summary>
/// Each test is given a specific test category. Some category may need
- /// specific support in testee programs. Refer to the definition of TestCategory
- /// for more information.
+ /// specific support in testee programs. Refer to the definition of
+ /// TestCategory for more information.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
@@ -541,10 +599,10 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (payloadCase_ == PayloadOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
- if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
- if (payloadCase_ == PayloadOneofCase.JspbPayload) hash ^= JspbPayload.GetHashCode();
- if (payloadCase_ == PayloadOneofCase.TextPayload) hash ^= TextPayload.GetHashCode();
+ if (HasProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
+ if (HasJsonPayload) hash ^= JsonPayload.GetHashCode();
+ if (HasJspbPayload) hash ^= JspbPayload.GetHashCode();
+ if (HasTextPayload) hash ^= TextPayload.GetHashCode();
if (RequestedOutputFormat != global::Conformance.WireFormat.Unspecified) hash ^= RequestedOutputFormat.GetHashCode();
if (MessageType.Length != 0) hash ^= MessageType.GetHashCode();
if (TestCategory != global::Conformance.TestCategory.UnspecifiedTest) hash ^= TestCategory.GetHashCode();
@@ -569,11 +627,11 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (payloadCase_ == PayloadOneofCase.ProtobufPayload) {
+ if (HasProtobufPayload) {
output.WriteRawTag(10);
output.WriteBytes(ProtobufPayload);
}
- if (payloadCase_ == PayloadOneofCase.JsonPayload) {
+ if (HasJsonPayload) {
output.WriteRawTag(18);
output.WriteString(JsonPayload);
}
@@ -593,11 +651,11 @@
output.WriteRawTag(50);
output.WriteMessage(JspbEncodingOptions);
}
- if (payloadCase_ == PayloadOneofCase.JspbPayload) {
+ if (HasJspbPayload) {
output.WriteRawTag(58);
output.WriteString(JspbPayload);
}
- if (payloadCase_ == PayloadOneofCase.TextPayload) {
+ if (HasTextPayload) {
output.WriteRawTag(66);
output.WriteString(TextPayload);
}
@@ -615,11 +673,11 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (payloadCase_ == PayloadOneofCase.ProtobufPayload) {
+ if (HasProtobufPayload) {
output.WriteRawTag(10);
output.WriteBytes(ProtobufPayload);
}
- if (payloadCase_ == PayloadOneofCase.JsonPayload) {
+ if (HasJsonPayload) {
output.WriteRawTag(18);
output.WriteString(JsonPayload);
}
@@ -639,11 +697,11 @@
output.WriteRawTag(50);
output.WriteMessage(JspbEncodingOptions);
}
- if (payloadCase_ == PayloadOneofCase.JspbPayload) {
+ if (HasJspbPayload) {
output.WriteRawTag(58);
output.WriteString(JspbPayload);
}
- if (payloadCase_ == PayloadOneofCase.TextPayload) {
+ if (HasTextPayload) {
output.WriteRawTag(66);
output.WriteString(TextPayload);
}
@@ -661,16 +719,16 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (payloadCase_ == PayloadOneofCase.ProtobufPayload) {
+ if (HasProtobufPayload) {
size += 1 + pb::CodedOutputStream.ComputeBytesSize(ProtobufPayload);
}
- if (payloadCase_ == PayloadOneofCase.JsonPayload) {
+ if (HasJsonPayload) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonPayload);
}
- if (payloadCase_ == PayloadOneofCase.JspbPayload) {
+ if (HasJspbPayload) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(JspbPayload);
}
- if (payloadCase_ == PayloadOneofCase.TextPayload) {
+ if (HasTextPayload) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(TextPayload);
}
if (RequestedOutputFormat != global::Conformance.WireFormat.Unspecified) {
@@ -892,6 +950,9 @@
case ResultOneofCase.SerializeError:
SerializeError = other.SerializeError;
break;
+ case ResultOneofCase.TimeoutError:
+ TimeoutError = other.TimeoutError;
+ break;
case ResultOneofCase.RuntimeError:
RuntimeError = other.RuntimeError;
break;
@@ -933,12 +994,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string ParseError {
- get { return resultCase_ == ResultOneofCase.ParseError ? (string) result_ : ""; }
+ get { return HasParseError ? (string) result_ : ""; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.ParseError;
}
}
+ /// <summary>Gets whether the "parse_error" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasParseError {
+ get { return resultCase_ == ResultOneofCase.ParseError; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "parse_error" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearParseError() {
+ if (HasParseError) {
+ ClearResult();
+ }
+ }
/// <summary>Field number for the "serialize_error" field.</summary>
public const int SerializeErrorFieldNumber = 6;
@@ -950,12 +1025,57 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string SerializeError {
- get { return resultCase_ == ResultOneofCase.SerializeError ? (string) result_ : ""; }
+ get { return HasSerializeError ? (string) result_ : ""; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.SerializeError;
}
}
+ /// <summary>Gets whether the "serialize_error" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasSerializeError {
+ get { return resultCase_ == ResultOneofCase.SerializeError; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "serialize_error" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearSerializeError() {
+ if (HasSerializeError) {
+ ClearResult();
+ }
+ }
+
+ /// <summary>Field number for the "timeout_error" field.</summary>
+ public const int TimeoutErrorFieldNumber = 9;
+ /// <summary>
+ /// This should be set if the test program timed out. The string should
+ /// provide more information about what the child process was doing when it
+ /// was killed.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string TimeoutError {
+ get { return HasTimeoutError ? (string) result_ : ""; }
+ set {
+ result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ resultCase_ = ResultOneofCase.TimeoutError;
+ }
+ }
+ /// <summary>Gets whether the "timeout_error" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasTimeoutError {
+ get { return resultCase_ == ResultOneofCase.TimeoutError; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "timeout_error" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearTimeoutError() {
+ if (HasTimeoutError) {
+ ClearResult();
+ }
+ }
/// <summary>Field number for the "runtime_error" field.</summary>
public const int RuntimeErrorFieldNumber = 2;
@@ -967,12 +1087,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string RuntimeError {
- get { return resultCase_ == ResultOneofCase.RuntimeError ? (string) result_ : ""; }
+ get { return HasRuntimeError ? (string) result_ : ""; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.RuntimeError;
}
}
+ /// <summary>Gets whether the "runtime_error" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRuntimeError {
+ get { return resultCase_ == ResultOneofCase.RuntimeError; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "runtime_error" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRuntimeError() {
+ if (HasRuntimeError) {
+ ClearResult();
+ }
+ }
/// <summary>Field number for the "protobuf_payload" field.</summary>
public const int ProtobufPayloadFieldNumber = 3;
@@ -983,12 +1117,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pb::ByteString ProtobufPayload {
- get { return resultCase_ == ResultOneofCase.ProtobufPayload ? (pb::ByteString) result_ : pb::ByteString.Empty; }
+ get { return HasProtobufPayload ? (pb::ByteString) result_ : pb::ByteString.Empty; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.ProtobufPayload;
}
}
+ /// <summary>Gets whether the "protobuf_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasProtobufPayload {
+ get { return resultCase_ == ResultOneofCase.ProtobufPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "protobuf_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearProtobufPayload() {
+ if (HasProtobufPayload) {
+ ClearResult();
+ }
+ }
/// <summary>Field number for the "json_payload" field.</summary>
public const int JsonPayloadFieldNumber = 4;
@@ -999,12 +1147,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string JsonPayload {
- get { return resultCase_ == ResultOneofCase.JsonPayload ? (string) result_ : ""; }
+ get { return HasJsonPayload ? (string) result_ : ""; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.JsonPayload;
}
}
+ /// <summary>Gets whether the "json_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasJsonPayload {
+ get { return resultCase_ == ResultOneofCase.JsonPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "json_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearJsonPayload() {
+ if (HasJsonPayload) {
+ ClearResult();
+ }
+ }
/// <summary>Field number for the "skipped" field.</summary>
public const int SkippedFieldNumber = 5;
@@ -1015,12 +1177,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string Skipped {
- get { return resultCase_ == ResultOneofCase.Skipped ? (string) result_ : ""; }
+ get { return HasSkipped ? (string) result_ : ""; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.Skipped;
}
}
+ /// <summary>Gets whether the "skipped" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasSkipped {
+ get { return resultCase_ == ResultOneofCase.Skipped; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "skipped" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearSkipped() {
+ if (HasSkipped) {
+ ClearResult();
+ }
+ }
/// <summary>Field number for the "jspb_payload" field.</summary>
public const int JspbPayloadFieldNumber = 7;
@@ -1032,12 +1208,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string JspbPayload {
- get { return resultCase_ == ResultOneofCase.JspbPayload ? (string) result_ : ""; }
+ get { return HasJspbPayload ? (string) result_ : ""; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.JspbPayload;
}
}
+ /// <summary>Gets whether the "jspb_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasJspbPayload {
+ get { return resultCase_ == ResultOneofCase.JspbPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "jspb_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearJspbPayload() {
+ if (HasJspbPayload) {
+ ClearResult();
+ }
+ }
/// <summary>Field number for the "text_payload" field.</summary>
public const int TextPayloadFieldNumber = 8;
@@ -1048,12 +1238,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string TextPayload {
- get { return resultCase_ == ResultOneofCase.TextPayload ? (string) result_ : ""; }
+ get { return HasTextPayload ? (string) result_ : ""; }
set {
result_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
resultCase_ = ResultOneofCase.TextPayload;
}
}
+ /// <summary>Gets whether the "text_payload" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasTextPayload {
+ get { return resultCase_ == ResultOneofCase.TextPayload; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "text_payload" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearTextPayload() {
+ if (HasTextPayload) {
+ ClearResult();
+ }
+ }
private object result_;
/// <summary>Enum of possible cases for the "result" oneof.</summary>
@@ -1061,6 +1265,7 @@
None = 0,
ParseError = 1,
SerializeError = 6,
+ TimeoutError = 9,
RuntimeError = 2,
ProtobufPayload = 3,
JsonPayload = 4,
@@ -1099,6 +1304,7 @@
}
if (ParseError != other.ParseError) return false;
if (SerializeError != other.SerializeError) return false;
+ if (TimeoutError != other.TimeoutError) return false;
if (RuntimeError != other.RuntimeError) return false;
if (ProtobufPayload != other.ProtobufPayload) return false;
if (JsonPayload != other.JsonPayload) return false;
@@ -1113,14 +1319,15 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (resultCase_ == ResultOneofCase.ParseError) hash ^= ParseError.GetHashCode();
- if (resultCase_ == ResultOneofCase.SerializeError) hash ^= SerializeError.GetHashCode();
- if (resultCase_ == ResultOneofCase.RuntimeError) hash ^= RuntimeError.GetHashCode();
- if (resultCase_ == ResultOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
- if (resultCase_ == ResultOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode();
- if (resultCase_ == ResultOneofCase.Skipped) hash ^= Skipped.GetHashCode();
- if (resultCase_ == ResultOneofCase.JspbPayload) hash ^= JspbPayload.GetHashCode();
- if (resultCase_ == ResultOneofCase.TextPayload) hash ^= TextPayload.GetHashCode();
+ if (HasParseError) hash ^= ParseError.GetHashCode();
+ if (HasSerializeError) hash ^= SerializeError.GetHashCode();
+ if (HasTimeoutError) hash ^= TimeoutError.GetHashCode();
+ if (HasRuntimeError) hash ^= RuntimeError.GetHashCode();
+ if (HasProtobufPayload) hash ^= ProtobufPayload.GetHashCode();
+ if (HasJsonPayload) hash ^= JsonPayload.GetHashCode();
+ if (HasSkipped) hash ^= Skipped.GetHashCode();
+ if (HasJspbPayload) hash ^= JspbPayload.GetHashCode();
+ if (HasTextPayload) hash ^= TextPayload.GetHashCode();
hash ^= (int) resultCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
@@ -1140,38 +1347,42 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (resultCase_ == ResultOneofCase.ParseError) {
+ if (HasParseError) {
output.WriteRawTag(10);
output.WriteString(ParseError);
}
- if (resultCase_ == ResultOneofCase.RuntimeError) {
+ if (HasRuntimeError) {
output.WriteRawTag(18);
output.WriteString(RuntimeError);
}
- if (resultCase_ == ResultOneofCase.ProtobufPayload) {
+ if (HasProtobufPayload) {
output.WriteRawTag(26);
output.WriteBytes(ProtobufPayload);
}
- if (resultCase_ == ResultOneofCase.JsonPayload) {
+ if (HasJsonPayload) {
output.WriteRawTag(34);
output.WriteString(JsonPayload);
}
- if (resultCase_ == ResultOneofCase.Skipped) {
+ if (HasSkipped) {
output.WriteRawTag(42);
output.WriteString(Skipped);
}
- if (resultCase_ == ResultOneofCase.SerializeError) {
+ if (HasSerializeError) {
output.WriteRawTag(50);
output.WriteString(SerializeError);
}
- if (resultCase_ == ResultOneofCase.JspbPayload) {
+ if (HasJspbPayload) {
output.WriteRawTag(58);
output.WriteString(JspbPayload);
}
- if (resultCase_ == ResultOneofCase.TextPayload) {
+ if (HasTextPayload) {
output.WriteRawTag(66);
output.WriteString(TextPayload);
}
+ if (HasTimeoutError) {
+ output.WriteRawTag(74);
+ output.WriteString(TimeoutError);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -1182,38 +1393,42 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (resultCase_ == ResultOneofCase.ParseError) {
+ if (HasParseError) {
output.WriteRawTag(10);
output.WriteString(ParseError);
}
- if (resultCase_ == ResultOneofCase.RuntimeError) {
+ if (HasRuntimeError) {
output.WriteRawTag(18);
output.WriteString(RuntimeError);
}
- if (resultCase_ == ResultOneofCase.ProtobufPayload) {
+ if (HasProtobufPayload) {
output.WriteRawTag(26);
output.WriteBytes(ProtobufPayload);
}
- if (resultCase_ == ResultOneofCase.JsonPayload) {
+ if (HasJsonPayload) {
output.WriteRawTag(34);
output.WriteString(JsonPayload);
}
- if (resultCase_ == ResultOneofCase.Skipped) {
+ if (HasSkipped) {
output.WriteRawTag(42);
output.WriteString(Skipped);
}
- if (resultCase_ == ResultOneofCase.SerializeError) {
+ if (HasSerializeError) {
output.WriteRawTag(50);
output.WriteString(SerializeError);
}
- if (resultCase_ == ResultOneofCase.JspbPayload) {
+ if (HasJspbPayload) {
output.WriteRawTag(58);
output.WriteString(JspbPayload);
}
- if (resultCase_ == ResultOneofCase.TextPayload) {
+ if (HasTextPayload) {
output.WriteRawTag(66);
output.WriteString(TextPayload);
}
+ if (HasTimeoutError) {
+ output.WriteRawTag(74);
+ output.WriteString(TimeoutError);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -1224,28 +1439,31 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (resultCase_ == ResultOneofCase.ParseError) {
+ if (HasParseError) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(ParseError);
}
- if (resultCase_ == ResultOneofCase.SerializeError) {
+ if (HasSerializeError) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(SerializeError);
}
- if (resultCase_ == ResultOneofCase.RuntimeError) {
+ if (HasTimeoutError) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(TimeoutError);
+ }
+ if (HasRuntimeError) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(RuntimeError);
}
- if (resultCase_ == ResultOneofCase.ProtobufPayload) {
+ if (HasProtobufPayload) {
size += 1 + pb::CodedOutputStream.ComputeBytesSize(ProtobufPayload);
}
- if (resultCase_ == ResultOneofCase.JsonPayload) {
+ if (HasJsonPayload) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonPayload);
}
- if (resultCase_ == ResultOneofCase.Skipped) {
+ if (HasSkipped) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Skipped);
}
- if (resultCase_ == ResultOneofCase.JspbPayload) {
+ if (HasJspbPayload) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(JspbPayload);
}
- if (resultCase_ == ResultOneofCase.TextPayload) {
+ if (HasTextPayload) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(TextPayload);
}
if (_unknownFields != null) {
@@ -1267,6 +1485,9 @@
case ResultOneofCase.SerializeError:
SerializeError = other.SerializeError;
break;
+ case ResultOneofCase.TimeoutError:
+ TimeoutError = other.TimeoutError;
+ break;
case ResultOneofCase.RuntimeError:
RuntimeError = other.RuntimeError;
break;
@@ -1334,6 +1555,10 @@
TextPayload = input.ReadString();
break;
}
+ case 74: {
+ TimeoutError = input.ReadString();
+ break;
+ }
}
}
#endif
@@ -1381,6 +1606,10 @@
TextPayload = input.ReadString();
break;
}
+ case 74: {
+ TimeoutError = input.ReadString();
+ break;
+ }
}
}
}
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.pb.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.pb.cs
index bbfe2e0..d48c50e 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.pb.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto2.pb.cs
@@ -215,12 +215,68 @@
"cm90bzIiLwoORW51bU9ubHlQcm90bzIiHQoEQm9vbBIKCgZrRmFsc2UQABIJ",
"CgVrVHJ1ZRABIh8KD09uZVN0cmluZ1Byb3RvMhIMCgRkYXRhGAEgASgJIkYK",
"EVByb3RvV2l0aEtleXdvcmRzEg4KBmlubGluZRgBIAEoBRIPCgdjb25jZXB0",
- "GAIgASgJEhAKCHJlcXVpcmVzGAMgAygJKkYKEUZvcmVpZ25FbnVtUHJvdG8y",
- "Eg8KC0ZPUkVJR05fRk9PEAASDwoLRk9SRUlHTl9CQVIQARIPCgtGT1JFSUdO",
- "X0JBWhACOkoKD2V4dGVuc2lvbl9pbnQzMhIxLnByb3RvYnVmX3Rlc3RfbWVz",
- "c2FnZXMucHJvdG8yLlRlc3RBbGxUeXBlc1Byb3RvMhh4IAEoBUI4Cihjb20u",
- "Z29vZ2xlLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8ySAH4AQGiAgZQ",
- "cm90bzI="));
+ "GAIgASgJEhAKCHJlcXVpcmVzGAMgAygJIt4TChpUZXN0QWxsUmVxdWlyZWRU",
+ "eXBlc1Byb3RvMhIWCg5yZXF1aXJlZF9pbnQzMhgBIAIoBRIWCg5yZXF1aXJl",
+ "ZF9pbnQ2NBgCIAIoAxIXCg9yZXF1aXJlZF91aW50MzIYAyACKA0SFwoPcmVx",
+ "dWlyZWRfdWludDY0GAQgAigEEhcKD3JlcXVpcmVkX3NpbnQzMhgFIAIoERIX",
+ "Cg9yZXF1aXJlZF9zaW50NjQYBiACKBISGAoQcmVxdWlyZWRfZml4ZWQzMhgH",
+ "IAIoBxIYChByZXF1aXJlZF9maXhlZDY0GAggAigGEhkKEXJlcXVpcmVkX3Nm",
+ "aXhlZDMyGAkgAigPEhkKEXJlcXVpcmVkX3NmaXhlZDY0GAogAigQEhYKDnJl",
+ "cXVpcmVkX2Zsb2F0GAsgAigCEhcKD3JlcXVpcmVkX2RvdWJsZRgMIAIoARIV",
+ "Cg1yZXF1aXJlZF9ib29sGA0gAigIEhcKD3JlcXVpcmVkX3N0cmluZxgOIAIo",
+ "CRIWCg5yZXF1aXJlZF9ieXRlcxgPIAIoDBJoChdyZXF1aXJlZF9uZXN0ZWRf",
+ "bWVzc2FnZRgSIAIoCzJHLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8y",
+ "LlRlc3RBbGxSZXF1aXJlZFR5cGVzUHJvdG8yLk5lc3RlZE1lc3NhZ2USVQoY",
+ "cmVxdWlyZWRfZm9yZWlnbl9tZXNzYWdlGBMgAigLMjMucHJvdG9idWZfdGVz",
+ "dF9tZXNzYWdlcy5wcm90bzIuRm9yZWlnbk1lc3NhZ2VQcm90bzISYgoUcmVx",
+ "dWlyZWRfbmVzdGVkX2VudW0YFSACKA4yRC5wcm90b2J1Zl90ZXN0X21lc3Nh",
+ "Z2VzLnByb3RvMi5UZXN0QWxsUmVxdWlyZWRUeXBlc1Byb3RvMi5OZXN0ZWRF",
+ "bnVtEk8KFXJlcXVpcmVkX2ZvcmVpZ25fZW51bRgWIAIoDjIwLnByb3RvYnVm",
+ "X3Rlc3RfbWVzc2FnZXMucHJvdG8yLkZvcmVpZ25FbnVtUHJvdG8yEiEKFXJl",
+ "cXVpcmVkX3N0cmluZ19waWVjZRgYIAIoCUICCAISGQoNcmVxdWlyZWRfY29y",
+ "ZBgZIAIoCUICCAESVAoRcmVjdXJzaXZlX21lc3NhZ2UYGyACKAsyOS5wcm90",
+ "b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5UZXN0QWxsUmVxdWlyZWRUeXBl",
+ "c1Byb3RvMhJdChpvcHRpb25hbF9yZWN1cnNpdmVfbWVzc2FnZRgcIAEoCzI5",
+ "LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RBbGxSZXF1aXJl",
+ "ZFR5cGVzUHJvdG8yEk0KBGRhdGEYyQEgAigKMj4ucHJvdG9idWZfdGVzdF9t",
+ "ZXNzYWdlcy5wcm90bzIuVGVzdEFsbFJlcXVpcmVkVHlwZXNQcm90bzIuRGF0",
+ "YRIiCg1kZWZhdWx0X2ludDMyGPEBIAIoBToKLTEyMzQ1Njc4ORIsCg1kZWZh",
+ "dWx0X2ludDY0GPIBIAIoAzoULTkxMjM0NTY3ODkxMjM0NTY3ODkSIwoOZGVm",
+ "YXVsdF91aW50MzIY8wEgAigNOgoyMTIzNDU2Nzg5Ei0KDmRlZmF1bHRfdWlu",
+ "dDY0GPQBIAIoBDoUMTAxMjM0NTY3ODkxMjM0NTY3ODkSIwoOZGVmYXVsdF9z",
+ "aW50MzIY9QEgAigROgotMTIzNDU2Nzg5Ei0KDmRlZmF1bHRfc2ludDY0GPYB",
+ "IAIoEjoULTkxMjM0NTY3ODkxMjM0NTY3ODkSJAoPZGVmYXVsdF9maXhlZDMy",
+ "GPcBIAIoBzoKMjEyMzQ1Njc4ORIuCg9kZWZhdWx0X2ZpeGVkNjQY+AEgAigG",
+ "OhQxMDEyMzQ1Njc4OTEyMzQ1Njc4ORIlChBkZWZhdWx0X3NmaXhlZDMyGPkB",
+ "IAIoDzoKLTEyMzQ1Njc4ORIvChBkZWZhdWx0X3NmaXhlZDY0GPoBIAIoEDoU",
+ "LTkxMjM0NTY3ODkxMjM0NTY3ODkSHQoNZGVmYXVsdF9mbG9hdBj7ASACKAI6",
+ "BTllKzA5Eh4KDmRlZmF1bHRfZG91YmxlGPwBIAIoAToFN2UrMjISGwoMZGVm",
+ "YXVsdF9ib29sGP0BIAIoCDoEdHJ1ZRIgCg5kZWZhdWx0X3N0cmluZxj+ASAC",
+ "KAk6B1Jvc2VidWQSHgoNZGVmYXVsdF9ieXRlcxj/ASACKAw6Bmpvc2h1YRrD",
+ "AQoNTmVzdGVkTWVzc2FnZRIJCgFhGAEgAigFEk4KC2NvcmVjdXJzaXZlGAIg",
+ "AigLMjkucHJvdG9idWZfdGVzdF9tZXNzYWdlcy5wcm90bzIuVGVzdEFsbFJl",
+ "cXVpcmVkVHlwZXNQcm90bzISVwoUb3B0aW9uYWxfY29yZWN1cnNpdmUYAyAB",
+ "KAsyOS5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5UZXN0QWxsUmVx",
+ "dWlyZWRUeXBlc1Byb3RvMhozCgREYXRhEhQKC2dyb3VwX2ludDMyGMoBIAIo",
+ "BRIVCgxncm91cF91aW50MzIYywEgAigNGiEKEU1lc3NhZ2VTZXRDb3JyZWN0",
+ "KggIBBD/////BzoCCAEa8AEKG01lc3NhZ2VTZXRDb3JyZWN0RXh0ZW5zaW9u",
+ "MRILCgNzdHIYGSACKAkywwEKFW1lc3NhZ2Vfc2V0X2V4dGVuc2lvbhJLLnBy",
+ "b3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RBbGxSZXF1aXJlZFR5",
+ "cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0GPm7XiABKAsyVS5wcm90b2J1",
+ "Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5UZXN0QWxsUmVxdWlyZWRUeXBlc1By",
+ "b3RvMi5NZXNzYWdlU2V0Q29ycmVjdEV4dGVuc2lvbjEa7wEKG01lc3NhZ2VT",
+ "ZXRDb3JyZWN0RXh0ZW5zaW9uMhIJCgFpGAkgAigFMsQBChVtZXNzYWdlX3Nl",
+ "dF9leHRlbnNpb24SSy5wcm90b2J1Zl90ZXN0X21lc3NhZ2VzLnByb3RvMi5U",
+ "ZXN0QWxsUmVxdWlyZWRUeXBlc1Byb3RvMi5NZXNzYWdlU2V0Q29ycmVjdBiQ",
+ "s/wBIAEoCzJVLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RB",
+ "bGxSZXF1aXJlZFR5cGVzUHJvdG8yLk1lc3NhZ2VTZXRDb3JyZWN0RXh0ZW5z",
+ "aW9uMiI5CgpOZXN0ZWRFbnVtEgcKA0ZPTxAAEgcKA0JBUhABEgcKA0JBWhAC",
+ "EhAKA05FRxD///////////8BKgUIeBDJAUoGCOgHEJBOKkYKEUZvcmVpZ25F",
+ "bnVtUHJvdG8yEg8KC0ZPUkVJR05fRk9PEAASDwoLRk9SRUlHTl9CQVIQARIP",
+ "CgtGT1JFSUdOX0JBWhACOkoKD2V4dGVuc2lvbl9pbnQzMhIxLnByb3RvYnVm",
+ "X3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RBbGxUeXBlc1Byb3RvMhh4IAEo",
+ "BUI4Cihjb20uZ29vZ2xlLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8y",
+ "SAH4AQGiAgZQcm90bzI="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ProtobufTestMessages.Proto2.ForeignEnumProto2), }, new pb::Extension[] { TestMessagesProto2Extensions.ExtensionInt32 }, new pbr::GeneratedClrTypeInfo[] {
@@ -234,7 +290,12 @@
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.NullHypothesisProto2), global::ProtobufTestMessages.Proto2.NullHypothesisProto2.Parser, null, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2), global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Parser, null, null, new[]{ typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Types.Bool) }, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.OneStringProto2), global::ProtobufTestMessages.Proto2.OneStringProto2.Parser, new[]{ "Data" }, null, null, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.ProtoWithKeywords), global::ProtobufTestMessages.Proto2.ProtoWithKeywords.Parser, new[]{ "Inline", "Concept", "Requires" }, null, null, null, null)
+ new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.ProtoWithKeywords), global::ProtobufTestMessages.Proto2.ProtoWithKeywords.Parser, new[]{ "Inline", "Concept", "Requires" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2), global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Parser, new[]{ "RequiredInt32", "RequiredInt64", "RequiredUint32", "RequiredUint64", "RequiredSint32", "RequiredSint64", "RequiredFixed32", "RequiredFixed64", "RequiredSfixed32", "RequiredSfixed64", "RequiredFloat", "RequiredDouble", "RequiredBool", "RequiredString", "RequiredBytes", "RequiredNestedMessage", "RequiredForeignMessage", "RequiredNestedEnum", "RequiredForeignEnum", "RequiredStringPiece", "RequiredCord", "RecursiveMessage", "OptionalRecursiveMessage", "Data", "DefaultInt32", "DefaultInt64", "DefaultUint32", "DefaultUint64", "DefaultSint32", "DefaultSint64", "DefaultFixed32", "DefaultFixed64", "DefaultSfixed32", "DefaultSfixed64", "DefaultFloat", "DefaultDouble", "DefaultBool", "DefaultString", "DefaultBytes" }, null, new[]{ typeof(global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedEnum) }, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedMessage), global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedMessage.Parser, new[]{ "A", "Corecursive", "OptionalCorecursive" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.Data), global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.Data.Parser, new[]{ "GroupInt32", "GroupUint32" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrect), global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrect.Parser, null, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension1), global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension1.Parser, new[]{ "Str" }, null, null, new pb::Extension[] { global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension1.Extensions.MessageSetExtension }, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension2), global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension2.Parser, new[]{ "I" }, null, null, new pb::Extension[] { global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension2.Extensions.MessageSetExtension }, null)})
}));
}
#endregion
@@ -8586,6 +8647,3427 @@
}
+ public sealed partial class TestAllRequiredTypesProto2 : pb::IExtendableMessage<TestAllRequiredTypesProto2>
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser<TestAllRequiredTypesProto2> _parser = new pb::MessageParser<TestAllRequiredTypesProto2>(() => new TestAllRequiredTypesProto2());
+ private pb::UnknownFieldSet _unknownFields;
+ private pb::ExtensionSet<TestAllRequiredTypesProto2> _extensions;
+ private pb::ExtensionSet<TestAllRequiredTypesProto2> _Extensions { get { return _extensions; } }
+ private int _hasBits0;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser<TestAllRequiredTypesProto2> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ProtobufTestMessages.Proto2.TestMessagesProto2Reflection.Descriptor.MessageTypes[7]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public TestAllRequiredTypesProto2() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public TestAllRequiredTypesProto2(TestAllRequiredTypesProto2 other) : this() {
+ _hasBits0 = other._hasBits0;
+ requiredInt32_ = other.requiredInt32_;
+ requiredInt64_ = other.requiredInt64_;
+ requiredUint32_ = other.requiredUint32_;
+ requiredUint64_ = other.requiredUint64_;
+ requiredSint32_ = other.requiredSint32_;
+ requiredSint64_ = other.requiredSint64_;
+ requiredFixed32_ = other.requiredFixed32_;
+ requiredFixed64_ = other.requiredFixed64_;
+ requiredSfixed32_ = other.requiredSfixed32_;
+ requiredSfixed64_ = other.requiredSfixed64_;
+ requiredFloat_ = other.requiredFloat_;
+ requiredDouble_ = other.requiredDouble_;
+ requiredBool_ = other.requiredBool_;
+ requiredString_ = other.requiredString_;
+ requiredBytes_ = other.requiredBytes_;
+ requiredNestedMessage_ = other.requiredNestedMessage_ != null ? other.requiredNestedMessage_.Clone() : null;
+ requiredForeignMessage_ = other.requiredForeignMessage_ != null ? other.requiredForeignMessage_.Clone() : null;
+ requiredNestedEnum_ = other.requiredNestedEnum_;
+ requiredForeignEnum_ = other.requiredForeignEnum_;
+ requiredStringPiece_ = other.requiredStringPiece_;
+ requiredCord_ = other.requiredCord_;
+ recursiveMessage_ = other.recursiveMessage_ != null ? other.recursiveMessage_.Clone() : null;
+ optionalRecursiveMessage_ = other.optionalRecursiveMessage_ != null ? other.optionalRecursiveMessage_.Clone() : null;
+ data_ = other.HasData ? other.data_.Clone() : null;
+ defaultInt32_ = other.defaultInt32_;
+ defaultInt64_ = other.defaultInt64_;
+ defaultUint32_ = other.defaultUint32_;
+ defaultUint64_ = other.defaultUint64_;
+ defaultSint32_ = other.defaultSint32_;
+ defaultSint64_ = other.defaultSint64_;
+ defaultFixed32_ = other.defaultFixed32_;
+ defaultFixed64_ = other.defaultFixed64_;
+ defaultSfixed32_ = other.defaultSfixed32_;
+ defaultSfixed64_ = other.defaultSfixed64_;
+ defaultFloat_ = other.defaultFloat_;
+ defaultDouble_ = other.defaultDouble_;
+ defaultBool_ = other.defaultBool_;
+ defaultString_ = other.defaultString_;
+ defaultBytes_ = other.defaultBytes_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ _extensions = pb::ExtensionSet.Clone(other._extensions);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public TestAllRequiredTypesProto2 Clone() {
+ return new TestAllRequiredTypesProto2(this);
+ }
+
+ /// <summary>Field number for the "required_int32" field.</summary>
+ public const int RequiredInt32FieldNumber = 1;
+ private readonly static int RequiredInt32DefaultValue = 0;
+
+ private int requiredInt32_;
+ /// <summary>
+ /// Singular
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int RequiredInt32 {
+ get { if ((_hasBits0 & 1) != 0) { return requiredInt32_; } else { return RequiredInt32DefaultValue; } }
+ set {
+ _hasBits0 |= 1;
+ requiredInt32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_int32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredInt32 {
+ get { return (_hasBits0 & 1) != 0; }
+ }
+ /// <summary>Clears the value of the "required_int32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredInt32() {
+ _hasBits0 &= ~1;
+ }
+
+ /// <summary>Field number for the "required_int64" field.</summary>
+ public const int RequiredInt64FieldNumber = 2;
+ private readonly static long RequiredInt64DefaultValue = 0L;
+
+ private long requiredInt64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public long RequiredInt64 {
+ get { if ((_hasBits0 & 2) != 0) { return requiredInt64_; } else { return RequiredInt64DefaultValue; } }
+ set {
+ _hasBits0 |= 2;
+ requiredInt64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_int64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredInt64 {
+ get { return (_hasBits0 & 2) != 0; }
+ }
+ /// <summary>Clears the value of the "required_int64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredInt64() {
+ _hasBits0 &= ~2;
+ }
+
+ /// <summary>Field number for the "required_uint32" field.</summary>
+ public const int RequiredUint32FieldNumber = 3;
+ private readonly static uint RequiredUint32DefaultValue = 0;
+
+ private uint requiredUint32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public uint RequiredUint32 {
+ get { if ((_hasBits0 & 4) != 0) { return requiredUint32_; } else { return RequiredUint32DefaultValue; } }
+ set {
+ _hasBits0 |= 4;
+ requiredUint32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_uint32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredUint32 {
+ get { return (_hasBits0 & 4) != 0; }
+ }
+ /// <summary>Clears the value of the "required_uint32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredUint32() {
+ _hasBits0 &= ~4;
+ }
+
+ /// <summary>Field number for the "required_uint64" field.</summary>
+ public const int RequiredUint64FieldNumber = 4;
+ private readonly static ulong RequiredUint64DefaultValue = 0UL;
+
+ private ulong requiredUint64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public ulong RequiredUint64 {
+ get { if ((_hasBits0 & 8) != 0) { return requiredUint64_; } else { return RequiredUint64DefaultValue; } }
+ set {
+ _hasBits0 |= 8;
+ requiredUint64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_uint64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredUint64 {
+ get { return (_hasBits0 & 8) != 0; }
+ }
+ /// <summary>Clears the value of the "required_uint64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredUint64() {
+ _hasBits0 &= ~8;
+ }
+
+ /// <summary>Field number for the "required_sint32" field.</summary>
+ public const int RequiredSint32FieldNumber = 5;
+ private readonly static int RequiredSint32DefaultValue = 0;
+
+ private int requiredSint32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int RequiredSint32 {
+ get { if ((_hasBits0 & 16) != 0) { return requiredSint32_; } else { return RequiredSint32DefaultValue; } }
+ set {
+ _hasBits0 |= 16;
+ requiredSint32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_sint32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredSint32 {
+ get { return (_hasBits0 & 16) != 0; }
+ }
+ /// <summary>Clears the value of the "required_sint32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredSint32() {
+ _hasBits0 &= ~16;
+ }
+
+ /// <summary>Field number for the "required_sint64" field.</summary>
+ public const int RequiredSint64FieldNumber = 6;
+ private readonly static long RequiredSint64DefaultValue = 0L;
+
+ private long requiredSint64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public long RequiredSint64 {
+ get { if ((_hasBits0 & 32) != 0) { return requiredSint64_; } else { return RequiredSint64DefaultValue; } }
+ set {
+ _hasBits0 |= 32;
+ requiredSint64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_sint64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredSint64 {
+ get { return (_hasBits0 & 32) != 0; }
+ }
+ /// <summary>Clears the value of the "required_sint64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredSint64() {
+ _hasBits0 &= ~32;
+ }
+
+ /// <summary>Field number for the "required_fixed32" field.</summary>
+ public const int RequiredFixed32FieldNumber = 7;
+ private readonly static uint RequiredFixed32DefaultValue = 0;
+
+ private uint requiredFixed32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public uint RequiredFixed32 {
+ get { if ((_hasBits0 & 64) != 0) { return requiredFixed32_; } else { return RequiredFixed32DefaultValue; } }
+ set {
+ _hasBits0 |= 64;
+ requiredFixed32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_fixed32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredFixed32 {
+ get { return (_hasBits0 & 64) != 0; }
+ }
+ /// <summary>Clears the value of the "required_fixed32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredFixed32() {
+ _hasBits0 &= ~64;
+ }
+
+ /// <summary>Field number for the "required_fixed64" field.</summary>
+ public const int RequiredFixed64FieldNumber = 8;
+ private readonly static ulong RequiredFixed64DefaultValue = 0UL;
+
+ private ulong requiredFixed64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public ulong RequiredFixed64 {
+ get { if ((_hasBits0 & 128) != 0) { return requiredFixed64_; } else { return RequiredFixed64DefaultValue; } }
+ set {
+ _hasBits0 |= 128;
+ requiredFixed64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_fixed64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredFixed64 {
+ get { return (_hasBits0 & 128) != 0; }
+ }
+ /// <summary>Clears the value of the "required_fixed64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredFixed64() {
+ _hasBits0 &= ~128;
+ }
+
+ /// <summary>Field number for the "required_sfixed32" field.</summary>
+ public const int RequiredSfixed32FieldNumber = 9;
+ private readonly static int RequiredSfixed32DefaultValue = 0;
+
+ private int requiredSfixed32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int RequiredSfixed32 {
+ get { if ((_hasBits0 & 256) != 0) { return requiredSfixed32_; } else { return RequiredSfixed32DefaultValue; } }
+ set {
+ _hasBits0 |= 256;
+ requiredSfixed32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_sfixed32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredSfixed32 {
+ get { return (_hasBits0 & 256) != 0; }
+ }
+ /// <summary>Clears the value of the "required_sfixed32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredSfixed32() {
+ _hasBits0 &= ~256;
+ }
+
+ /// <summary>Field number for the "required_sfixed64" field.</summary>
+ public const int RequiredSfixed64FieldNumber = 10;
+ private readonly static long RequiredSfixed64DefaultValue = 0L;
+
+ private long requiredSfixed64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public long RequiredSfixed64 {
+ get { if ((_hasBits0 & 512) != 0) { return requiredSfixed64_; } else { return RequiredSfixed64DefaultValue; } }
+ set {
+ _hasBits0 |= 512;
+ requiredSfixed64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_sfixed64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredSfixed64 {
+ get { return (_hasBits0 & 512) != 0; }
+ }
+ /// <summary>Clears the value of the "required_sfixed64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredSfixed64() {
+ _hasBits0 &= ~512;
+ }
+
+ /// <summary>Field number for the "required_float" field.</summary>
+ public const int RequiredFloatFieldNumber = 11;
+ private readonly static float RequiredFloatDefaultValue = 0F;
+
+ private float requiredFloat_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public float RequiredFloat {
+ get { if ((_hasBits0 & 1024) != 0) { return requiredFloat_; } else { return RequiredFloatDefaultValue; } }
+ set {
+ _hasBits0 |= 1024;
+ requiredFloat_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_float" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredFloat {
+ get { return (_hasBits0 & 1024) != 0; }
+ }
+ /// <summary>Clears the value of the "required_float" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredFloat() {
+ _hasBits0 &= ~1024;
+ }
+
+ /// <summary>Field number for the "required_double" field.</summary>
+ public const int RequiredDoubleFieldNumber = 12;
+ private readonly static double RequiredDoubleDefaultValue = 0D;
+
+ private double requiredDouble_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public double RequiredDouble {
+ get { if ((_hasBits0 & 2048) != 0) { return requiredDouble_; } else { return RequiredDoubleDefaultValue; } }
+ set {
+ _hasBits0 |= 2048;
+ requiredDouble_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_double" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredDouble {
+ get { return (_hasBits0 & 2048) != 0; }
+ }
+ /// <summary>Clears the value of the "required_double" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredDouble() {
+ _hasBits0 &= ~2048;
+ }
+
+ /// <summary>Field number for the "required_bool" field.</summary>
+ public const int RequiredBoolFieldNumber = 13;
+ private readonly static bool RequiredBoolDefaultValue = false;
+
+ private bool requiredBool_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool RequiredBool {
+ get { if ((_hasBits0 & 4096) != 0) { return requiredBool_; } else { return RequiredBoolDefaultValue; } }
+ set {
+ _hasBits0 |= 4096;
+ requiredBool_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_bool" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredBool {
+ get { return (_hasBits0 & 4096) != 0; }
+ }
+ /// <summary>Clears the value of the "required_bool" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredBool() {
+ _hasBits0 &= ~4096;
+ }
+
+ /// <summary>Field number for the "required_string" field.</summary>
+ public const int RequiredStringFieldNumber = 14;
+ private readonly static string RequiredStringDefaultValue = "";
+
+ private string requiredString_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string RequiredString {
+ get { return requiredString_ ?? RequiredStringDefaultValue; }
+ set {
+ requiredString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+ /// <summary>Gets whether the "required_string" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredString {
+ get { return requiredString_ != null; }
+ }
+ /// <summary>Clears the value of the "required_string" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredString() {
+ requiredString_ = null;
+ }
+
+ /// <summary>Field number for the "required_bytes" field.</summary>
+ public const int RequiredBytesFieldNumber = 15;
+ private readonly static pb::ByteString RequiredBytesDefaultValue = pb::ByteString.Empty;
+
+ private pb::ByteString requiredBytes_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public pb::ByteString RequiredBytes {
+ get { return requiredBytes_ ?? RequiredBytesDefaultValue; }
+ set {
+ requiredBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+ /// <summary>Gets whether the "required_bytes" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredBytes {
+ get { return requiredBytes_ != null; }
+ }
+ /// <summary>Clears the value of the "required_bytes" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredBytes() {
+ requiredBytes_ = null;
+ }
+
+ /// <summary>Field number for the "required_nested_message" field.</summary>
+ public const int RequiredNestedMessageFieldNumber = 18;
+ private global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedMessage requiredNestedMessage_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedMessage RequiredNestedMessage {
+ get { return requiredNestedMessage_; }
+ set {
+ requiredNestedMessage_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "required_foreign_message" field.</summary>
+ public const int RequiredForeignMessageFieldNumber = 19;
+ private global::ProtobufTestMessages.Proto2.ForeignMessageProto2 requiredForeignMessage_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.ForeignMessageProto2 RequiredForeignMessage {
+ get { return requiredForeignMessage_; }
+ set {
+ requiredForeignMessage_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "required_nested_enum" field.</summary>
+ public const int RequiredNestedEnumFieldNumber = 21;
+ private readonly static global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedEnum RequiredNestedEnumDefaultValue = global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedEnum.Foo;
+
+ private global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedEnum requiredNestedEnum_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedEnum RequiredNestedEnum {
+ get { if ((_hasBits0 & 8192) != 0) { return requiredNestedEnum_; } else { return RequiredNestedEnumDefaultValue; } }
+ set {
+ _hasBits0 |= 8192;
+ requiredNestedEnum_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_nested_enum" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredNestedEnum {
+ get { return (_hasBits0 & 8192) != 0; }
+ }
+ /// <summary>Clears the value of the "required_nested_enum" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredNestedEnum() {
+ _hasBits0 &= ~8192;
+ }
+
+ /// <summary>Field number for the "required_foreign_enum" field.</summary>
+ public const int RequiredForeignEnumFieldNumber = 22;
+ private readonly static global::ProtobufTestMessages.Proto2.ForeignEnumProto2 RequiredForeignEnumDefaultValue = global::ProtobufTestMessages.Proto2.ForeignEnumProto2.ForeignFoo;
+
+ private global::ProtobufTestMessages.Proto2.ForeignEnumProto2 requiredForeignEnum_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.ForeignEnumProto2 RequiredForeignEnum {
+ get { if ((_hasBits0 & 16384) != 0) { return requiredForeignEnum_; } else { return RequiredForeignEnumDefaultValue; } }
+ set {
+ _hasBits0 |= 16384;
+ requiredForeignEnum_ = value;
+ }
+ }
+ /// <summary>Gets whether the "required_foreign_enum" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredForeignEnum {
+ get { return (_hasBits0 & 16384) != 0; }
+ }
+ /// <summary>Clears the value of the "required_foreign_enum" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredForeignEnum() {
+ _hasBits0 &= ~16384;
+ }
+
+ /// <summary>Field number for the "required_string_piece" field.</summary>
+ public const int RequiredStringPieceFieldNumber = 24;
+ private readonly static string RequiredStringPieceDefaultValue = "";
+
+ private string requiredStringPiece_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string RequiredStringPiece {
+ get { return requiredStringPiece_ ?? RequiredStringPieceDefaultValue; }
+ set {
+ requiredStringPiece_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+ /// <summary>Gets whether the "required_string_piece" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredStringPiece {
+ get { return requiredStringPiece_ != null; }
+ }
+ /// <summary>Clears the value of the "required_string_piece" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredStringPiece() {
+ requiredStringPiece_ = null;
+ }
+
+ /// <summary>Field number for the "required_cord" field.</summary>
+ public const int RequiredCordFieldNumber = 25;
+ private readonly static string RequiredCordDefaultValue = "";
+
+ private string requiredCord_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string RequiredCord {
+ get { return requiredCord_ ?? RequiredCordDefaultValue; }
+ set {
+ requiredCord_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+ /// <summary>Gets whether the "required_cord" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasRequiredCord {
+ get { return requiredCord_ != null; }
+ }
+ /// <summary>Clears the value of the "required_cord" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearRequiredCord() {
+ requiredCord_ = null;
+ }
+
+ /// <summary>Field number for the "recursive_message" field.</summary>
+ public const int RecursiveMessageFieldNumber = 27;
+ private global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 recursiveMessage_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 RecursiveMessage {
+ get { return recursiveMessage_; }
+ set {
+ recursiveMessage_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "optional_recursive_message" field.</summary>
+ public const int OptionalRecursiveMessageFieldNumber = 28;
+ private global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 optionalRecursiveMessage_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 OptionalRecursiveMessage {
+ get { return optionalRecursiveMessage_; }
+ set {
+ optionalRecursiveMessage_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "data" field.</summary>
+ public const int DataFieldNumber = 201;
+ private global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.Data data_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.Data Data {
+ get { return data_; }
+ set {
+ data_ = value;
+ }
+ }
+ /// <summary>Gets whether the data field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasData {
+ get { return data_ != null; }
+ }
+ /// <summary>Clears the value of the data field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearData() {
+ data_ = null;
+ }
+
+ /// <summary>Field number for the "default_int32" field.</summary>
+ public const int DefaultInt32FieldNumber = 241;
+ private readonly static int DefaultInt32DefaultValue = -123456789;
+
+ private int defaultInt32_;
+ /// <summary>
+ /// default values
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int DefaultInt32 {
+ get { if ((_hasBits0 & 32768) != 0) { return defaultInt32_; } else { return DefaultInt32DefaultValue; } }
+ set {
+ _hasBits0 |= 32768;
+ defaultInt32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_int32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultInt32 {
+ get { return (_hasBits0 & 32768) != 0; }
+ }
+ /// <summary>Clears the value of the "default_int32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultInt32() {
+ _hasBits0 &= ~32768;
+ }
+
+ /// <summary>Field number for the "default_int64" field.</summary>
+ public const int DefaultInt64FieldNumber = 242;
+ private readonly static long DefaultInt64DefaultValue = -9123456789123456789L;
+
+ private long defaultInt64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public long DefaultInt64 {
+ get { if ((_hasBits0 & 65536) != 0) { return defaultInt64_; } else { return DefaultInt64DefaultValue; } }
+ set {
+ _hasBits0 |= 65536;
+ defaultInt64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_int64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultInt64 {
+ get { return (_hasBits0 & 65536) != 0; }
+ }
+ /// <summary>Clears the value of the "default_int64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultInt64() {
+ _hasBits0 &= ~65536;
+ }
+
+ /// <summary>Field number for the "default_uint32" field.</summary>
+ public const int DefaultUint32FieldNumber = 243;
+ private readonly static uint DefaultUint32DefaultValue = 2123456789;
+
+ private uint defaultUint32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public uint DefaultUint32 {
+ get { if ((_hasBits0 & 131072) != 0) { return defaultUint32_; } else { return DefaultUint32DefaultValue; } }
+ set {
+ _hasBits0 |= 131072;
+ defaultUint32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_uint32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultUint32 {
+ get { return (_hasBits0 & 131072) != 0; }
+ }
+ /// <summary>Clears the value of the "default_uint32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultUint32() {
+ _hasBits0 &= ~131072;
+ }
+
+ /// <summary>Field number for the "default_uint64" field.</summary>
+ public const int DefaultUint64FieldNumber = 244;
+ private readonly static ulong DefaultUint64DefaultValue = 10123456789123456789UL;
+
+ private ulong defaultUint64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public ulong DefaultUint64 {
+ get { if ((_hasBits0 & 262144) != 0) { return defaultUint64_; } else { return DefaultUint64DefaultValue; } }
+ set {
+ _hasBits0 |= 262144;
+ defaultUint64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_uint64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultUint64 {
+ get { return (_hasBits0 & 262144) != 0; }
+ }
+ /// <summary>Clears the value of the "default_uint64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultUint64() {
+ _hasBits0 &= ~262144;
+ }
+
+ /// <summary>Field number for the "default_sint32" field.</summary>
+ public const int DefaultSint32FieldNumber = 245;
+ private readonly static int DefaultSint32DefaultValue = -123456789;
+
+ private int defaultSint32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int DefaultSint32 {
+ get { if ((_hasBits0 & 524288) != 0) { return defaultSint32_; } else { return DefaultSint32DefaultValue; } }
+ set {
+ _hasBits0 |= 524288;
+ defaultSint32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_sint32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultSint32 {
+ get { return (_hasBits0 & 524288) != 0; }
+ }
+ /// <summary>Clears the value of the "default_sint32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultSint32() {
+ _hasBits0 &= ~524288;
+ }
+
+ /// <summary>Field number for the "default_sint64" field.</summary>
+ public const int DefaultSint64FieldNumber = 246;
+ private readonly static long DefaultSint64DefaultValue = -9123456789123456789L;
+
+ private long defaultSint64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public long DefaultSint64 {
+ get { if ((_hasBits0 & 1048576) != 0) { return defaultSint64_; } else { return DefaultSint64DefaultValue; } }
+ set {
+ _hasBits0 |= 1048576;
+ defaultSint64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_sint64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultSint64 {
+ get { return (_hasBits0 & 1048576) != 0; }
+ }
+ /// <summary>Clears the value of the "default_sint64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultSint64() {
+ _hasBits0 &= ~1048576;
+ }
+
+ /// <summary>Field number for the "default_fixed32" field.</summary>
+ public const int DefaultFixed32FieldNumber = 247;
+ private readonly static uint DefaultFixed32DefaultValue = 2123456789;
+
+ private uint defaultFixed32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public uint DefaultFixed32 {
+ get { if ((_hasBits0 & 2097152) != 0) { return defaultFixed32_; } else { return DefaultFixed32DefaultValue; } }
+ set {
+ _hasBits0 |= 2097152;
+ defaultFixed32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_fixed32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultFixed32 {
+ get { return (_hasBits0 & 2097152) != 0; }
+ }
+ /// <summary>Clears the value of the "default_fixed32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultFixed32() {
+ _hasBits0 &= ~2097152;
+ }
+
+ /// <summary>Field number for the "default_fixed64" field.</summary>
+ public const int DefaultFixed64FieldNumber = 248;
+ private readonly static ulong DefaultFixed64DefaultValue = 10123456789123456789UL;
+
+ private ulong defaultFixed64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public ulong DefaultFixed64 {
+ get { if ((_hasBits0 & 4194304) != 0) { return defaultFixed64_; } else { return DefaultFixed64DefaultValue; } }
+ set {
+ _hasBits0 |= 4194304;
+ defaultFixed64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_fixed64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultFixed64 {
+ get { return (_hasBits0 & 4194304) != 0; }
+ }
+ /// <summary>Clears the value of the "default_fixed64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultFixed64() {
+ _hasBits0 &= ~4194304;
+ }
+
+ /// <summary>Field number for the "default_sfixed32" field.</summary>
+ public const int DefaultSfixed32FieldNumber = 249;
+ private readonly static int DefaultSfixed32DefaultValue = -123456789;
+
+ private int defaultSfixed32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int DefaultSfixed32 {
+ get { if ((_hasBits0 & 8388608) != 0) { return defaultSfixed32_; } else { return DefaultSfixed32DefaultValue; } }
+ set {
+ _hasBits0 |= 8388608;
+ defaultSfixed32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_sfixed32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultSfixed32 {
+ get { return (_hasBits0 & 8388608) != 0; }
+ }
+ /// <summary>Clears the value of the "default_sfixed32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultSfixed32() {
+ _hasBits0 &= ~8388608;
+ }
+
+ /// <summary>Field number for the "default_sfixed64" field.</summary>
+ public const int DefaultSfixed64FieldNumber = 250;
+ private readonly static long DefaultSfixed64DefaultValue = -9123456789123456789L;
+
+ private long defaultSfixed64_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public long DefaultSfixed64 {
+ get { if ((_hasBits0 & 16777216) != 0) { return defaultSfixed64_; } else { return DefaultSfixed64DefaultValue; } }
+ set {
+ _hasBits0 |= 16777216;
+ defaultSfixed64_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_sfixed64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultSfixed64 {
+ get { return (_hasBits0 & 16777216) != 0; }
+ }
+ /// <summary>Clears the value of the "default_sfixed64" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultSfixed64() {
+ _hasBits0 &= ~16777216;
+ }
+
+ /// <summary>Field number for the "default_float" field.</summary>
+ public const int DefaultFloatFieldNumber = 251;
+ private readonly static float DefaultFloatDefaultValue = 9e+09F;
+
+ private float defaultFloat_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public float DefaultFloat {
+ get { if ((_hasBits0 & 33554432) != 0) { return defaultFloat_; } else { return DefaultFloatDefaultValue; } }
+ set {
+ _hasBits0 |= 33554432;
+ defaultFloat_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_float" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultFloat {
+ get { return (_hasBits0 & 33554432) != 0; }
+ }
+ /// <summary>Clears the value of the "default_float" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultFloat() {
+ _hasBits0 &= ~33554432;
+ }
+
+ /// <summary>Field number for the "default_double" field.</summary>
+ public const int DefaultDoubleFieldNumber = 252;
+ private readonly static double DefaultDoubleDefaultValue = 7e+22D;
+
+ private double defaultDouble_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public double DefaultDouble {
+ get { if ((_hasBits0 & 67108864) != 0) { return defaultDouble_; } else { return DefaultDoubleDefaultValue; } }
+ set {
+ _hasBits0 |= 67108864;
+ defaultDouble_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_double" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultDouble {
+ get { return (_hasBits0 & 67108864) != 0; }
+ }
+ /// <summary>Clears the value of the "default_double" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultDouble() {
+ _hasBits0 &= ~67108864;
+ }
+
+ /// <summary>Field number for the "default_bool" field.</summary>
+ public const int DefaultBoolFieldNumber = 253;
+ private readonly static bool DefaultBoolDefaultValue = true;
+
+ private bool defaultBool_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool DefaultBool {
+ get { if ((_hasBits0 & 134217728) != 0) { return defaultBool_; } else { return DefaultBoolDefaultValue; } }
+ set {
+ _hasBits0 |= 134217728;
+ defaultBool_ = value;
+ }
+ }
+ /// <summary>Gets whether the "default_bool" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultBool {
+ get { return (_hasBits0 & 134217728) != 0; }
+ }
+ /// <summary>Clears the value of the "default_bool" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultBool() {
+ _hasBits0 &= ~134217728;
+ }
+
+ /// <summary>Field number for the "default_string" field.</summary>
+ public const int DefaultStringFieldNumber = 254;
+ private readonly static string DefaultStringDefaultValue = global::System.Text.Encoding.UTF8.GetString(global::System.Convert.FromBase64String("Um9zZWJ1ZA=="), 0, 7);
+
+ private string defaultString_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string DefaultString {
+ get { return defaultString_ ?? DefaultStringDefaultValue; }
+ set {
+ defaultString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+ /// <summary>Gets whether the "default_string" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultString {
+ get { return defaultString_ != null; }
+ }
+ /// <summary>Clears the value of the "default_string" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultString() {
+ defaultString_ = null;
+ }
+
+ /// <summary>Field number for the "default_bytes" field.</summary>
+ public const int DefaultBytesFieldNumber = 255;
+ private readonly static pb::ByteString DefaultBytesDefaultValue = pb::ByteString.FromBase64("am9zaHVh");
+
+ private pb::ByteString defaultBytes_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public pb::ByteString DefaultBytes {
+ get { return defaultBytes_ ?? DefaultBytesDefaultValue; }
+ set {
+ defaultBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+ /// <summary>Gets whether the "default_bytes" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasDefaultBytes {
+ get { return defaultBytes_ != null; }
+ }
+ /// <summary>Clears the value of the "default_bytes" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearDefaultBytes() {
+ defaultBytes_ = null;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as TestAllRequiredTypesProto2);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(TestAllRequiredTypesProto2 other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (RequiredInt32 != other.RequiredInt32) return false;
+ if (RequiredInt64 != other.RequiredInt64) return false;
+ if (RequiredUint32 != other.RequiredUint32) return false;
+ if (RequiredUint64 != other.RequiredUint64) return false;
+ if (RequiredSint32 != other.RequiredSint32) return false;
+ if (RequiredSint64 != other.RequiredSint64) return false;
+ if (RequiredFixed32 != other.RequiredFixed32) return false;
+ if (RequiredFixed64 != other.RequiredFixed64) return false;
+ if (RequiredSfixed32 != other.RequiredSfixed32) return false;
+ if (RequiredSfixed64 != other.RequiredSfixed64) return false;
+ if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(RequiredFloat, other.RequiredFloat)) return false;
+ if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(RequiredDouble, other.RequiredDouble)) return false;
+ if (RequiredBool != other.RequiredBool) return false;
+ if (RequiredString != other.RequiredString) return false;
+ if (RequiredBytes != other.RequiredBytes) return false;
+ if (!object.Equals(RequiredNestedMessage, other.RequiredNestedMessage)) return false;
+ if (!object.Equals(RequiredForeignMessage, other.RequiredForeignMessage)) return false;
+ if (RequiredNestedEnum != other.RequiredNestedEnum) return false;
+ if (RequiredForeignEnum != other.RequiredForeignEnum) return false;
+ if (RequiredStringPiece != other.RequiredStringPiece) return false;
+ if (RequiredCord != other.RequiredCord) return false;
+ if (!object.Equals(RecursiveMessage, other.RecursiveMessage)) return false;
+ if (!object.Equals(OptionalRecursiveMessage, other.OptionalRecursiveMessage)) return false;
+ if (!object.Equals(Data, other.Data)) return false;
+ if (DefaultInt32 != other.DefaultInt32) return false;
+ if (DefaultInt64 != other.DefaultInt64) return false;
+ if (DefaultUint32 != other.DefaultUint32) return false;
+ if (DefaultUint64 != other.DefaultUint64) return false;
+ if (DefaultSint32 != other.DefaultSint32) return false;
+ if (DefaultSint64 != other.DefaultSint64) return false;
+ if (DefaultFixed32 != other.DefaultFixed32) return false;
+ if (DefaultFixed64 != other.DefaultFixed64) return false;
+ if (DefaultSfixed32 != other.DefaultSfixed32) return false;
+ if (DefaultSfixed64 != other.DefaultSfixed64) return false;
+ if (!pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.Equals(DefaultFloat, other.DefaultFloat)) return false;
+ if (!pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.Equals(DefaultDouble, other.DefaultDouble)) return false;
+ if (DefaultBool != other.DefaultBool) return false;
+ if (DefaultString != other.DefaultString) return false;
+ if (DefaultBytes != other.DefaultBytes) return false;
+ if (!Equals(_extensions, other._extensions)) {
+ return false;
+ }
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (HasRequiredInt32) hash ^= RequiredInt32.GetHashCode();
+ if (HasRequiredInt64) hash ^= RequiredInt64.GetHashCode();
+ if (HasRequiredUint32) hash ^= RequiredUint32.GetHashCode();
+ if (HasRequiredUint64) hash ^= RequiredUint64.GetHashCode();
+ if (HasRequiredSint32) hash ^= RequiredSint32.GetHashCode();
+ if (HasRequiredSint64) hash ^= RequiredSint64.GetHashCode();
+ if (HasRequiredFixed32) hash ^= RequiredFixed32.GetHashCode();
+ if (HasRequiredFixed64) hash ^= RequiredFixed64.GetHashCode();
+ if (HasRequiredSfixed32) hash ^= RequiredSfixed32.GetHashCode();
+ if (HasRequiredSfixed64) hash ^= RequiredSfixed64.GetHashCode();
+ if (HasRequiredFloat) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(RequiredFloat);
+ if (HasRequiredDouble) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(RequiredDouble);
+ if (HasRequiredBool) hash ^= RequiredBool.GetHashCode();
+ if (HasRequiredString) hash ^= RequiredString.GetHashCode();
+ if (HasRequiredBytes) hash ^= RequiredBytes.GetHashCode();
+ if (requiredNestedMessage_ != null) hash ^= RequiredNestedMessage.GetHashCode();
+ if (requiredForeignMessage_ != null) hash ^= RequiredForeignMessage.GetHashCode();
+ if (HasRequiredNestedEnum) hash ^= RequiredNestedEnum.GetHashCode();
+ if (HasRequiredForeignEnum) hash ^= RequiredForeignEnum.GetHashCode();
+ if (HasRequiredStringPiece) hash ^= RequiredStringPiece.GetHashCode();
+ if (HasRequiredCord) hash ^= RequiredCord.GetHashCode();
+ if (recursiveMessage_ != null) hash ^= RecursiveMessage.GetHashCode();
+ if (optionalRecursiveMessage_ != null) hash ^= OptionalRecursiveMessage.GetHashCode();
+ if (HasData) hash ^= Data.GetHashCode();
+ if (HasDefaultInt32) hash ^= DefaultInt32.GetHashCode();
+ if (HasDefaultInt64) hash ^= DefaultInt64.GetHashCode();
+ if (HasDefaultUint32) hash ^= DefaultUint32.GetHashCode();
+ if (HasDefaultUint64) hash ^= DefaultUint64.GetHashCode();
+ if (HasDefaultSint32) hash ^= DefaultSint32.GetHashCode();
+ if (HasDefaultSint64) hash ^= DefaultSint64.GetHashCode();
+ if (HasDefaultFixed32) hash ^= DefaultFixed32.GetHashCode();
+ if (HasDefaultFixed64) hash ^= DefaultFixed64.GetHashCode();
+ if (HasDefaultSfixed32) hash ^= DefaultSfixed32.GetHashCode();
+ if (HasDefaultSfixed64) hash ^= DefaultSfixed64.GetHashCode();
+ if (HasDefaultFloat) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(DefaultFloat);
+ if (HasDefaultDouble) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(DefaultDouble);
+ if (HasDefaultBool) hash ^= DefaultBool.GetHashCode();
+ if (HasDefaultString) hash ^= DefaultString.GetHashCode();
+ if (HasDefaultBytes) hash ^= DefaultBytes.GetHashCode();
+ if (_extensions != null) {
+ hash ^= _extensions.GetHashCode();
+ }
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (HasRequiredInt32) {
+ output.WriteRawTag(8);
+ output.WriteInt32(RequiredInt32);
+ }
+ if (HasRequiredInt64) {
+ output.WriteRawTag(16);
+ output.WriteInt64(RequiredInt64);
+ }
+ if (HasRequiredUint32) {
+ output.WriteRawTag(24);
+ output.WriteUInt32(RequiredUint32);
+ }
+ if (HasRequiredUint64) {
+ output.WriteRawTag(32);
+ output.WriteUInt64(RequiredUint64);
+ }
+ if (HasRequiredSint32) {
+ output.WriteRawTag(40);
+ output.WriteSInt32(RequiredSint32);
+ }
+ if (HasRequiredSint64) {
+ output.WriteRawTag(48);
+ output.WriteSInt64(RequiredSint64);
+ }
+ if (HasRequiredFixed32) {
+ output.WriteRawTag(61);
+ output.WriteFixed32(RequiredFixed32);
+ }
+ if (HasRequiredFixed64) {
+ output.WriteRawTag(65);
+ output.WriteFixed64(RequiredFixed64);
+ }
+ if (HasRequiredSfixed32) {
+ output.WriteRawTag(77);
+ output.WriteSFixed32(RequiredSfixed32);
+ }
+ if (HasRequiredSfixed64) {
+ output.WriteRawTag(81);
+ output.WriteSFixed64(RequiredSfixed64);
+ }
+ if (HasRequiredFloat) {
+ output.WriteRawTag(93);
+ output.WriteFloat(RequiredFloat);
+ }
+ if (HasRequiredDouble) {
+ output.WriteRawTag(97);
+ output.WriteDouble(RequiredDouble);
+ }
+ if (HasRequiredBool) {
+ output.WriteRawTag(104);
+ output.WriteBool(RequiredBool);
+ }
+ if (HasRequiredString) {
+ output.WriteRawTag(114);
+ output.WriteString(RequiredString);
+ }
+ if (HasRequiredBytes) {
+ output.WriteRawTag(122);
+ output.WriteBytes(RequiredBytes);
+ }
+ if (requiredNestedMessage_ != null) {
+ output.WriteRawTag(146, 1);
+ output.WriteMessage(RequiredNestedMessage);
+ }
+ if (requiredForeignMessage_ != null) {
+ output.WriteRawTag(154, 1);
+ output.WriteMessage(RequiredForeignMessage);
+ }
+ if (HasRequiredNestedEnum) {
+ output.WriteRawTag(168, 1);
+ output.WriteEnum((int) RequiredNestedEnum);
+ }
+ if (HasRequiredForeignEnum) {
+ output.WriteRawTag(176, 1);
+ output.WriteEnum((int) RequiredForeignEnum);
+ }
+ if (HasRequiredStringPiece) {
+ output.WriteRawTag(194, 1);
+ output.WriteString(RequiredStringPiece);
+ }
+ if (HasRequiredCord) {
+ output.WriteRawTag(202, 1);
+ output.WriteString(RequiredCord);
+ }
+ if (recursiveMessage_ != null) {
+ output.WriteRawTag(218, 1);
+ output.WriteMessage(RecursiveMessage);
+ }
+ if (optionalRecursiveMessage_ != null) {
+ output.WriteRawTag(226, 1);
+ output.WriteMessage(OptionalRecursiveMessage);
+ }
+ if (HasData) {
+ output.WriteRawTag(203, 12);
+ output.WriteGroup(Data);
+ output.WriteRawTag(204, 12);
+ }
+ if (HasDefaultInt32) {
+ output.WriteRawTag(136, 15);
+ output.WriteInt32(DefaultInt32);
+ }
+ if (HasDefaultInt64) {
+ output.WriteRawTag(144, 15);
+ output.WriteInt64(DefaultInt64);
+ }
+ if (HasDefaultUint32) {
+ output.WriteRawTag(152, 15);
+ output.WriteUInt32(DefaultUint32);
+ }
+ if (HasDefaultUint64) {
+ output.WriteRawTag(160, 15);
+ output.WriteUInt64(DefaultUint64);
+ }
+ if (HasDefaultSint32) {
+ output.WriteRawTag(168, 15);
+ output.WriteSInt32(DefaultSint32);
+ }
+ if (HasDefaultSint64) {
+ output.WriteRawTag(176, 15);
+ output.WriteSInt64(DefaultSint64);
+ }
+ if (HasDefaultFixed32) {
+ output.WriteRawTag(189, 15);
+ output.WriteFixed32(DefaultFixed32);
+ }
+ if (HasDefaultFixed64) {
+ output.WriteRawTag(193, 15);
+ output.WriteFixed64(DefaultFixed64);
+ }
+ if (HasDefaultSfixed32) {
+ output.WriteRawTag(205, 15);
+ output.WriteSFixed32(DefaultSfixed32);
+ }
+ if (HasDefaultSfixed64) {
+ output.WriteRawTag(209, 15);
+ output.WriteSFixed64(DefaultSfixed64);
+ }
+ if (HasDefaultFloat) {
+ output.WriteRawTag(221, 15);
+ output.WriteFloat(DefaultFloat);
+ }
+ if (HasDefaultDouble) {
+ output.WriteRawTag(225, 15);
+ output.WriteDouble(DefaultDouble);
+ }
+ if (HasDefaultBool) {
+ output.WriteRawTag(232, 15);
+ output.WriteBool(DefaultBool);
+ }
+ if (HasDefaultString) {
+ output.WriteRawTag(242, 15);
+ output.WriteString(DefaultString);
+ }
+ if (HasDefaultBytes) {
+ output.WriteRawTag(250, 15);
+ output.WriteBytes(DefaultBytes);
+ }
+ if (_extensions != null) {
+ _extensions.WriteTo(output);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (HasRequiredInt32) {
+ output.WriteRawTag(8);
+ output.WriteInt32(RequiredInt32);
+ }
+ if (HasRequiredInt64) {
+ output.WriteRawTag(16);
+ output.WriteInt64(RequiredInt64);
+ }
+ if (HasRequiredUint32) {
+ output.WriteRawTag(24);
+ output.WriteUInt32(RequiredUint32);
+ }
+ if (HasRequiredUint64) {
+ output.WriteRawTag(32);
+ output.WriteUInt64(RequiredUint64);
+ }
+ if (HasRequiredSint32) {
+ output.WriteRawTag(40);
+ output.WriteSInt32(RequiredSint32);
+ }
+ if (HasRequiredSint64) {
+ output.WriteRawTag(48);
+ output.WriteSInt64(RequiredSint64);
+ }
+ if (HasRequiredFixed32) {
+ output.WriteRawTag(61);
+ output.WriteFixed32(RequiredFixed32);
+ }
+ if (HasRequiredFixed64) {
+ output.WriteRawTag(65);
+ output.WriteFixed64(RequiredFixed64);
+ }
+ if (HasRequiredSfixed32) {
+ output.WriteRawTag(77);
+ output.WriteSFixed32(RequiredSfixed32);
+ }
+ if (HasRequiredSfixed64) {
+ output.WriteRawTag(81);
+ output.WriteSFixed64(RequiredSfixed64);
+ }
+ if (HasRequiredFloat) {
+ output.WriteRawTag(93);
+ output.WriteFloat(RequiredFloat);
+ }
+ if (HasRequiredDouble) {
+ output.WriteRawTag(97);
+ output.WriteDouble(RequiredDouble);
+ }
+ if (HasRequiredBool) {
+ output.WriteRawTag(104);
+ output.WriteBool(RequiredBool);
+ }
+ if (HasRequiredString) {
+ output.WriteRawTag(114);
+ output.WriteString(RequiredString);
+ }
+ if (HasRequiredBytes) {
+ output.WriteRawTag(122);
+ output.WriteBytes(RequiredBytes);
+ }
+ if (requiredNestedMessage_ != null) {
+ output.WriteRawTag(146, 1);
+ output.WriteMessage(RequiredNestedMessage);
+ }
+ if (requiredForeignMessage_ != null) {
+ output.WriteRawTag(154, 1);
+ output.WriteMessage(RequiredForeignMessage);
+ }
+ if (HasRequiredNestedEnum) {
+ output.WriteRawTag(168, 1);
+ output.WriteEnum((int) RequiredNestedEnum);
+ }
+ if (HasRequiredForeignEnum) {
+ output.WriteRawTag(176, 1);
+ output.WriteEnum((int) RequiredForeignEnum);
+ }
+ if (HasRequiredStringPiece) {
+ output.WriteRawTag(194, 1);
+ output.WriteString(RequiredStringPiece);
+ }
+ if (HasRequiredCord) {
+ output.WriteRawTag(202, 1);
+ output.WriteString(RequiredCord);
+ }
+ if (recursiveMessage_ != null) {
+ output.WriteRawTag(218, 1);
+ output.WriteMessage(RecursiveMessage);
+ }
+ if (optionalRecursiveMessage_ != null) {
+ output.WriteRawTag(226, 1);
+ output.WriteMessage(OptionalRecursiveMessage);
+ }
+ if (HasData) {
+ output.WriteRawTag(203, 12);
+ output.WriteGroup(Data);
+ output.WriteRawTag(204, 12);
+ }
+ if (HasDefaultInt32) {
+ output.WriteRawTag(136, 15);
+ output.WriteInt32(DefaultInt32);
+ }
+ if (HasDefaultInt64) {
+ output.WriteRawTag(144, 15);
+ output.WriteInt64(DefaultInt64);
+ }
+ if (HasDefaultUint32) {
+ output.WriteRawTag(152, 15);
+ output.WriteUInt32(DefaultUint32);
+ }
+ if (HasDefaultUint64) {
+ output.WriteRawTag(160, 15);
+ output.WriteUInt64(DefaultUint64);
+ }
+ if (HasDefaultSint32) {
+ output.WriteRawTag(168, 15);
+ output.WriteSInt32(DefaultSint32);
+ }
+ if (HasDefaultSint64) {
+ output.WriteRawTag(176, 15);
+ output.WriteSInt64(DefaultSint64);
+ }
+ if (HasDefaultFixed32) {
+ output.WriteRawTag(189, 15);
+ output.WriteFixed32(DefaultFixed32);
+ }
+ if (HasDefaultFixed64) {
+ output.WriteRawTag(193, 15);
+ output.WriteFixed64(DefaultFixed64);
+ }
+ if (HasDefaultSfixed32) {
+ output.WriteRawTag(205, 15);
+ output.WriteSFixed32(DefaultSfixed32);
+ }
+ if (HasDefaultSfixed64) {
+ output.WriteRawTag(209, 15);
+ output.WriteSFixed64(DefaultSfixed64);
+ }
+ if (HasDefaultFloat) {
+ output.WriteRawTag(221, 15);
+ output.WriteFloat(DefaultFloat);
+ }
+ if (HasDefaultDouble) {
+ output.WriteRawTag(225, 15);
+ output.WriteDouble(DefaultDouble);
+ }
+ if (HasDefaultBool) {
+ output.WriteRawTag(232, 15);
+ output.WriteBool(DefaultBool);
+ }
+ if (HasDefaultString) {
+ output.WriteRawTag(242, 15);
+ output.WriteString(DefaultString);
+ }
+ if (HasDefaultBytes) {
+ output.WriteRawTag(250, 15);
+ output.WriteBytes(DefaultBytes);
+ }
+ if (_extensions != null) {
+ _extensions.WriteTo(ref output);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (HasRequiredInt32) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(RequiredInt32);
+ }
+ if (HasRequiredInt64) {
+ size += 1 + pb::CodedOutputStream.ComputeInt64Size(RequiredInt64);
+ }
+ if (HasRequiredUint32) {
+ size += 1 + pb::CodedOutputStream.ComputeUInt32Size(RequiredUint32);
+ }
+ if (HasRequiredUint64) {
+ size += 1 + pb::CodedOutputStream.ComputeUInt64Size(RequiredUint64);
+ }
+ if (HasRequiredSint32) {
+ size += 1 + pb::CodedOutputStream.ComputeSInt32Size(RequiredSint32);
+ }
+ if (HasRequiredSint64) {
+ size += 1 + pb::CodedOutputStream.ComputeSInt64Size(RequiredSint64);
+ }
+ if (HasRequiredFixed32) {
+ size += 1 + 4;
+ }
+ if (HasRequiredFixed64) {
+ size += 1 + 8;
+ }
+ if (HasRequiredSfixed32) {
+ size += 1 + 4;
+ }
+ if (HasRequiredSfixed64) {
+ size += 1 + 8;
+ }
+ if (HasRequiredFloat) {
+ size += 1 + 4;
+ }
+ if (HasRequiredDouble) {
+ size += 1 + 8;
+ }
+ if (HasRequiredBool) {
+ size += 1 + 1;
+ }
+ if (HasRequiredString) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(RequiredString);
+ }
+ if (HasRequiredBytes) {
+ size += 1 + pb::CodedOutputStream.ComputeBytesSize(RequiredBytes);
+ }
+ if (requiredNestedMessage_ != null) {
+ size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequiredNestedMessage);
+ }
+ if (requiredForeignMessage_ != null) {
+ size += 2 + pb::CodedOutputStream.ComputeMessageSize(RequiredForeignMessage);
+ }
+ if (HasRequiredNestedEnum) {
+ size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) RequiredNestedEnum);
+ }
+ if (HasRequiredForeignEnum) {
+ size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) RequiredForeignEnum);
+ }
+ if (HasRequiredStringPiece) {
+ size += 2 + pb::CodedOutputStream.ComputeStringSize(RequiredStringPiece);
+ }
+ if (HasRequiredCord) {
+ size += 2 + pb::CodedOutputStream.ComputeStringSize(RequiredCord);
+ }
+ if (recursiveMessage_ != null) {
+ size += 2 + pb::CodedOutputStream.ComputeMessageSize(RecursiveMessage);
+ }
+ if (optionalRecursiveMessage_ != null) {
+ size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalRecursiveMessage);
+ }
+ if (HasData) {
+ size += 4 + pb::CodedOutputStream.ComputeGroupSize(Data);
+ }
+ if (HasDefaultInt32) {
+ size += 2 + pb::CodedOutputStream.ComputeInt32Size(DefaultInt32);
+ }
+ if (HasDefaultInt64) {
+ size += 2 + pb::CodedOutputStream.ComputeInt64Size(DefaultInt64);
+ }
+ if (HasDefaultUint32) {
+ size += 2 + pb::CodedOutputStream.ComputeUInt32Size(DefaultUint32);
+ }
+ if (HasDefaultUint64) {
+ size += 2 + pb::CodedOutputStream.ComputeUInt64Size(DefaultUint64);
+ }
+ if (HasDefaultSint32) {
+ size += 2 + pb::CodedOutputStream.ComputeSInt32Size(DefaultSint32);
+ }
+ if (HasDefaultSint64) {
+ size += 2 + pb::CodedOutputStream.ComputeSInt64Size(DefaultSint64);
+ }
+ if (HasDefaultFixed32) {
+ size += 2 + 4;
+ }
+ if (HasDefaultFixed64) {
+ size += 2 + 8;
+ }
+ if (HasDefaultSfixed32) {
+ size += 2 + 4;
+ }
+ if (HasDefaultSfixed64) {
+ size += 2 + 8;
+ }
+ if (HasDefaultFloat) {
+ size += 2 + 4;
+ }
+ if (HasDefaultDouble) {
+ size += 2 + 8;
+ }
+ if (HasDefaultBool) {
+ size += 2 + 1;
+ }
+ if (HasDefaultString) {
+ size += 2 + pb::CodedOutputStream.ComputeStringSize(DefaultString);
+ }
+ if (HasDefaultBytes) {
+ size += 2 + pb::CodedOutputStream.ComputeBytesSize(DefaultBytes);
+ }
+ if (_extensions != null) {
+ size += _extensions.CalculateSize();
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(TestAllRequiredTypesProto2 other) {
+ if (other == null) {
+ return;
+ }
+ if (other.HasRequiredInt32) {
+ RequiredInt32 = other.RequiredInt32;
+ }
+ if (other.HasRequiredInt64) {
+ RequiredInt64 = other.RequiredInt64;
+ }
+ if (other.HasRequiredUint32) {
+ RequiredUint32 = other.RequiredUint32;
+ }
+ if (other.HasRequiredUint64) {
+ RequiredUint64 = other.RequiredUint64;
+ }
+ if (other.HasRequiredSint32) {
+ RequiredSint32 = other.RequiredSint32;
+ }
+ if (other.HasRequiredSint64) {
+ RequiredSint64 = other.RequiredSint64;
+ }
+ if (other.HasRequiredFixed32) {
+ RequiredFixed32 = other.RequiredFixed32;
+ }
+ if (other.HasRequiredFixed64) {
+ RequiredFixed64 = other.RequiredFixed64;
+ }
+ if (other.HasRequiredSfixed32) {
+ RequiredSfixed32 = other.RequiredSfixed32;
+ }
+ if (other.HasRequiredSfixed64) {
+ RequiredSfixed64 = other.RequiredSfixed64;
+ }
+ if (other.HasRequiredFloat) {
+ RequiredFloat = other.RequiredFloat;
+ }
+ if (other.HasRequiredDouble) {
+ RequiredDouble = other.RequiredDouble;
+ }
+ if (other.HasRequiredBool) {
+ RequiredBool = other.RequiredBool;
+ }
+ if (other.HasRequiredString) {
+ RequiredString = other.RequiredString;
+ }
+ if (other.HasRequiredBytes) {
+ RequiredBytes = other.RequiredBytes;
+ }
+ if (other.requiredNestedMessage_ != null) {
+ if (requiredNestedMessage_ == null) {
+ RequiredNestedMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedMessage();
+ }
+ RequiredNestedMessage.MergeFrom(other.RequiredNestedMessage);
+ }
+ if (other.requiredForeignMessage_ != null) {
+ if (requiredForeignMessage_ == null) {
+ RequiredForeignMessage = new global::ProtobufTestMessages.Proto2.ForeignMessageProto2();
+ }
+ RequiredForeignMessage.MergeFrom(other.RequiredForeignMessage);
+ }
+ if (other.HasRequiredNestedEnum) {
+ RequiredNestedEnum = other.RequiredNestedEnum;
+ }
+ if (other.HasRequiredForeignEnum) {
+ RequiredForeignEnum = other.RequiredForeignEnum;
+ }
+ if (other.HasRequiredStringPiece) {
+ RequiredStringPiece = other.RequiredStringPiece;
+ }
+ if (other.HasRequiredCord) {
+ RequiredCord = other.RequiredCord;
+ }
+ if (other.recursiveMessage_ != null) {
+ if (recursiveMessage_ == null) {
+ RecursiveMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ RecursiveMessage.MergeFrom(other.RecursiveMessage);
+ }
+ if (other.optionalRecursiveMessage_ != null) {
+ if (optionalRecursiveMessage_ == null) {
+ OptionalRecursiveMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ OptionalRecursiveMessage.MergeFrom(other.OptionalRecursiveMessage);
+ }
+ if (other.HasData) {
+ if (!HasData) {
+ Data = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.Data();
+ }
+ Data.MergeFrom(other.Data);
+ }
+ if (other.HasDefaultInt32) {
+ DefaultInt32 = other.DefaultInt32;
+ }
+ if (other.HasDefaultInt64) {
+ DefaultInt64 = other.DefaultInt64;
+ }
+ if (other.HasDefaultUint32) {
+ DefaultUint32 = other.DefaultUint32;
+ }
+ if (other.HasDefaultUint64) {
+ DefaultUint64 = other.DefaultUint64;
+ }
+ if (other.HasDefaultSint32) {
+ DefaultSint32 = other.DefaultSint32;
+ }
+ if (other.HasDefaultSint64) {
+ DefaultSint64 = other.DefaultSint64;
+ }
+ if (other.HasDefaultFixed32) {
+ DefaultFixed32 = other.DefaultFixed32;
+ }
+ if (other.HasDefaultFixed64) {
+ DefaultFixed64 = other.DefaultFixed64;
+ }
+ if (other.HasDefaultSfixed32) {
+ DefaultSfixed32 = other.DefaultSfixed32;
+ }
+ if (other.HasDefaultSfixed64) {
+ DefaultSfixed64 = other.DefaultSfixed64;
+ }
+ if (other.HasDefaultFloat) {
+ DefaultFloat = other.DefaultFloat;
+ }
+ if (other.HasDefaultDouble) {
+ DefaultDouble = other.DefaultDouble;
+ }
+ if (other.HasDefaultBool) {
+ DefaultBool = other.DefaultBool;
+ }
+ if (other.HasDefaultString) {
+ DefaultString = other.DefaultString;
+ }
+ if (other.HasDefaultBytes) {
+ DefaultBytes = other.DefaultBytes;
+ }
+ pb::ExtensionSet.MergeFrom(ref _extensions, other._extensions);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ if (!pb::ExtensionSet.TryMergeFieldFrom(ref _extensions, input)) {
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ }
+ break;
+ case 8: {
+ RequiredInt32 = input.ReadInt32();
+ break;
+ }
+ case 16: {
+ RequiredInt64 = input.ReadInt64();
+ break;
+ }
+ case 24: {
+ RequiredUint32 = input.ReadUInt32();
+ break;
+ }
+ case 32: {
+ RequiredUint64 = input.ReadUInt64();
+ break;
+ }
+ case 40: {
+ RequiredSint32 = input.ReadSInt32();
+ break;
+ }
+ case 48: {
+ RequiredSint64 = input.ReadSInt64();
+ break;
+ }
+ case 61: {
+ RequiredFixed32 = input.ReadFixed32();
+ break;
+ }
+ case 65: {
+ RequiredFixed64 = input.ReadFixed64();
+ break;
+ }
+ case 77: {
+ RequiredSfixed32 = input.ReadSFixed32();
+ break;
+ }
+ case 81: {
+ RequiredSfixed64 = input.ReadSFixed64();
+ break;
+ }
+ case 93: {
+ RequiredFloat = input.ReadFloat();
+ break;
+ }
+ case 97: {
+ RequiredDouble = input.ReadDouble();
+ break;
+ }
+ case 104: {
+ RequiredBool = input.ReadBool();
+ break;
+ }
+ case 114: {
+ RequiredString = input.ReadString();
+ break;
+ }
+ case 122: {
+ RequiredBytes = input.ReadBytes();
+ break;
+ }
+ case 146: {
+ if (requiredNestedMessage_ == null) {
+ RequiredNestedMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedMessage();
+ }
+ input.ReadMessage(RequiredNestedMessage);
+ break;
+ }
+ case 154: {
+ if (requiredForeignMessage_ == null) {
+ RequiredForeignMessage = new global::ProtobufTestMessages.Proto2.ForeignMessageProto2();
+ }
+ input.ReadMessage(RequiredForeignMessage);
+ break;
+ }
+ case 168: {
+ RequiredNestedEnum = (global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedEnum) input.ReadEnum();
+ break;
+ }
+ case 176: {
+ RequiredForeignEnum = (global::ProtobufTestMessages.Proto2.ForeignEnumProto2) input.ReadEnum();
+ break;
+ }
+ case 194: {
+ RequiredStringPiece = input.ReadString();
+ break;
+ }
+ case 202: {
+ RequiredCord = input.ReadString();
+ break;
+ }
+ case 218: {
+ if (recursiveMessage_ == null) {
+ RecursiveMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(RecursiveMessage);
+ break;
+ }
+ case 226: {
+ if (optionalRecursiveMessage_ == null) {
+ OptionalRecursiveMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(OptionalRecursiveMessage);
+ break;
+ }
+ case 1611: {
+ if (!HasData) {
+ Data = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.Data();
+ }
+ input.ReadGroup(Data);
+ break;
+ }
+ case 1928: {
+ DefaultInt32 = input.ReadInt32();
+ break;
+ }
+ case 1936: {
+ DefaultInt64 = input.ReadInt64();
+ break;
+ }
+ case 1944: {
+ DefaultUint32 = input.ReadUInt32();
+ break;
+ }
+ case 1952: {
+ DefaultUint64 = input.ReadUInt64();
+ break;
+ }
+ case 1960: {
+ DefaultSint32 = input.ReadSInt32();
+ break;
+ }
+ case 1968: {
+ DefaultSint64 = input.ReadSInt64();
+ break;
+ }
+ case 1981: {
+ DefaultFixed32 = input.ReadFixed32();
+ break;
+ }
+ case 1985: {
+ DefaultFixed64 = input.ReadFixed64();
+ break;
+ }
+ case 1997: {
+ DefaultSfixed32 = input.ReadSFixed32();
+ break;
+ }
+ case 2001: {
+ DefaultSfixed64 = input.ReadSFixed64();
+ break;
+ }
+ case 2013: {
+ DefaultFloat = input.ReadFloat();
+ break;
+ }
+ case 2017: {
+ DefaultDouble = input.ReadDouble();
+ break;
+ }
+ case 2024: {
+ DefaultBool = input.ReadBool();
+ break;
+ }
+ case 2034: {
+ DefaultString = input.ReadString();
+ break;
+ }
+ case 2042: {
+ DefaultBytes = input.ReadBytes();
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ if (!pb::ExtensionSet.TryMergeFieldFrom(ref _extensions, ref input)) {
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ }
+ break;
+ case 8: {
+ RequiredInt32 = input.ReadInt32();
+ break;
+ }
+ case 16: {
+ RequiredInt64 = input.ReadInt64();
+ break;
+ }
+ case 24: {
+ RequiredUint32 = input.ReadUInt32();
+ break;
+ }
+ case 32: {
+ RequiredUint64 = input.ReadUInt64();
+ break;
+ }
+ case 40: {
+ RequiredSint32 = input.ReadSInt32();
+ break;
+ }
+ case 48: {
+ RequiredSint64 = input.ReadSInt64();
+ break;
+ }
+ case 61: {
+ RequiredFixed32 = input.ReadFixed32();
+ break;
+ }
+ case 65: {
+ RequiredFixed64 = input.ReadFixed64();
+ break;
+ }
+ case 77: {
+ RequiredSfixed32 = input.ReadSFixed32();
+ break;
+ }
+ case 81: {
+ RequiredSfixed64 = input.ReadSFixed64();
+ break;
+ }
+ case 93: {
+ RequiredFloat = input.ReadFloat();
+ break;
+ }
+ case 97: {
+ RequiredDouble = input.ReadDouble();
+ break;
+ }
+ case 104: {
+ RequiredBool = input.ReadBool();
+ break;
+ }
+ case 114: {
+ RequiredString = input.ReadString();
+ break;
+ }
+ case 122: {
+ RequiredBytes = input.ReadBytes();
+ break;
+ }
+ case 146: {
+ if (requiredNestedMessage_ == null) {
+ RequiredNestedMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedMessage();
+ }
+ input.ReadMessage(RequiredNestedMessage);
+ break;
+ }
+ case 154: {
+ if (requiredForeignMessage_ == null) {
+ RequiredForeignMessage = new global::ProtobufTestMessages.Proto2.ForeignMessageProto2();
+ }
+ input.ReadMessage(RequiredForeignMessage);
+ break;
+ }
+ case 168: {
+ RequiredNestedEnum = (global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.NestedEnum) input.ReadEnum();
+ break;
+ }
+ case 176: {
+ RequiredForeignEnum = (global::ProtobufTestMessages.Proto2.ForeignEnumProto2) input.ReadEnum();
+ break;
+ }
+ case 194: {
+ RequiredStringPiece = input.ReadString();
+ break;
+ }
+ case 202: {
+ RequiredCord = input.ReadString();
+ break;
+ }
+ case 218: {
+ if (recursiveMessage_ == null) {
+ RecursiveMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(RecursiveMessage);
+ break;
+ }
+ case 226: {
+ if (optionalRecursiveMessage_ == null) {
+ OptionalRecursiveMessage = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(OptionalRecursiveMessage);
+ break;
+ }
+ case 1611: {
+ if (!HasData) {
+ Data = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.Data();
+ }
+ input.ReadGroup(Data);
+ break;
+ }
+ case 1928: {
+ DefaultInt32 = input.ReadInt32();
+ break;
+ }
+ case 1936: {
+ DefaultInt64 = input.ReadInt64();
+ break;
+ }
+ case 1944: {
+ DefaultUint32 = input.ReadUInt32();
+ break;
+ }
+ case 1952: {
+ DefaultUint64 = input.ReadUInt64();
+ break;
+ }
+ case 1960: {
+ DefaultSint32 = input.ReadSInt32();
+ break;
+ }
+ case 1968: {
+ DefaultSint64 = input.ReadSInt64();
+ break;
+ }
+ case 1981: {
+ DefaultFixed32 = input.ReadFixed32();
+ break;
+ }
+ case 1985: {
+ DefaultFixed64 = input.ReadFixed64();
+ break;
+ }
+ case 1997: {
+ DefaultSfixed32 = input.ReadSFixed32();
+ break;
+ }
+ case 2001: {
+ DefaultSfixed64 = input.ReadSFixed64();
+ break;
+ }
+ case 2013: {
+ DefaultFloat = input.ReadFloat();
+ break;
+ }
+ case 2017: {
+ DefaultDouble = input.ReadDouble();
+ break;
+ }
+ case 2024: {
+ DefaultBool = input.ReadBool();
+ break;
+ }
+ case 2034: {
+ DefaultString = input.ReadString();
+ break;
+ }
+ case 2042: {
+ DefaultBytes = input.ReadBytes();
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ public TValue GetExtension<TValue>(pb::Extension<TestAllRequiredTypesProto2, TValue> extension) {
+ return pb::ExtensionSet.Get(ref _extensions, extension);
+ }
+ public pbc::RepeatedField<TValue> GetExtension<TValue>(pb::RepeatedExtension<TestAllRequiredTypesProto2, TValue> extension) {
+ return pb::ExtensionSet.Get(ref _extensions, extension);
+ }
+ public pbc::RepeatedField<TValue> GetOrInitializeExtension<TValue>(pb::RepeatedExtension<TestAllRequiredTypesProto2, TValue> extension) {
+ return pb::ExtensionSet.GetOrInitialize(ref _extensions, extension);
+ }
+ public void SetExtension<TValue>(pb::Extension<TestAllRequiredTypesProto2, TValue> extension, TValue value) {
+ pb::ExtensionSet.Set(ref _extensions, extension, value);
+ }
+ public bool HasExtension<TValue>(pb::Extension<TestAllRequiredTypesProto2, TValue> extension) {
+ return pb::ExtensionSet.Has(ref _extensions, extension);
+ }
+ public void ClearExtension<TValue>(pb::Extension<TestAllRequiredTypesProto2, TValue> extension) {
+ pb::ExtensionSet.Clear(ref _extensions, extension);
+ }
+ public void ClearExtension<TValue>(pb::RepeatedExtension<TestAllRequiredTypesProto2, TValue> extension) {
+ pb::ExtensionSet.Clear(ref _extensions, extension);
+ }
+
+ #region Nested types
+ /// <summary>Container for nested types declared in the TestAllRequiredTypesProto2 message type.</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static partial class Types {
+ public enum NestedEnum {
+ [pbr::OriginalName("FOO")] Foo = 0,
+ [pbr::OriginalName("BAR")] Bar = 1,
+ [pbr::OriginalName("BAZ")] Baz = 2,
+ /// <summary>
+ /// Intentionally negative.
+ /// </summary>
+ [pbr::OriginalName("NEG")] Neg = -1,
+ }
+
+ public sealed partial class NestedMessage : pb::IMessage<NestedMessage>
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser<NestedMessage> _parser = new pb::MessageParser<NestedMessage>(() => new NestedMessage());
+ private pb::UnknownFieldSet _unknownFields;
+ private int _hasBits0;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser<NestedMessage> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Descriptor.NestedTypes[0]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public NestedMessage() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public NestedMessage(NestedMessage other) : this() {
+ _hasBits0 = other._hasBits0;
+ a_ = other.a_;
+ corecursive_ = other.corecursive_ != null ? other.corecursive_.Clone() : null;
+ optionalCorecursive_ = other.optionalCorecursive_ != null ? other.optionalCorecursive_.Clone() : null;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public NestedMessage Clone() {
+ return new NestedMessage(this);
+ }
+
+ /// <summary>Field number for the "a" field.</summary>
+ public const int AFieldNumber = 1;
+ private readonly static int ADefaultValue = 0;
+
+ private int a_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int A {
+ get { if ((_hasBits0 & 1) != 0) { return a_; } else { return ADefaultValue; } }
+ set {
+ _hasBits0 |= 1;
+ a_ = value;
+ }
+ }
+ /// <summary>Gets whether the "a" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasA {
+ get { return (_hasBits0 & 1) != 0; }
+ }
+ /// <summary>Clears the value of the "a" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearA() {
+ _hasBits0 &= ~1;
+ }
+
+ /// <summary>Field number for the "corecursive" field.</summary>
+ public const int CorecursiveFieldNumber = 2;
+ private global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 corecursive_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 Corecursive {
+ get { return corecursive_; }
+ set {
+ corecursive_ = value;
+ }
+ }
+
+ /// <summary>Field number for the "optional_corecursive" field.</summary>
+ public const int OptionalCorecursiveFieldNumber = 3;
+ private global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 optionalCorecursive_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2 OptionalCorecursive {
+ get { return optionalCorecursive_; }
+ set {
+ optionalCorecursive_ = value;
+ }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as NestedMessage);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(NestedMessage other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (A != other.A) return false;
+ if (!object.Equals(Corecursive, other.Corecursive)) return false;
+ if (!object.Equals(OptionalCorecursive, other.OptionalCorecursive)) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (HasA) hash ^= A.GetHashCode();
+ if (corecursive_ != null) hash ^= Corecursive.GetHashCode();
+ if (optionalCorecursive_ != null) hash ^= OptionalCorecursive.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (HasA) {
+ output.WriteRawTag(8);
+ output.WriteInt32(A);
+ }
+ if (corecursive_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Corecursive);
+ }
+ if (optionalCorecursive_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(OptionalCorecursive);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (HasA) {
+ output.WriteRawTag(8);
+ output.WriteInt32(A);
+ }
+ if (corecursive_ != null) {
+ output.WriteRawTag(18);
+ output.WriteMessage(Corecursive);
+ }
+ if (optionalCorecursive_ != null) {
+ output.WriteRawTag(26);
+ output.WriteMessage(OptionalCorecursive);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (HasA) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(A);
+ }
+ if (corecursive_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(Corecursive);
+ }
+ if (optionalCorecursive_ != null) {
+ size += 1 + pb::CodedOutputStream.ComputeMessageSize(OptionalCorecursive);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(NestedMessage other) {
+ if (other == null) {
+ return;
+ }
+ if (other.HasA) {
+ A = other.A;
+ }
+ if (other.corecursive_ != null) {
+ if (corecursive_ == null) {
+ Corecursive = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ Corecursive.MergeFrom(other.Corecursive);
+ }
+ if (other.optionalCorecursive_ != null) {
+ if (optionalCorecursive_ == null) {
+ OptionalCorecursive = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ OptionalCorecursive.MergeFrom(other.OptionalCorecursive);
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 8: {
+ A = input.ReadInt32();
+ break;
+ }
+ case 18: {
+ if (corecursive_ == null) {
+ Corecursive = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(Corecursive);
+ break;
+ }
+ case 26: {
+ if (optionalCorecursive_ == null) {
+ OptionalCorecursive = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(OptionalCorecursive);
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 8: {
+ A = input.ReadInt32();
+ break;
+ }
+ case 18: {
+ if (corecursive_ == null) {
+ Corecursive = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(Corecursive);
+ break;
+ }
+ case 26: {
+ if (optionalCorecursive_ == null) {
+ OptionalCorecursive = new global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2();
+ }
+ input.ReadMessage(OptionalCorecursive);
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ }
+
+ /// <summary>
+ /// groups
+ /// </summary>
+ public sealed partial class Data : pb::IMessage<Data>
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser<Data> _parser = new pb::MessageParser<Data>(() => new Data());
+ private pb::UnknownFieldSet _unknownFields;
+ private int _hasBits0;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser<Data> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Descriptor.NestedTypes[1]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public Data() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public Data(Data other) : this() {
+ _hasBits0 = other._hasBits0;
+ groupInt32_ = other.groupInt32_;
+ groupUint32_ = other.groupUint32_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public Data Clone() {
+ return new Data(this);
+ }
+
+ /// <summary>Field number for the "group_int32" field.</summary>
+ public const int GroupInt32FieldNumber = 202;
+ private readonly static int GroupInt32DefaultValue = 0;
+
+ private int groupInt32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int GroupInt32 {
+ get { if ((_hasBits0 & 1) != 0) { return groupInt32_; } else { return GroupInt32DefaultValue; } }
+ set {
+ _hasBits0 |= 1;
+ groupInt32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "group_int32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasGroupInt32 {
+ get { return (_hasBits0 & 1) != 0; }
+ }
+ /// <summary>Clears the value of the "group_int32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearGroupInt32() {
+ _hasBits0 &= ~1;
+ }
+
+ /// <summary>Field number for the "group_uint32" field.</summary>
+ public const int GroupUint32FieldNumber = 203;
+ private readonly static uint GroupUint32DefaultValue = 0;
+
+ private uint groupUint32_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public uint GroupUint32 {
+ get { if ((_hasBits0 & 2) != 0) { return groupUint32_; } else { return GroupUint32DefaultValue; } }
+ set {
+ _hasBits0 |= 2;
+ groupUint32_ = value;
+ }
+ }
+ /// <summary>Gets whether the "group_uint32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasGroupUint32 {
+ get { return (_hasBits0 & 2) != 0; }
+ }
+ /// <summary>Clears the value of the "group_uint32" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearGroupUint32() {
+ _hasBits0 &= ~2;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as Data);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(Data other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (GroupInt32 != other.GroupInt32) return false;
+ if (GroupUint32 != other.GroupUint32) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (HasGroupInt32) hash ^= GroupInt32.GetHashCode();
+ if (HasGroupUint32) hash ^= GroupUint32.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (HasGroupInt32) {
+ output.WriteRawTag(208, 12);
+ output.WriteInt32(GroupInt32);
+ }
+ if (HasGroupUint32) {
+ output.WriteRawTag(216, 12);
+ output.WriteUInt32(GroupUint32);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (HasGroupInt32) {
+ output.WriteRawTag(208, 12);
+ output.WriteInt32(GroupInt32);
+ }
+ if (HasGroupUint32) {
+ output.WriteRawTag(216, 12);
+ output.WriteUInt32(GroupUint32);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (HasGroupInt32) {
+ size += 2 + pb::CodedOutputStream.ComputeInt32Size(GroupInt32);
+ }
+ if (HasGroupUint32) {
+ size += 2 + pb::CodedOutputStream.ComputeUInt32Size(GroupUint32);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(Data other) {
+ if (other == null) {
+ return;
+ }
+ if (other.HasGroupInt32) {
+ GroupInt32 = other.GroupInt32;
+ }
+ if (other.HasGroupUint32) {
+ GroupUint32 = other.GroupUint32;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ case 1612:
+ return;
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 1616: {
+ GroupInt32 = input.ReadInt32();
+ break;
+ }
+ case 1624: {
+ GroupUint32 = input.ReadUInt32();
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ case 1612:
+ return;
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 1616: {
+ GroupInt32 = input.ReadInt32();
+ break;
+ }
+ case 1624: {
+ GroupUint32 = input.ReadUInt32();
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ }
+
+ /// <summary>
+ /// message_set test case.
+ /// </summary>
+ public sealed partial class MessageSetCorrect : pb::IExtendableMessage<MessageSetCorrect>
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser<MessageSetCorrect> _parser = new pb::MessageParser<MessageSetCorrect>(() => new MessageSetCorrect());
+ private pb::UnknownFieldSet _unknownFields;
+ private pb::ExtensionSet<MessageSetCorrect> _extensions;
+ private pb::ExtensionSet<MessageSetCorrect> _Extensions { get { return _extensions; } }
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser<MessageSetCorrect> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Descriptor.NestedTypes[2]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrect() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrect(MessageSetCorrect other) : this() {
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ _extensions = pb::ExtensionSet.Clone(other._extensions);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrect Clone() {
+ return new MessageSetCorrect(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as MessageSetCorrect);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(MessageSetCorrect other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (!Equals(_extensions, other._extensions)) {
+ return false;
+ }
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (_extensions != null) {
+ hash ^= _extensions.GetHashCode();
+ }
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (_extensions != null) {
+ _extensions.WriteTo(output);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (_extensions != null) {
+ _extensions.WriteTo(ref output);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (_extensions != null) {
+ size += _extensions.CalculateSize();
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(MessageSetCorrect other) {
+ if (other == null) {
+ return;
+ }
+ pb::ExtensionSet.MergeFrom(ref _extensions, other._extensions);
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ if (!pb::ExtensionSet.TryMergeFieldFrom(ref _extensions, input)) {
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ }
+ break;
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ if (!pb::ExtensionSet.TryMergeFieldFrom(ref _extensions, ref input)) {
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ }
+ break;
+ }
+ }
+ }
+ #endif
+
+ public TValue GetExtension<TValue>(pb::Extension<MessageSetCorrect, TValue> extension) {
+ return pb::ExtensionSet.Get(ref _extensions, extension);
+ }
+ public pbc::RepeatedField<TValue> GetExtension<TValue>(pb::RepeatedExtension<MessageSetCorrect, TValue> extension) {
+ return pb::ExtensionSet.Get(ref _extensions, extension);
+ }
+ public pbc::RepeatedField<TValue> GetOrInitializeExtension<TValue>(pb::RepeatedExtension<MessageSetCorrect, TValue> extension) {
+ return pb::ExtensionSet.GetOrInitialize(ref _extensions, extension);
+ }
+ public void SetExtension<TValue>(pb::Extension<MessageSetCorrect, TValue> extension, TValue value) {
+ pb::ExtensionSet.Set(ref _extensions, extension, value);
+ }
+ public bool HasExtension<TValue>(pb::Extension<MessageSetCorrect, TValue> extension) {
+ return pb::ExtensionSet.Has(ref _extensions, extension);
+ }
+ public void ClearExtension<TValue>(pb::Extension<MessageSetCorrect, TValue> extension) {
+ pb::ExtensionSet.Clear(ref _extensions, extension);
+ }
+ public void ClearExtension<TValue>(pb::RepeatedExtension<MessageSetCorrect, TValue> extension) {
+ pb::ExtensionSet.Clear(ref _extensions, extension);
+ }
+
+ }
+
+ public sealed partial class MessageSetCorrectExtension1 : pb::IMessage<MessageSetCorrectExtension1>
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser<MessageSetCorrectExtension1> _parser = new pb::MessageParser<MessageSetCorrectExtension1>(() => new MessageSetCorrectExtension1());
+ private pb::UnknownFieldSet _unknownFields;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser<MessageSetCorrectExtension1> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Descriptor.NestedTypes[3]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrectExtension1() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrectExtension1(MessageSetCorrectExtension1 other) : this() {
+ str_ = other.str_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrectExtension1 Clone() {
+ return new MessageSetCorrectExtension1(this);
+ }
+
+ /// <summary>Field number for the "str" field.</summary>
+ public const int StrFieldNumber = 25;
+ private readonly static string StrDefaultValue = "";
+
+ private string str_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string Str {
+ get { return str_ ?? StrDefaultValue; }
+ set {
+ str_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+ /// <summary>Gets whether the "str" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasStr {
+ get { return str_ != null; }
+ }
+ /// <summary>Clears the value of the "str" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearStr() {
+ str_ = null;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as MessageSetCorrectExtension1);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(MessageSetCorrectExtension1 other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (Str != other.Str) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (HasStr) hash ^= Str.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (HasStr) {
+ output.WriteRawTag(202, 1);
+ output.WriteString(Str);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (HasStr) {
+ output.WriteRawTag(202, 1);
+ output.WriteString(Str);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (HasStr) {
+ size += 2 + pb::CodedOutputStream.ComputeStringSize(Str);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(MessageSetCorrectExtension1 other) {
+ if (other == null) {
+ return;
+ }
+ if (other.HasStr) {
+ Str = other.Str;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 202: {
+ Str = input.ReadString();
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 202: {
+ Str = input.ReadString();
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ #region Extensions
+ /// <summary>Container for extensions for other messages declared in the MessageSetCorrectExtension1 message type.</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static partial class Extensions {
+ public static readonly pb::Extension<global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrect, global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension1> MessageSetExtension =
+ new pb::Extension<global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrect, global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension1>(1547769, pb::FieldCodec.ForMessage(12382154, global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension1.Parser));
+ }
+ #endregion
+
+ }
+
+ public sealed partial class MessageSetCorrectExtension2 : pb::IMessage<MessageSetCorrectExtension2>
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ , pb::IBufferMessage
+ #endif
+ {
+ private static readonly pb::MessageParser<MessageSetCorrectExtension2> _parser = new pb::MessageParser<MessageSetCorrectExtension2>(() => new MessageSetCorrectExtension2());
+ private pb::UnknownFieldSet _unknownFields;
+ private int _hasBits0;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pb::MessageParser<MessageSetCorrectExtension2> Parser { get { return _parser; } }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static pbr::MessageDescriptor Descriptor {
+ get { return global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Descriptor.NestedTypes[4]; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ pbr::MessageDescriptor pb::IMessage.Descriptor {
+ get { return Descriptor; }
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrectExtension2() {
+ OnConstruction();
+ }
+
+ partial void OnConstruction();
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrectExtension2(MessageSetCorrectExtension2 other) : this() {
+ _hasBits0 = other._hasBits0;
+ i_ = other.i_;
+ _unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public MessageSetCorrectExtension2 Clone() {
+ return new MessageSetCorrectExtension2(this);
+ }
+
+ /// <summary>Field number for the "i" field.</summary>
+ public const int IFieldNumber = 9;
+ private readonly static int IDefaultValue = 0;
+
+ private int i_;
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int I {
+ get { if ((_hasBits0 & 1) != 0) { return i_; } else { return IDefaultValue; } }
+ set {
+ _hasBits0 |= 1;
+ i_ = value;
+ }
+ }
+ /// <summary>Gets whether the "i" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasI {
+ get { return (_hasBits0 & 1) != 0; }
+ }
+ /// <summary>Clears the value of the "i" field</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearI() {
+ _hasBits0 &= ~1;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override bool Equals(object other) {
+ return Equals(other as MessageSetCorrectExtension2);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool Equals(MessageSetCorrectExtension2 other) {
+ if (ReferenceEquals(other, null)) {
+ return false;
+ }
+ if (ReferenceEquals(other, this)) {
+ return true;
+ }
+ if (I != other.I) return false;
+ return Equals(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override int GetHashCode() {
+ int hash = 1;
+ if (HasI) hash ^= I.GetHashCode();
+ if (_unknownFields != null) {
+ hash ^= _unknownFields.GetHashCode();
+ }
+ return hash;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public override string ToString() {
+ return pb::JsonFormatter.ToDiagnosticString(this);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void WriteTo(pb::CodedOutputStream output) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ output.WriteRawMessage(this);
+ #else
+ if (HasI) {
+ output.WriteRawTag(72);
+ output.WriteInt32(I);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(output);
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
+ if (HasI) {
+ output.WriteRawTag(72);
+ output.WriteInt32(I);
+ }
+ if (_unknownFields != null) {
+ _unknownFields.WriteTo(ref output);
+ }
+ }
+ #endif
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public int CalculateSize() {
+ int size = 0;
+ if (HasI) {
+ size += 1 + pb::CodedOutputStream.ComputeInt32Size(I);
+ }
+ if (_unknownFields != null) {
+ size += _unknownFields.CalculateSize();
+ }
+ return size;
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(MessageSetCorrectExtension2 other) {
+ if (other == null) {
+ return;
+ }
+ if (other.HasI) {
+ I = other.I;
+ }
+ _unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+ }
+
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void MergeFrom(pb::CodedInputStream input) {
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ input.ReadRawMessage(this);
+ #else
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+ break;
+ case 72: {
+ I = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ #endif
+ }
+
+ #if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
+ uint tag;
+ while ((tag = input.ReadTag()) != 0) {
+ switch(tag) {
+ default:
+ _unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
+ break;
+ case 72: {
+ I = input.ReadInt32();
+ break;
+ }
+ }
+ }
+ }
+ #endif
+
+ #region Extensions
+ /// <summary>Container for extensions for other messages declared in the MessageSetCorrectExtension2 message type.</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public static partial class Extensions {
+ public static readonly pb::Extension<global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrect, global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension2> MessageSetExtension =
+ new pb::Extension<global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrect, global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension2>(4135312, pb::FieldCodec.ForMessage(33082498, global::ProtobufTestMessages.Proto2.TestAllRequiredTypesProto2.Types.MessageSetCorrectExtension2.Parser));
+ }
+ #endregion
+
+ }
+
+ }
+ #endregion
+
+ }
+
#endregion
}
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.pb.cs b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.pb.cs
index 74e2a57..47bb7d0 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.pb.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/TestMessagesProto3.pb.cs
@@ -1526,12 +1526,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint OneofUint32 {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32 ? (uint) oneofField_ : 0; }
+ get { return HasOneofUint32 ? (uint) oneofField_ : 0; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofUint32;
}
}
+ /// <summary>Gets whether the "oneof_uint32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofUint32 {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_uint32" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofUint32() {
+ if (HasOneofUint32) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_nested_message" field.</summary>
public const int OneofNestedMessageFieldNumber = 112;
@@ -1550,96 +1564,208 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string OneofString {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
+ get { return HasOneofString ? (string) oneofField_ : ""; }
set {
oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
oneofFieldCase_ = OneofFieldOneofCase.OneofString;
}
}
+ /// <summary>Gets whether the "oneof_string" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofString {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_string" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofString() {
+ if (HasOneofString) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_bytes" field.</summary>
public const int OneofBytesFieldNumber = 114;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pb::ByteString OneofBytes {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
+ get { return HasOneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
set {
oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
}
}
+ /// <summary>Gets whether the "oneof_bytes" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofBytes {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_bytes" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofBytes() {
+ if (HasOneofBytes) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_bool" field.</summary>
public const int OneofBoolFieldNumber = 115;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool OneofBool {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBool ? (bool) oneofField_ : false; }
+ get { return HasOneofBool ? (bool) oneofField_ : false; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofBool;
}
}
+ /// <summary>Gets whether the "oneof_bool" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofBool {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBool; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_bool" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofBool() {
+ if (HasOneofBool) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_uint64" field.</summary>
public const int OneofUint64FieldNumber = 116;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public ulong OneofUint64 {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint64 ? (ulong) oneofField_ : 0UL; }
+ get { return HasOneofUint64 ? (ulong) oneofField_ : 0UL; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofUint64;
}
}
+ /// <summary>Gets whether the "oneof_uint64" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofUint64 {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint64; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_uint64" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofUint64() {
+ if (HasOneofUint64) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_float" field.</summary>
public const int OneofFloatFieldNumber = 117;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public float OneofFloat {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofFloat ? (float) oneofField_ : 0F; }
+ get { return HasOneofFloat ? (float) oneofField_ : 0F; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofFloat;
}
}
+ /// <summary>Gets whether the "oneof_float" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofFloat {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofFloat; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_float" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofFloat() {
+ if (HasOneofFloat) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_double" field.</summary>
public const int OneofDoubleFieldNumber = 118;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public double OneofDouble {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofDouble ? (double) oneofField_ : 0D; }
+ get { return HasOneofDouble ? (double) oneofField_ : 0D; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofDouble;
}
}
+ /// <summary>Gets whether the "oneof_double" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofDouble {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofDouble; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_double" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofDouble() {
+ if (HasOneofDouble) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_enum" field.</summary>
public const int OneofEnumFieldNumber = 119;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedEnum OneofEnum {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofEnum ? (global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedEnum) oneofField_ : global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedEnum.Foo; }
+ get { return HasOneofEnum ? (global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedEnum) oneofField_ : global::ProtobufTestMessages.Proto3.TestAllTypesProto3.Types.NestedEnum.Foo; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofEnum;
}
}
+ /// <summary>Gets whether the "oneof_enum" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofEnum {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofEnum; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_enum" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofEnum() {
+ if (HasOneofEnum) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_null_value" field.</summary>
public const int OneofNullValueFieldNumber = 120;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Google.Protobuf.WellKnownTypes.NullValue OneofNullValue {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofNullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) oneofField_ : global::Google.Protobuf.WellKnownTypes.NullValue.NullValue; }
+ get { return HasOneofNullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) oneofField_ : global::Google.Protobuf.WellKnownTypes.NullValue.NullValue; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofNullValue;
}
}
+ /// <summary>Gets whether the "oneof_null_value" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofNullValue {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofNullValue; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_null_value" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofNullValue() {
+ if (HasOneofNullValue) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "optional_bool_wrapper" field.</summary>
public const int OptionalBoolWrapperFieldNumber = 201;
@@ -2544,16 +2670,16 @@
hash ^= MapStringForeignMessage.GetHashCode();
hash ^= MapStringNestedEnum.GetHashCode();
hash ^= MapStringForeignEnum.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) hash ^= OneofUint32.GetHashCode();
+ if (HasOneofUint32) hash ^= OneofUint32.GetHashCode();
if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) hash ^= OneofNestedMessage.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) hash ^= OneofString.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) hash ^= OneofBytes.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBool) hash ^= OneofBool.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint64) hash ^= OneofUint64.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofFloat) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(OneofFloat);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofDouble) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(OneofDouble);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofEnum) hash ^= OneofEnum.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofNullValue) hash ^= OneofNullValue.GetHashCode();
+ if (HasOneofString) hash ^= OneofString.GetHashCode();
+ if (HasOneofBytes) hash ^= OneofBytes.GetHashCode();
+ if (HasOneofBool) hash ^= OneofBool.GetHashCode();
+ if (HasOneofUint64) hash ^= OneofUint64.GetHashCode();
+ if (HasOneofFloat) hash ^= pbc::ProtobufEqualityComparers.BitwiseSingleEqualityComparer.GetHashCode(OneofFloat);
+ if (HasOneofDouble) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(OneofDouble);
+ if (HasOneofEnum) hash ^= OneofEnum.GetHashCode();
+ if (HasOneofNullValue) hash ^= OneofNullValue.GetHashCode();
if (optionalBoolWrapper_ != null) hash ^= OptionalBoolWrapper.GetHashCode();
if (optionalInt32Wrapper_ != null) hash ^= OptionalInt32Wrapper.GetHashCode();
if (optionalInt64Wrapper_ != null) hash ^= OptionalInt64Wrapper.GetHashCode();
@@ -2783,7 +2909,7 @@
unpackedDouble_.WriteTo(output, _repeated_unpackedDouble_codec);
unpackedBool_.WriteTo(output, _repeated_unpackedBool_codec);
unpackedNestedEnum_.WriteTo(output, _repeated_unpackedNestedEnum_codec);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+ if (HasOneofUint32) {
output.WriteRawTag(248, 6);
output.WriteUInt32(OneofUint32);
}
@@ -2791,35 +2917,35 @@
output.WriteRawTag(130, 7);
output.WriteMessage(OneofNestedMessage);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+ if (HasOneofString) {
output.WriteRawTag(138, 7);
output.WriteString(OneofString);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+ if (HasOneofBytes) {
output.WriteRawTag(146, 7);
output.WriteBytes(OneofBytes);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBool) {
+ if (HasOneofBool) {
output.WriteRawTag(152, 7);
output.WriteBool(OneofBool);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint64) {
+ if (HasOneofUint64) {
output.WriteRawTag(160, 7);
output.WriteUInt64(OneofUint64);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofFloat) {
+ if (HasOneofFloat) {
output.WriteRawTag(173, 7);
output.WriteFloat(OneofFloat);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofDouble) {
+ if (HasOneofDouble) {
output.WriteRawTag(177, 7);
output.WriteDouble(OneofDouble);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofEnum) {
+ if (HasOneofEnum) {
output.WriteRawTag(184, 7);
output.WriteEnum((int) OneofEnum);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofNullValue) {
+ if (HasOneofNullValue) {
output.WriteRawTag(192, 7);
output.WriteEnum((int) OneofNullValue);
}
@@ -3136,7 +3262,7 @@
unpackedDouble_.WriteTo(ref output, _repeated_unpackedDouble_codec);
unpackedBool_.WriteTo(ref output, _repeated_unpackedBool_codec);
unpackedNestedEnum_.WriteTo(ref output, _repeated_unpackedNestedEnum_codec);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+ if (HasOneofUint32) {
output.WriteRawTag(248, 6);
output.WriteUInt32(OneofUint32);
}
@@ -3144,35 +3270,35 @@
output.WriteRawTag(130, 7);
output.WriteMessage(OneofNestedMessage);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+ if (HasOneofString) {
output.WriteRawTag(138, 7);
output.WriteString(OneofString);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+ if (HasOneofBytes) {
output.WriteRawTag(146, 7);
output.WriteBytes(OneofBytes);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBool) {
+ if (HasOneofBool) {
output.WriteRawTag(152, 7);
output.WriteBool(OneofBool);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint64) {
+ if (HasOneofUint64) {
output.WriteRawTag(160, 7);
output.WriteUInt64(OneofUint64);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofFloat) {
+ if (HasOneofFloat) {
output.WriteRawTag(173, 7);
output.WriteFloat(OneofFloat);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofDouble) {
+ if (HasOneofDouble) {
output.WriteRawTag(177, 7);
output.WriteDouble(OneofDouble);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofEnum) {
+ if (HasOneofEnum) {
output.WriteRawTag(184, 7);
output.WriteEnum((int) OneofEnum);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofNullValue) {
+ if (HasOneofNullValue) {
output.WriteRawTag(192, 7);
output.WriteEnum((int) OneofNullValue);
}
@@ -3466,34 +3592,34 @@
size += mapStringForeignMessage_.CalculateSize(_map_mapStringForeignMessage_codec);
size += mapStringNestedEnum_.CalculateSize(_map_mapStringNestedEnum_codec);
size += mapStringForeignEnum_.CalculateSize(_map_mapStringForeignEnum_codec);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+ if (HasOneofUint32) {
size += 2 + pb::CodedOutputStream.ComputeUInt32Size(OneofUint32);
}
if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
size += 2 + pb::CodedOutputStream.ComputeMessageSize(OneofNestedMessage);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+ if (HasOneofString) {
size += 2 + pb::CodedOutputStream.ComputeStringSize(OneofString);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+ if (HasOneofBytes) {
size += 2 + pb::CodedOutputStream.ComputeBytesSize(OneofBytes);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBool) {
+ if (HasOneofBool) {
size += 2 + 1;
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint64) {
+ if (HasOneofUint64) {
size += 2 + pb::CodedOutputStream.ComputeUInt64Size(OneofUint64);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofFloat) {
+ if (HasOneofFloat) {
size += 2 + 4;
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofDouble) {
+ if (HasOneofDouble) {
size += 2 + 8;
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofEnum) {
+ if (HasOneofEnum) {
size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OneofEnum);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofNullValue) {
+ if (HasOneofNullValue) {
size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OneofNullValue);
}
if (optionalBoolWrapper_ != null) {
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestCustomOptionsProto3.pb.cs b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestCustomOptionsProto3.pb.cs
index 42cac04..8b94027 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestCustomOptionsProto3.pb.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestCustomOptionsProto3.pb.cs
@@ -324,12 +324,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int OneofField {
- get { return anOneofCase_ == AnOneofOneofCase.OneofField ? (int) anOneof_ : 0; }
+ get { return HasOneofField ? (int) anOneof_ : 0; }
set {
anOneof_ = value;
anOneofCase_ = AnOneofOneofCase.OneofField;
}
}
+ /// <summary>Gets whether the "oneof_field" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofField {
+ get { return anOneofCase_ == AnOneofOneofCase.OneofField; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_field" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofField() {
+ if (HasOneofField) {
+ ClearAnOneof();
+ }
+ }
private object anOneof_;
/// <summary>Enum of possible cases for the "AnOneof" oneof.</summary>
@@ -377,7 +391,7 @@
public override int GetHashCode() {
int hash = 1;
if (Field1.Length != 0) hash ^= Field1.GetHashCode();
- if (anOneofCase_ == AnOneofOneofCase.OneofField) hash ^= OneofField.GetHashCode();
+ if (HasOneofField) hash ^= OneofField.GetHashCode();
hash ^= (int) anOneofCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
@@ -401,7 +415,7 @@
output.WriteRawTag(10);
output.WriteString(Field1);
}
- if (anOneofCase_ == AnOneofOneofCase.OneofField) {
+ if (HasOneofField) {
output.WriteRawTag(16);
output.WriteInt32(OneofField);
}
@@ -419,7 +433,7 @@
output.WriteRawTag(10);
output.WriteString(Field1);
}
- if (anOneofCase_ == AnOneofOneofCase.OneofField) {
+ if (HasOneofField) {
output.WriteRawTag(16);
output.WriteInt32(OneofField);
}
@@ -436,7 +450,7 @@
if (Field1.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Field1);
}
- if (anOneofCase_ == AnOneofOneofCase.OneofField) {
+ if (HasOneofField) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(OneofField);
}
if (_unknownFields != null) {
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.pb.cs b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.pb.cs
index b5a517a..82e935e 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.pb.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestIssues.pb.cs
@@ -2015,24 +2015,52 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string O1String {
- get { return o1Case_ == O1OneofCase.O1String ? (string) o1_ : ""; }
+ get { return HasO1String ? (string) o1_ : ""; }
set {
o1_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
o1Case_ = O1OneofCase.O1String;
}
}
+ /// <summary>Gets whether the "o1_string" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasO1String {
+ get { return o1Case_ == O1OneofCase.O1String; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "o1_string" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearO1String() {
+ if (HasO1String) {
+ ClearO1();
+ }
+ }
/// <summary>Field number for the "o1_int32" field.</summary>
public const int O1Int32FieldNumber = 5;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int O1Int32 {
- get { return o1Case_ == O1OneofCase.O1Int32 ? (int) o1_ : 0; }
+ get { return HasO1Int32 ? (int) o1_ : 0; }
set {
o1_ = value;
o1Case_ = O1OneofCase.O1Int32;
}
}
+ /// <summary>Gets whether the "o1_int32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasO1Int32 {
+ get { return o1Case_ == O1OneofCase.O1Int32; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "o1_int32" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearO1Int32() {
+ if (HasO1Int32) {
+ ClearO1();
+ }
+ }
/// <summary>Field number for the "plain_string" field.</summary>
public const int PlainStringFieldNumber = 1;
@@ -2051,24 +2079,52 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int O2Int32 {
- get { return o2Case_ == O2OneofCase.O2Int32 ? (int) o2_ : 0; }
+ get { return HasO2Int32 ? (int) o2_ : 0; }
set {
o2_ = value;
o2Case_ = O2OneofCase.O2Int32;
}
}
+ /// <summary>Gets whether the "o2_int32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasO2Int32 {
+ get { return o2Case_ == O2OneofCase.O2Int32; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "o2_int32" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearO2Int32() {
+ if (HasO2Int32) {
+ ClearO2();
+ }
+ }
/// <summary>Field number for the "o2_string" field.</summary>
public const int O2StringFieldNumber = 3;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string O2String {
- get { return o2Case_ == O2OneofCase.O2String ? (string) o2_ : ""; }
+ get { return HasO2String ? (string) o2_ : ""; }
set {
o2_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
o2Case_ = O2OneofCase.O2String;
}
}
+ /// <summary>Gets whether the "o2_string" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasO2String {
+ get { return o2Case_ == O2OneofCase.O2String; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "o2_string" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearO2String() {
+ if (HasO2String) {
+ ClearO2();
+ }
+ }
private object o1_;
/// <summary>Enum of possible cases for the "o1" oneof.</summary>
@@ -2143,11 +2199,11 @@
public override int GetHashCode() {
int hash = 1;
if (PlainInt32 != 0) hash ^= PlainInt32.GetHashCode();
- if (o1Case_ == O1OneofCase.O1String) hash ^= O1String.GetHashCode();
- if (o1Case_ == O1OneofCase.O1Int32) hash ^= O1Int32.GetHashCode();
+ if (HasO1String) hash ^= O1String.GetHashCode();
+ if (HasO1Int32) hash ^= O1Int32.GetHashCode();
if (PlainString.Length != 0) hash ^= PlainString.GetHashCode();
- if (o2Case_ == O2OneofCase.O2Int32) hash ^= O2Int32.GetHashCode();
- if (o2Case_ == O2OneofCase.O2String) hash ^= O2String.GetHashCode();
+ if (HasO2Int32) hash ^= O2Int32.GetHashCode();
+ if (HasO2String) hash ^= O2String.GetHashCode();
hash ^= (int) o1Case_;
hash ^= (int) o2Case_;
if (_unknownFields != null) {
@@ -2172,11 +2228,11 @@
output.WriteRawTag(10);
output.WriteString(PlainString);
}
- if (o1Case_ == O1OneofCase.O1String) {
+ if (HasO1String) {
output.WriteRawTag(18);
output.WriteString(O1String);
}
- if (o2Case_ == O2OneofCase.O2String) {
+ if (HasO2String) {
output.WriteRawTag(26);
output.WriteString(O2String);
}
@@ -2184,11 +2240,11 @@
output.WriteRawTag(32);
output.WriteInt32(PlainInt32);
}
- if (o1Case_ == O1OneofCase.O1Int32) {
+ if (HasO1Int32) {
output.WriteRawTag(40);
output.WriteInt32(O1Int32);
}
- if (o2Case_ == O2OneofCase.O2Int32) {
+ if (HasO2Int32) {
output.WriteRawTag(48);
output.WriteInt32(O2Int32);
}
@@ -2206,11 +2262,11 @@
output.WriteRawTag(10);
output.WriteString(PlainString);
}
- if (o1Case_ == O1OneofCase.O1String) {
+ if (HasO1String) {
output.WriteRawTag(18);
output.WriteString(O1String);
}
- if (o2Case_ == O2OneofCase.O2String) {
+ if (HasO2String) {
output.WriteRawTag(26);
output.WriteString(O2String);
}
@@ -2218,11 +2274,11 @@
output.WriteRawTag(32);
output.WriteInt32(PlainInt32);
}
- if (o1Case_ == O1OneofCase.O1Int32) {
+ if (HasO1Int32) {
output.WriteRawTag(40);
output.WriteInt32(O1Int32);
}
- if (o2Case_ == O2OneofCase.O2Int32) {
+ if (HasO2Int32) {
output.WriteRawTag(48);
output.WriteInt32(O2Int32);
}
@@ -2239,19 +2295,19 @@
if (PlainInt32 != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(PlainInt32);
}
- if (o1Case_ == O1OneofCase.O1String) {
+ if (HasO1String) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(O1String);
}
- if (o1Case_ == O1OneofCase.O1Int32) {
+ if (HasO1Int32) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(O1Int32);
}
if (PlainString.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(PlainString);
}
- if (o2Case_ == O2OneofCase.O2Int32) {
+ if (HasO2Int32) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(O2Int32);
}
- if (o2Case_ == O2OneofCase.O2String) {
+ if (HasO2String) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(O2String);
}
if (_unknownFields != null) {
@@ -2703,12 +2759,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string Text {
- get { return valueCase_ == ValueOneofCase.Text ? (string) value_ : ""; }
+ get { return HasText ? (string) value_ : ""; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
valueCase_ = ValueOneofCase.Text;
}
}
+ /// <summary>Gets whether the "text" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasText {
+ get { return valueCase_ == ValueOneofCase.Text; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "text" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearText() {
+ if (HasText) {
+ ClearValue();
+ }
+ }
/// <summary>Field number for the "nested" field.</summary>
public const int NestedFieldNumber = 2;
@@ -2768,7 +2838,7 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (valueCase_ == ValueOneofCase.Text) hash ^= Text.GetHashCode();
+ if (HasText) hash ^= Text.GetHashCode();
if (valueCase_ == ValueOneofCase.Nested) hash ^= Nested.GetHashCode();
hash ^= (int) valueCase_;
if (_unknownFields != null) {
@@ -2789,7 +2859,7 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (valueCase_ == ValueOneofCase.Text) {
+ if (HasText) {
output.WriteRawTag(10);
output.WriteString(Text);
}
@@ -2807,7 +2877,7 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (valueCase_ == ValueOneofCase.Text) {
+ if (HasText) {
output.WriteRawTag(10);
output.WriteString(Text);
}
@@ -2825,7 +2895,7 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (valueCase_ == ValueOneofCase.Text) {
+ if (HasText) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Text);
}
if (valueCase_ == ValueOneofCase.Nested) {
@@ -3209,24 +3279,52 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string StringValue {
- get { return valueCase_ == ValueOneofCase.StringValue ? (string) value_ : ""; }
+ get { return HasStringValue ? (string) value_ : ""; }
set {
value_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
valueCase_ = ValueOneofCase.StringValue;
}
}
+ /// <summary>Gets whether the "string_value" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasStringValue {
+ get { return valueCase_ == ValueOneofCase.StringValue; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "string_value" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearStringValue() {
+ if (HasStringValue) {
+ ClearValue();
+ }
+ }
/// <summary>Field number for the "null_value" field.</summary>
public const int NullValueFieldNumber = 2;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Google.Protobuf.WellKnownTypes.NullValue NullValue {
- get { return valueCase_ == ValueOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) value_ : global::Google.Protobuf.WellKnownTypes.NullValue.NullValue; }
+ get { return HasNullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) value_ : global::Google.Protobuf.WellKnownTypes.NullValue.NullValue; }
set {
value_ = value;
valueCase_ = ValueOneofCase.NullValue;
}
}
+ /// <summary>Gets whether the "null_value" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasNullValue {
+ get { return valueCase_ == ValueOneofCase.NullValue; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "null_value" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearNullValue() {
+ if (HasNullValue) {
+ ClearValue();
+ }
+ }
private object value_;
/// <summary>Enum of possible cases for the "value" oneof.</summary>
@@ -3274,8 +3372,8 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (valueCase_ == ValueOneofCase.StringValue) hash ^= StringValue.GetHashCode();
- if (valueCase_ == ValueOneofCase.NullValue) hash ^= NullValue.GetHashCode();
+ if (HasStringValue) hash ^= StringValue.GetHashCode();
+ if (HasNullValue) hash ^= NullValue.GetHashCode();
hash ^= (int) valueCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
@@ -3295,11 +3393,11 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (valueCase_ == ValueOneofCase.StringValue) {
+ if (HasStringValue) {
output.WriteRawTag(10);
output.WriteString(StringValue);
}
- if (valueCase_ == ValueOneofCase.NullValue) {
+ if (HasNullValue) {
output.WriteRawTag(16);
output.WriteEnum((int) NullValue);
}
@@ -3313,11 +3411,11 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (valueCase_ == ValueOneofCase.StringValue) {
+ if (HasStringValue) {
output.WriteRawTag(10);
output.WriteString(StringValue);
}
- if (valueCase_ == ValueOneofCase.NullValue) {
+ if (HasNullValue) {
output.WriteRawTag(16);
output.WriteEnum((int) NullValue);
}
@@ -3331,10 +3429,10 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (valueCase_ == ValueOneofCase.StringValue) {
+ if (HasStringValue) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
}
- if (valueCase_ == ValueOneofCase.NullValue) {
+ if (HasNullValue) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) NullValue);
}
if (_unknownFields != null) {
@@ -3661,11 +3759,13 @@
/// <summary>Field number for the "optional_field" field.</summary>
public const int OptionalFieldFieldNumber = 2;
+ private readonly static string OptionalFieldDefaultValue = "";
+
private string optionalField_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string OptionalField {
- get { return optionalField_ ?? ""; }
+ get { return optionalField_ ?? OptionalFieldDefaultValue; }
set {
optionalField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
@@ -3897,24 +3997,52 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string X {
- get { return testCase_ == TestOneofCase.X ? (string) test_ : ""; }
+ get { return HasX ? (string) test_ : ""; }
set {
test_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
testCase_ = TestOneofCase.X;
}
}
+ /// <summary>Gets whether the "x" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasX {
+ get { return testCase_ == TestOneofCase.X; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "x" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearX() {
+ if (HasX) {
+ ClearTest();
+ }
+ }
/// <summary>Field number for the "none" field.</summary>
public const int NoneFieldNumber = 2;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string None {
- get { return testCase_ == TestOneofCase.None_ ? (string) test_ : ""; }
+ get { return HasNone ? (string) test_ : ""; }
set {
test_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
testCase_ = TestOneofCase.None_;
}
}
+ /// <summary>Gets whether the "none" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasNone {
+ get { return testCase_ == TestOneofCase.None_; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "none" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearNone() {
+ if (HasNone) {
+ ClearTest();
+ }
+ }
private object test_;
/// <summary>Enum of possible cases for the "test" oneof.</summary>
@@ -3962,8 +4090,8 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (testCase_ == TestOneofCase.X) hash ^= X.GetHashCode();
- if (testCase_ == TestOneofCase.None_) hash ^= None.GetHashCode();
+ if (HasX) hash ^= X.GetHashCode();
+ if (HasNone) hash ^= None.GetHashCode();
hash ^= (int) testCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
@@ -3983,11 +4111,11 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (testCase_ == TestOneofCase.X) {
+ if (HasX) {
output.WriteRawTag(10);
output.WriteString(X);
}
- if (testCase_ == TestOneofCase.None_) {
+ if (HasNone) {
output.WriteRawTag(18);
output.WriteString(None);
}
@@ -4001,11 +4129,11 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (testCase_ == TestOneofCase.X) {
+ if (HasX) {
output.WriteRawTag(10);
output.WriteString(X);
}
- if (testCase_ == TestOneofCase.None_) {
+ if (HasNone) {
output.WriteRawTag(18);
output.WriteString(None);
}
@@ -4019,10 +4147,10 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (testCase_ == TestOneofCase.X) {
+ if (HasX) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(X);
}
- if (testCase_ == TestOneofCase.None_) {
+ if (HasNone) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(None);
}
if (_unknownFields != null) {
@@ -4156,24 +4284,52 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string X {
- get { return noneCase_ == NoneOneofCase.X ? (string) none_ : ""; }
+ get { return HasX ? (string) none_ : ""; }
set {
none_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
noneCase_ = NoneOneofCase.X;
}
}
+ /// <summary>Gets whether the "x" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasX {
+ get { return noneCase_ == NoneOneofCase.X; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "x" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearX() {
+ if (HasX) {
+ ClearNone();
+ }
+ }
/// <summary>Field number for the "y" field.</summary>
public const int YFieldNumber = 2;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string Y {
- get { return noneCase_ == NoneOneofCase.Y ? (string) none_ : ""; }
+ get { return HasY ? (string) none_ : ""; }
set {
none_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
noneCase_ = NoneOneofCase.Y;
}
}
+ /// <summary>Gets whether the "y" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasY {
+ get { return noneCase_ == NoneOneofCase.Y; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "y" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearY() {
+ if (HasY) {
+ ClearNone();
+ }
+ }
private object none_;
/// <summary>Enum of possible cases for the "none" oneof.</summary>
@@ -4221,8 +4377,8 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (noneCase_ == NoneOneofCase.X) hash ^= X.GetHashCode();
- if (noneCase_ == NoneOneofCase.Y) hash ^= Y.GetHashCode();
+ if (HasX) hash ^= X.GetHashCode();
+ if (HasY) hash ^= Y.GetHashCode();
hash ^= (int) noneCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
@@ -4242,11 +4398,11 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (noneCase_ == NoneOneofCase.X) {
+ if (HasX) {
output.WriteRawTag(10);
output.WriteString(X);
}
- if (noneCase_ == NoneOneofCase.Y) {
+ if (HasY) {
output.WriteRawTag(18);
output.WriteString(Y);
}
@@ -4260,11 +4416,11 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (noneCase_ == NoneOneofCase.X) {
+ if (HasX) {
output.WriteRawTag(10);
output.WriteString(X);
}
- if (noneCase_ == NoneOneofCase.Y) {
+ if (HasY) {
output.WriteRawTag(18);
output.WriteString(Y);
}
@@ -4278,10 +4434,10 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (noneCase_ == NoneOneofCase.X) {
+ if (HasX) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(X);
}
- if (noneCase_ == NoneOneofCase.Y) {
+ if (HasY) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Y);
}
if (_unknownFields != null) {
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3.pb.cs b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3.pb.cs
index 7236b1c..209d37b 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3.pb.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3.pb.cs
@@ -880,12 +880,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint OneofUint32 {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32 ? (uint) oneofField_ : 0; }
+ get { return HasOneofUint32 ? (uint) oneofField_ : 0; }
set {
oneofField_ = value;
oneofFieldCase_ = OneofFieldOneofCase.OneofUint32;
}
}
+ /// <summary>Gets whether the "oneof_uint32" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofUint32 {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofUint32; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_uint32" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofUint32() {
+ if (HasOneofUint32) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_nested_message" field.</summary>
public const int OneofNestedMessageFieldNumber = 112;
@@ -904,24 +918,52 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string OneofString {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString ? (string) oneofField_ : ""; }
+ get { return HasOneofString ? (string) oneofField_ : ""; }
set {
oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
oneofFieldCase_ = OneofFieldOneofCase.OneofString;
}
}
+ /// <summary>Gets whether the "oneof_string" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofString {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofString; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_string" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofString() {
+ if (HasOneofString) {
+ ClearOneofField();
+ }
+ }
/// <summary>Field number for the "oneof_bytes" field.</summary>
public const int OneofBytesFieldNumber = 114;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pb::ByteString OneofBytes {
- get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
+ get { return HasOneofBytes ? (pb::ByteString) oneofField_ : pb::ByteString.Empty; }
set {
oneofField_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
oneofFieldCase_ = OneofFieldOneofCase.OneofBytes;
}
}
+ /// <summary>Gets whether the "oneof_bytes" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasOneofBytes {
+ get { return oneofFieldCase_ == OneofFieldOneofCase.OneofBytes; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "oneof_bytes" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearOneofBytes() {
+ if (HasOneofBytes) {
+ ClearOneofField();
+ }
+ }
private object oneofField_;
/// <summary>Enum of possible cases for the "oneof_field" oneof.</summary>
@@ -1061,10 +1103,10 @@
hash ^= repeatedForeignEnum_.GetHashCode();
hash ^= repeatedImportEnum_.GetHashCode();
hash ^= repeatedPublicImportMessage_.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) hash ^= OneofUint32.GetHashCode();
+ if (HasOneofUint32) hash ^= OneofUint32.GetHashCode();
if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) hash ^= OneofNestedMessage.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) hash ^= OneofString.GetHashCode();
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) hash ^= OneofBytes.GetHashCode();
+ if (HasOneofString) hash ^= OneofString.GetHashCode();
+ if (HasOneofBytes) hash ^= OneofBytes.GetHashCode();
hash ^= (int) oneofFieldCase_;
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
@@ -1194,7 +1236,7 @@
repeatedForeignEnum_.WriteTo(output, _repeated_repeatedForeignEnum_codec);
repeatedImportEnum_.WriteTo(output, _repeated_repeatedImportEnum_codec);
repeatedPublicImportMessage_.WriteTo(output, _repeated_repeatedPublicImportMessage_codec);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+ if (HasOneofUint32) {
output.WriteRawTag(248, 6);
output.WriteUInt32(OneofUint32);
}
@@ -1202,11 +1244,11 @@
output.WriteRawTag(130, 7);
output.WriteMessage(OneofNestedMessage);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+ if (HasOneofString) {
output.WriteRawTag(138, 7);
output.WriteString(OneofString);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+ if (HasOneofBytes) {
output.WriteRawTag(146, 7);
output.WriteBytes(OneofBytes);
}
@@ -1330,7 +1372,7 @@
repeatedForeignEnum_.WriteTo(ref output, _repeated_repeatedForeignEnum_codec);
repeatedImportEnum_.WriteTo(ref output, _repeated_repeatedImportEnum_codec);
repeatedPublicImportMessage_.WriteTo(ref output, _repeated_repeatedPublicImportMessage_codec);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+ if (HasOneofUint32) {
output.WriteRawTag(248, 6);
output.WriteUInt32(OneofUint32);
}
@@ -1338,11 +1380,11 @@
output.WriteRawTag(130, 7);
output.WriteMessage(OneofNestedMessage);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+ if (HasOneofString) {
output.WriteRawTag(138, 7);
output.WriteString(OneofString);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+ if (HasOneofBytes) {
output.WriteRawTag(146, 7);
output.WriteBytes(OneofBytes);
}
@@ -1444,16 +1486,16 @@
size += repeatedForeignEnum_.CalculateSize(_repeated_repeatedForeignEnum_codec);
size += repeatedImportEnum_.CalculateSize(_repeated_repeatedImportEnum_codec);
size += repeatedPublicImportMessage_.CalculateSize(_repeated_repeatedPublicImportMessage_codec);
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofUint32) {
+ if (HasOneofUint32) {
size += 2 + pb::CodedOutputStream.ComputeUInt32Size(OneofUint32);
}
if (oneofFieldCase_ == OneofFieldOneofCase.OneofNestedMessage) {
size += 2 + pb::CodedOutputStream.ComputeMessageSize(OneofNestedMessage);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofString) {
+ if (HasOneofString) {
size += 2 + pb::CodedOutputStream.ComputeStringSize(OneofString);
}
- if (oneofFieldCase_ == OneofFieldOneofCase.OneofBytes) {
+ if (HasOneofBytes) {
size += 2 + pb::CodedOutputStream.ComputeBytesSize(OneofBytes);
}
if (_unknownFields != null) {
@@ -7309,24 +7351,52 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int FooInt {
- get { return fooCase_ == FooOneofCase.FooInt ? (int) foo_ : 0; }
+ get { return HasFooInt ? (int) foo_ : 0; }
set {
foo_ = value;
fooCase_ = FooOneofCase.FooInt;
}
}
+ /// <summary>Gets whether the "foo_int" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasFooInt {
+ get { return fooCase_ == FooOneofCase.FooInt; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "foo_int" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearFooInt() {
+ if (HasFooInt) {
+ ClearFoo();
+ }
+ }
/// <summary>Field number for the "foo_string" field.</summary>
public const int FooStringFieldNumber = 2;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string FooString {
- get { return fooCase_ == FooOneofCase.FooString ? (string) foo_ : ""; }
+ get { return HasFooString ? (string) foo_ : ""; }
set {
foo_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
fooCase_ = FooOneofCase.FooString;
}
}
+ /// <summary>Gets whether the "foo_string" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasFooString {
+ get { return fooCase_ == FooOneofCase.FooString; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "foo_string" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearFooString() {
+ if (HasFooString) {
+ ClearFoo();
+ }
+ }
/// <summary>Field number for the "foo_message" field.</summary>
public const int FooMessageFieldNumber = 3;
@@ -7388,8 +7458,8 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (fooCase_ == FooOneofCase.FooInt) hash ^= FooInt.GetHashCode();
- if (fooCase_ == FooOneofCase.FooString) hash ^= FooString.GetHashCode();
+ if (HasFooInt) hash ^= FooInt.GetHashCode();
+ if (HasFooString) hash ^= FooString.GetHashCode();
if (fooCase_ == FooOneofCase.FooMessage) hash ^= FooMessage.GetHashCode();
hash ^= (int) fooCase_;
if (_unknownFields != null) {
@@ -7410,11 +7480,11 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (fooCase_ == FooOneofCase.FooInt) {
+ if (HasFooInt) {
output.WriteRawTag(8);
output.WriteInt32(FooInt);
}
- if (fooCase_ == FooOneofCase.FooString) {
+ if (HasFooString) {
output.WriteRawTag(18);
output.WriteString(FooString);
}
@@ -7432,11 +7502,11 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (fooCase_ == FooOneofCase.FooInt) {
+ if (HasFooInt) {
output.WriteRawTag(8);
output.WriteInt32(FooInt);
}
- if (fooCase_ == FooOneofCase.FooString) {
+ if (HasFooString) {
output.WriteRawTag(18);
output.WriteString(FooString);
}
@@ -7454,10 +7524,10 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (fooCase_ == FooOneofCase.FooInt) {
+ if (HasFooInt) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(FooInt);
}
- if (fooCase_ == FooOneofCase.FooString) {
+ if (HasFooString) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(FooString);
}
if (fooCase_ == FooOneofCase.FooMessage) {
diff --git a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3Optional.pb.cs b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3Optional.pb.cs
index b97d56f..ff9c203 100644
--- a/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3Optional.pb.cs
+++ b/csharp/src/Google.Protobuf.Test.TestProtos/UnittestProto3Optional.pb.cs
@@ -148,6 +148,8 @@
/// <summary>Field number for the "optional_int32" field.</summary>
public const int OptionalInt32FieldNumber = 1;
+ private readonly static int OptionalInt32DefaultValue = 0;
+
private int optionalInt32_;
/// <summary>
/// Singular
@@ -155,7 +157,7 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int OptionalInt32 {
- get { if ((_hasBits0 & 1) != 0) { return optionalInt32_; } else { return 0; } }
+ get { if ((_hasBits0 & 1) != 0) { return optionalInt32_; } else { return OptionalInt32DefaultValue; } }
set {
_hasBits0 |= 1;
optionalInt32_ = value;
@@ -176,11 +178,13 @@
/// <summary>Field number for the "optional_int64" field.</summary>
public const int OptionalInt64FieldNumber = 2;
+ private readonly static long OptionalInt64DefaultValue = 0L;
+
private long optionalInt64_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public long OptionalInt64 {
- get { if ((_hasBits0 & 2) != 0) { return optionalInt64_; } else { return 0L; } }
+ get { if ((_hasBits0 & 2) != 0) { return optionalInt64_; } else { return OptionalInt64DefaultValue; } }
set {
_hasBits0 |= 2;
optionalInt64_ = value;
@@ -201,11 +205,13 @@
/// <summary>Field number for the "optional_uint32" field.</summary>
public const int OptionalUint32FieldNumber = 3;
+ private readonly static uint OptionalUint32DefaultValue = 0;
+
private uint optionalUint32_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint OptionalUint32 {
- get { if ((_hasBits0 & 4) != 0) { return optionalUint32_; } else { return 0; } }
+ get { if ((_hasBits0 & 4) != 0) { return optionalUint32_; } else { return OptionalUint32DefaultValue; } }
set {
_hasBits0 |= 4;
optionalUint32_ = value;
@@ -226,11 +232,13 @@
/// <summary>Field number for the "optional_uint64" field.</summary>
public const int OptionalUint64FieldNumber = 4;
+ private readonly static ulong OptionalUint64DefaultValue = 0UL;
+
private ulong optionalUint64_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public ulong OptionalUint64 {
- get { if ((_hasBits0 & 8) != 0) { return optionalUint64_; } else { return 0UL; } }
+ get { if ((_hasBits0 & 8) != 0) { return optionalUint64_; } else { return OptionalUint64DefaultValue; } }
set {
_hasBits0 |= 8;
optionalUint64_ = value;
@@ -251,11 +259,13 @@
/// <summary>Field number for the "optional_sint32" field.</summary>
public const int OptionalSint32FieldNumber = 5;
+ private readonly static int OptionalSint32DefaultValue = 0;
+
private int optionalSint32_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int OptionalSint32 {
- get { if ((_hasBits0 & 16) != 0) { return optionalSint32_; } else { return 0; } }
+ get { if ((_hasBits0 & 16) != 0) { return optionalSint32_; } else { return OptionalSint32DefaultValue; } }
set {
_hasBits0 |= 16;
optionalSint32_ = value;
@@ -276,11 +286,13 @@
/// <summary>Field number for the "optional_sint64" field.</summary>
public const int OptionalSint64FieldNumber = 6;
+ private readonly static long OptionalSint64DefaultValue = 0L;
+
private long optionalSint64_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public long OptionalSint64 {
- get { if ((_hasBits0 & 32) != 0) { return optionalSint64_; } else { return 0L; } }
+ get { if ((_hasBits0 & 32) != 0) { return optionalSint64_; } else { return OptionalSint64DefaultValue; } }
set {
_hasBits0 |= 32;
optionalSint64_ = value;
@@ -301,11 +313,13 @@
/// <summary>Field number for the "optional_fixed32" field.</summary>
public const int OptionalFixed32FieldNumber = 7;
+ private readonly static uint OptionalFixed32DefaultValue = 0;
+
private uint optionalFixed32_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public uint OptionalFixed32 {
- get { if ((_hasBits0 & 64) != 0) { return optionalFixed32_; } else { return 0; } }
+ get { if ((_hasBits0 & 64) != 0) { return optionalFixed32_; } else { return OptionalFixed32DefaultValue; } }
set {
_hasBits0 |= 64;
optionalFixed32_ = value;
@@ -326,11 +340,13 @@
/// <summary>Field number for the "optional_fixed64" field.</summary>
public const int OptionalFixed64FieldNumber = 8;
+ private readonly static ulong OptionalFixed64DefaultValue = 0UL;
+
private ulong optionalFixed64_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public ulong OptionalFixed64 {
- get { if ((_hasBits0 & 128) != 0) { return optionalFixed64_; } else { return 0UL; } }
+ get { if ((_hasBits0 & 128) != 0) { return optionalFixed64_; } else { return OptionalFixed64DefaultValue; } }
set {
_hasBits0 |= 128;
optionalFixed64_ = value;
@@ -351,11 +367,13 @@
/// <summary>Field number for the "optional_sfixed32" field.</summary>
public const int OptionalSfixed32FieldNumber = 9;
+ private readonly static int OptionalSfixed32DefaultValue = 0;
+
private int optionalSfixed32_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int OptionalSfixed32 {
- get { if ((_hasBits0 & 256) != 0) { return optionalSfixed32_; } else { return 0; } }
+ get { if ((_hasBits0 & 256) != 0) { return optionalSfixed32_; } else { return OptionalSfixed32DefaultValue; } }
set {
_hasBits0 |= 256;
optionalSfixed32_ = value;
@@ -376,11 +394,13 @@
/// <summary>Field number for the "optional_sfixed64" field.</summary>
public const int OptionalSfixed64FieldNumber = 10;
+ private readonly static long OptionalSfixed64DefaultValue = 0L;
+
private long optionalSfixed64_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public long OptionalSfixed64 {
- get { if ((_hasBits0 & 512) != 0) { return optionalSfixed64_; } else { return 0L; } }
+ get { if ((_hasBits0 & 512) != 0) { return optionalSfixed64_; } else { return OptionalSfixed64DefaultValue; } }
set {
_hasBits0 |= 512;
optionalSfixed64_ = value;
@@ -401,11 +421,13 @@
/// <summary>Field number for the "optional_float" field.</summary>
public const int OptionalFloatFieldNumber = 11;
+ private readonly static float OptionalFloatDefaultValue = 0F;
+
private float optionalFloat_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public float OptionalFloat {
- get { if ((_hasBits0 & 1024) != 0) { return optionalFloat_; } else { return 0F; } }
+ get { if ((_hasBits0 & 1024) != 0) { return optionalFloat_; } else { return OptionalFloatDefaultValue; } }
set {
_hasBits0 |= 1024;
optionalFloat_ = value;
@@ -426,11 +448,13 @@
/// <summary>Field number for the "optional_double" field.</summary>
public const int OptionalDoubleFieldNumber = 12;
+ private readonly static double OptionalDoubleDefaultValue = 0D;
+
private double optionalDouble_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public double OptionalDouble {
- get { if ((_hasBits0 & 2048) != 0) { return optionalDouble_; } else { return 0D; } }
+ get { if ((_hasBits0 & 2048) != 0) { return optionalDouble_; } else { return OptionalDoubleDefaultValue; } }
set {
_hasBits0 |= 2048;
optionalDouble_ = value;
@@ -451,11 +475,13 @@
/// <summary>Field number for the "optional_bool" field.</summary>
public const int OptionalBoolFieldNumber = 13;
+ private readonly static bool OptionalBoolDefaultValue = false;
+
private bool optionalBool_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool OptionalBool {
- get { if ((_hasBits0 & 4096) != 0) { return optionalBool_; } else { return false; } }
+ get { if ((_hasBits0 & 4096) != 0) { return optionalBool_; } else { return OptionalBoolDefaultValue; } }
set {
_hasBits0 |= 4096;
optionalBool_ = value;
@@ -476,11 +502,13 @@
/// <summary>Field number for the "optional_string" field.</summary>
public const int OptionalStringFieldNumber = 14;
+ private readonly static string OptionalStringDefaultValue = "";
+
private string optionalString_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string OptionalString {
- get { return optionalString_ ?? ""; }
+ get { return optionalString_ ?? OptionalStringDefaultValue; }
set {
optionalString_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
@@ -500,11 +528,13 @@
/// <summary>Field number for the "optional_bytes" field.</summary>
public const int OptionalBytesFieldNumber = 15;
+ private readonly static pb::ByteString OptionalBytesDefaultValue = pb::ByteString.Empty;
+
private pb::ByteString optionalBytes_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pb::ByteString OptionalBytes {
- get { return optionalBytes_ ?? pb::ByteString.Empty; }
+ get { return optionalBytes_ ?? OptionalBytesDefaultValue; }
set {
optionalBytes_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
@@ -524,11 +554,13 @@
/// <summary>Field number for the "optional_cord" field.</summary>
public const int OptionalCordFieldNumber = 16;
+ private readonly static string OptionalCordDefaultValue = "";
+
private string optionalCord_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string OptionalCord {
- get { return optionalCord_ ?? ""; }
+ get { return optionalCord_ ?? OptionalCordDefaultValue; }
set {
optionalCord_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
@@ -572,11 +604,13 @@
/// <summary>Field number for the "optional_nested_enum" field.</summary>
public const int OptionalNestedEnumFieldNumber = 21;
+ private readonly static global::ProtobufUnittest.TestProto3Optional.Types.NestedEnum OptionalNestedEnumDefaultValue = global::ProtobufUnittest.TestProto3Optional.Types.NestedEnum.Unspecified;
+
private global::ProtobufUnittest.TestProto3Optional.Types.NestedEnum optionalNestedEnum_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::ProtobufUnittest.TestProto3Optional.Types.NestedEnum OptionalNestedEnum {
- get { if ((_hasBits0 & 8192) != 0) { return optionalNestedEnum_; } else { return global::ProtobufUnittest.TestProto3Optional.Types.NestedEnum.Unspecified; } }
+ get { if ((_hasBits0 & 8192) != 0) { return optionalNestedEnum_; } else { return OptionalNestedEnumDefaultValue; } }
set {
_hasBits0 |= 8192;
optionalNestedEnum_ = value;
@@ -1315,6 +1349,8 @@
/// <summary>Field number for the "bb" field.</summary>
public const int BbFieldNumber = 1;
+ private readonly static int BbDefaultValue = 0;
+
private int bb_;
/// <summary>
/// The field name "b" fails to compile in proto1 because it conflicts with
@@ -1324,7 +1360,7 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Bb {
- get { if ((_hasBits0 & 1) != 0) { return bb_; } else { return 0; } }
+ get { if ((_hasBits0 & 1) != 0) { return bb_; } else { return BbDefaultValue; } }
set {
_hasBits0 |= 1;
bb_ = value;
diff --git a/csharp/src/Google.Protobuf.Test/testprotos.pb b/csharp/src/Google.Protobuf.Test/testprotos.pb
index 5e361f9..8fb22bc 100644
--- a/csharp/src/Google.Protobuf.Test/testprotos.pb
+++ b/csharp/src/Google.Protobuf.Test/testprotos.pb
Binary files differ
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.pb.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.pb.cs
index aa25686..38a49ac 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.pb.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.pb.cs
@@ -55,7 +55,7 @@
/// `NullValue` is a singleton enumeration to represent the null value for the
/// `Value` type union.
///
- /// The JSON representation for `NullValue` is JSON `null`.
+ /// The JSON representation for `NullValue` is JSON `null`.
/// </summary>
public enum NullValue {
/// <summary>
@@ -338,12 +338,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public global::Google.Protobuf.WellKnownTypes.NullValue NullValue {
- get { return kindCase_ == KindOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : global::Google.Protobuf.WellKnownTypes.NullValue.NullValue; }
+ get { return HasNullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : global::Google.Protobuf.WellKnownTypes.NullValue.NullValue; }
set {
kind_ = value;
kindCase_ = KindOneofCase.NullValue;
}
}
+ /// <summary>Gets whether the "null_value" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasNullValue {
+ get { return kindCase_ == KindOneofCase.NullValue; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "null_value" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearNullValue() {
+ if (HasNullValue) {
+ ClearKind();
+ }
+ }
/// <summary>Field number for the "number_value" field.</summary>
public const int NumberValueFieldNumber = 2;
@@ -353,12 +367,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public double NumberValue {
- get { return kindCase_ == KindOneofCase.NumberValue ? (double) kind_ : 0D; }
+ get { return HasNumberValue ? (double) kind_ : 0D; }
set {
kind_ = value;
kindCase_ = KindOneofCase.NumberValue;
}
}
+ /// <summary>Gets whether the "number_value" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasNumberValue {
+ get { return kindCase_ == KindOneofCase.NumberValue; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "number_value" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearNumberValue() {
+ if (HasNumberValue) {
+ ClearKind();
+ }
+ }
/// <summary>Field number for the "string_value" field.</summary>
public const int StringValueFieldNumber = 3;
@@ -368,12 +396,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string StringValue {
- get { return kindCase_ == KindOneofCase.StringValue ? (string) kind_ : ""; }
+ get { return HasStringValue ? (string) kind_ : ""; }
set {
kind_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
kindCase_ = KindOneofCase.StringValue;
}
}
+ /// <summary>Gets whether the "string_value" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasStringValue {
+ get { return kindCase_ == KindOneofCase.StringValue; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "string_value" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearStringValue() {
+ if (HasStringValue) {
+ ClearKind();
+ }
+ }
/// <summary>Field number for the "bool_value" field.</summary>
public const int BoolValueFieldNumber = 4;
@@ -383,12 +425,26 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool BoolValue {
- get { return kindCase_ == KindOneofCase.BoolValue ? (bool) kind_ : false; }
+ get { return HasBoolValue ? (bool) kind_ : false; }
set {
kind_ = value;
kindCase_ = KindOneofCase.BoolValue;
}
}
+ /// <summary>Gets whether the "bool_value" field is set</summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public bool HasBoolValue {
+ get { return kindCase_ == KindOneofCase.BoolValue; }
+ }
+ /// <summary> Clears the value of the oneof if it's currently set to "bool_value" </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public void ClearBoolValue() {
+ if (HasBoolValue) {
+ ClearKind();
+ }
+ }
/// <summary>Field number for the "struct_value" field.</summary>
public const int StructValueFieldNumber = 5;
@@ -474,10 +530,10 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
- if (kindCase_ == KindOneofCase.NullValue) hash ^= NullValue.GetHashCode();
- if (kindCase_ == KindOneofCase.NumberValue) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(NumberValue);
- if (kindCase_ == KindOneofCase.StringValue) hash ^= StringValue.GetHashCode();
- if (kindCase_ == KindOneofCase.BoolValue) hash ^= BoolValue.GetHashCode();
+ if (HasNullValue) hash ^= NullValue.GetHashCode();
+ if (HasNumberValue) hash ^= pbc::ProtobufEqualityComparers.BitwiseDoubleEqualityComparer.GetHashCode(NumberValue);
+ if (HasStringValue) hash ^= StringValue.GetHashCode();
+ if (HasBoolValue) hash ^= BoolValue.GetHashCode();
if (kindCase_ == KindOneofCase.StructValue) hash ^= StructValue.GetHashCode();
if (kindCase_ == KindOneofCase.ListValue) hash ^= ListValue.GetHashCode();
hash ^= (int) kindCase_;
@@ -499,19 +555,19 @@
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
- if (kindCase_ == KindOneofCase.NullValue) {
+ if (HasNullValue) {
output.WriteRawTag(8);
output.WriteEnum((int) NullValue);
}
- if (kindCase_ == KindOneofCase.NumberValue) {
+ if (HasNumberValue) {
output.WriteRawTag(17);
output.WriteDouble(NumberValue);
}
- if (kindCase_ == KindOneofCase.StringValue) {
+ if (HasStringValue) {
output.WriteRawTag(26);
output.WriteString(StringValue);
}
- if (kindCase_ == KindOneofCase.BoolValue) {
+ if (HasBoolValue) {
output.WriteRawTag(32);
output.WriteBool(BoolValue);
}
@@ -533,19 +589,19 @@
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
- if (kindCase_ == KindOneofCase.NullValue) {
+ if (HasNullValue) {
output.WriteRawTag(8);
output.WriteEnum((int) NullValue);
}
- if (kindCase_ == KindOneofCase.NumberValue) {
+ if (HasNumberValue) {
output.WriteRawTag(17);
output.WriteDouble(NumberValue);
}
- if (kindCase_ == KindOneofCase.StringValue) {
+ if (HasStringValue) {
output.WriteRawTag(26);
output.WriteString(StringValue);
}
- if (kindCase_ == KindOneofCase.BoolValue) {
+ if (HasBoolValue) {
output.WriteRawTag(32);
output.WriteBool(BoolValue);
}
@@ -567,16 +623,16 @@
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
- if (kindCase_ == KindOneofCase.NullValue) {
+ if (HasNullValue) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) NullValue);
}
- if (kindCase_ == KindOneofCase.NumberValue) {
+ if (HasNumberValue) {
size += 1 + 8;
}
- if (kindCase_ == KindOneofCase.StringValue) {
+ if (HasStringValue) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(StringValue);
}
- if (kindCase_ == KindOneofCase.BoolValue) {
+ if (HasBoolValue) {
size += 1 + 1;
}
if (kindCase_ == KindOneofCase.StructValue) {
diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Type.pb.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Type.pb.cs
index 3088e38..7ad0a7a 100644
--- a/csharp/src/Google.Protobuf/WellKnownTypes/Type.pb.cs
+++ b/csharp/src/Google.Protobuf/WellKnownTypes/Type.pb.cs
@@ -26,46 +26,47 @@
string.Concat(
"Chpnb29nbGUvcHJvdG9idWYvdHlwZS5wcm90bxIPZ29vZ2xlLnByb3RvYnVm",
"Ghlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvGiRnb29nbGUvcHJvdG9idWYv",
- "c291cmNlX2NvbnRleHQucHJvdG8i1wEKBFR5cGUSDAoEbmFtZRgBIAEoCRIm",
+ "c291cmNlX2NvbnRleHQucHJvdG8i6AEKBFR5cGUSDAoEbmFtZRgBIAEoCRIm",
"CgZmaWVsZHMYAiADKAsyFi5nb29nbGUucHJvdG9idWYuRmllbGQSDgoGb25l",
"b2ZzGAMgAygJEigKB29wdGlvbnMYBCADKAsyFy5nb29nbGUucHJvdG9idWYu",
"T3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAUgASgLMh4uZ29vZ2xlLnByb3Rv",
"YnVmLlNvdXJjZUNvbnRleHQSJwoGc3ludGF4GAYgASgOMhcuZ29vZ2xlLnBy",
- "b3RvYnVmLlN5bnRheCLVBQoFRmllbGQSKQoEa2luZBgBIAEoDjIbLmdvb2ds",
- "ZS5wcm90b2J1Zi5GaWVsZC5LaW5kEjcKC2NhcmRpbmFsaXR5GAIgASgOMiIu",
- "Z29vZ2xlLnByb3RvYnVmLkZpZWxkLkNhcmRpbmFsaXR5Eg4KBm51bWJlchgD",
- "IAEoBRIMCgRuYW1lGAQgASgJEhAKCHR5cGVfdXJsGAYgASgJEhMKC29uZW9m",
- "X2luZGV4GAcgASgFEg4KBnBhY2tlZBgIIAEoCBIoCgdvcHRpb25zGAkgAygL",
- "MhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhIRCglqc29uX25hbWUYCiABKAkS",
- "FQoNZGVmYXVsdF92YWx1ZRgLIAEoCSLIAgoES2luZBIQCgxUWVBFX1VOS05P",
- "V04QABIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBF",
- "X0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoM",
- "VFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09M",
- "EAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9N",
- "RVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJ",
- "VFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVE",
- "NjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIidAoLQ2Fy",
- "ZGluYWxpdHkSFwoTQ0FSRElOQUxJVFlfVU5LTk9XThAAEhgKFENBUkRJTkFM",
- "SVRZX09QVElPTkFMEAESGAoUQ0FSRElOQUxJVFlfUkVRVUlSRUQQAhIYChRD",
- "QVJESU5BTElUWV9SRVBFQVRFRBADIs4BCgRFbnVtEgwKBG5hbWUYASABKAkS",
- "LQoJZW51bXZhbHVlGAIgAygLMhouZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1",
- "ZRIoCgdvcHRpb25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhI2",
- "Cg5zb3VyY2VfY29udGV4dBgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5Tb3Vy",
- "Y2VDb250ZXh0EicKBnN5bnRheBgFIAEoDjIXLmdvb2dsZS5wcm90b2J1Zi5T",
- "eW50YXgiUwoJRW51bVZhbHVlEgwKBG5hbWUYASABKAkSDgoGbnVtYmVyGAIg",
- "ASgFEigKB29wdGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9u",
- "IjsKBk9wdGlvbhIMCgRuYW1lGAEgASgJEiMKBXZhbHVlGAIgASgLMhQuZ29v",
- "Z2xlLnByb3RvYnVmLkFueSouCgZTeW50YXgSEQoNU1lOVEFYX1BST1RPMhAA",
- "EhEKDVNZTlRBWF9QUk9UTzMQAUJ7ChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
- "eXBlUHJvdG9QAVotZ29vZ2xlLmdvbGFuZy5vcmcvcHJvdG9idWYvdHlwZXMv",
- "a25vd24vdHlwZXBi+AEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxL",
- "bm93blR5cGVzYgZwcm90bzM="));
+ "b3RvYnVmLlN5bnRheBIPCgdlZGl0aW9uGAcgASgJItUFCgVGaWVsZBIpCgRr",
+ "aW5kGAEgASgOMhsuZ29vZ2xlLnByb3RvYnVmLkZpZWxkLktpbmQSNwoLY2Fy",
+ "ZGluYWxpdHkYAiABKA4yIi5nb29nbGUucHJvdG9idWYuRmllbGQuQ2FyZGlu",
+ "YWxpdHkSDgoGbnVtYmVyGAMgASgFEgwKBG5hbWUYBCABKAkSEAoIdHlwZV91",
+ "cmwYBiABKAkSEwoLb25lb2ZfaW5kZXgYByABKAUSDgoGcGFja2VkGAggASgI",
+ "EigKB29wdGlvbnMYCSADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9uEhEK",
+ "CWpzb25fbmFtZRgKIAEoCRIVCg1kZWZhdWx0X3ZhbHVlGAsgASgJIsgCCgRL",
+ "aW5kEhAKDFRZUEVfVU5LTk9XThAAEg8KC1RZUEVfRE9VQkxFEAESDgoKVFlQ",
+ "RV9GTE9BVBACEg4KClRZUEVfSU5UNjQQAxIPCgtUWVBFX1VJTlQ2NBAEEg4K",
+ "ClRZUEVfSU5UMzIQBRIQCgxUWVBFX0ZJWEVENjQQBhIQCgxUWVBFX0ZJWEVE",
+ "MzIQBxINCglUWVBFX0JPT0wQCBIPCgtUWVBFX1NUUklORxAJEg4KClRZUEVf",
+ "R1JPVVAQChIQCgxUWVBFX01FU1NBR0UQCxIOCgpUWVBFX0JZVEVTEAwSDwoL",
+ "VFlQRV9VSU5UMzIQDRINCglUWVBFX0VOVU0QDhIRCg1UWVBFX1NGSVhFRDMy",
+ "EA8SEQoNVFlQRV9TRklYRUQ2NBAQEg8KC1RZUEVfU0lOVDMyEBESDwoLVFlQ",
+ "RV9TSU5UNjQQEiJ0CgtDYXJkaW5hbGl0eRIXChNDQVJESU5BTElUWV9VTktO",
+ "T1dOEAASGAoUQ0FSRElOQUxJVFlfT1BUSU9OQUwQARIYChRDQVJESU5BTElU",
+ "WV9SRVFVSVJFRBACEhgKFENBUkRJTkFMSVRZX1JFUEVBVEVEEAMi3wEKBEVu",
+ "dW0SDAoEbmFtZRgBIAEoCRItCgllbnVtdmFsdWUYAiADKAsyGi5nb29nbGUu",
+ "cHJvdG9idWYuRW51bVZhbHVlEigKB29wdGlvbnMYAyADKAsyFy5nb29nbGUu",
+ "cHJvdG9idWYuT3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAQgASgLMh4uZ29v",
+ "Z2xlLnByb3RvYnVmLlNvdXJjZUNvbnRleHQSJwoGc3ludGF4GAUgASgOMhcu",
+ "Z29vZ2xlLnByb3RvYnVmLlN5bnRheBIPCgdlZGl0aW9uGAYgASgJIlMKCUVu",
+ "dW1WYWx1ZRIMCgRuYW1lGAEgASgJEg4KBm51bWJlchgCIAEoBRIoCgdvcHRp",
+ "b25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbiI7CgZPcHRpb24S",
+ "DAoEbmFtZRgBIAEoCRIjCgV2YWx1ZRgCIAEoCzIULmdvb2dsZS5wcm90b2J1",
+ "Zi5BbnkqQwoGU3ludGF4EhEKDVNZTlRBWF9QUk9UTzIQABIRCg1TWU5UQVhf",
+ "UFJPVE8zEAESEwoPU1lOVEFYX0VESVRJT05TEAJCewoTY29tLmdvb2dsZS5w",
+ "cm90b2J1ZkIJVHlwZVByb3RvUAFaLWdvb2dsZS5nb2xhbmcub3JnL3Byb3Rv",
+ "YnVmL3R5cGVzL2tub3duL3R5cGVwYvgBAaICA0dQQqoCHkdvb2dsZS5Qcm90",
+ "b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, null, new pbr::GeneratedClrTypeInfo[] {
- new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax", "Edition" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Field), global::Google.Protobuf.WellKnownTypes.Field.Parser, new[]{ "Kind", "Cardinality", "Number", "Name", "TypeUrl", "OneofIndex", "Packed", "Options", "JsonName", "DefaultValue" }, null, new[]{ typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Kind), typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) }, null, null),
- new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), global::Google.Protobuf.WellKnownTypes.Enum.Parser, new[]{ "Name", "Enumvalue", "Options", "SourceContext", "Syntax" }, null, null, null, null),
+ new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), global::Google.Protobuf.WellKnownTypes.Enum.Parser, new[]{ "Name", "Enumvalue", "Options", "SourceContext", "Syntax", "Edition" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.EnumValue), global::Google.Protobuf.WellKnownTypes.EnumValue.Parser, new[]{ "Name", "Number", "Options" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Option), global::Google.Protobuf.WellKnownTypes.Option.Parser, new[]{ "Name", "Value" }, null, null, null, null)
}));
@@ -86,6 +87,10 @@
/// Syntax `proto3`.
/// </summary>
[pbr::OriginalName("SYNTAX_PROTO3")] Proto3 = 1,
+ /// <summary>
+ /// Syntax `editions`.
+ /// </summary>
+ [pbr::OriginalName("SYNTAX_EDITIONS")] Editions = 2,
}
#endregion
@@ -134,6 +139,7 @@
options_ = other.options_.Clone();
sourceContext_ = other.sourceContext_ != null ? other.sourceContext_.Clone() : null;
syntax_ = other.syntax_;
+ edition_ = other.edition_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@@ -230,6 +236,21 @@
}
}
+ /// <summary>Field number for the "edition" field.</summary>
+ public const int EditionFieldNumber = 7;
+ private string edition_ = "";
+ /// <summary>
+ /// The source edition string, only valid when syntax is SYNTAX_EDITIONS.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string Edition {
+ get { return edition_; }
+ set {
+ edition_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
@@ -251,6 +272,7 @@
if(!options_.Equals(other.options_)) return false;
if (!object.Equals(SourceContext, other.SourceContext)) return false;
if (Syntax != other.Syntax) return false;
+ if (Edition != other.Edition) return false;
return Equals(_unknownFields, other._unknownFields);
}
@@ -264,6 +286,7 @@
hash ^= options_.GetHashCode();
if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.Proto2) hash ^= Syntax.GetHashCode();
+ if (Edition.Length != 0) hash ^= Edition.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
@@ -297,6 +320,10 @@
output.WriteRawTag(48);
output.WriteEnum((int) Syntax);
}
+ if (Edition.Length != 0) {
+ output.WriteRawTag(58);
+ output.WriteString(Edition);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -322,6 +349,10 @@
output.WriteRawTag(48);
output.WriteEnum((int) Syntax);
}
+ if (Edition.Length != 0) {
+ output.WriteRawTag(58);
+ output.WriteString(Edition);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -344,6 +375,9 @@
if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.Proto2) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
}
+ if (Edition.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Edition);
+ }
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
@@ -371,6 +405,9 @@
if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.Proto2) {
Syntax = other.Syntax;
}
+ if (other.Edition.Length != 0) {
+ Edition = other.Edition;
+ }
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -413,6 +450,10 @@
Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break;
}
+ case 58: {
+ Edition = input.ReadString();
+ break;
+ }
}
}
#endif
@@ -455,6 +496,10 @@
Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break;
}
+ case 58: {
+ Edition = input.ReadString();
+ break;
+ }
}
}
}
@@ -1162,6 +1207,7 @@
options_ = other.options_.Clone();
sourceContext_ = other.sourceContext_ != null ? other.sourceContext_.Clone() : null;
syntax_ = other.syntax_;
+ edition_ = other.edition_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
@@ -1244,6 +1290,21 @@
}
}
+ /// <summary>Field number for the "edition" field.</summary>
+ public const int EditionFieldNumber = 6;
+ private string edition_ = "";
+ /// <summary>
+ /// The source edition string, only valid when syntax is SYNTAX_EDITIONS.
+ /// </summary>
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+ [global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
+ public string Edition {
+ get { return edition_; }
+ set {
+ edition_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
+ }
+ }
+
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
@@ -1264,6 +1325,7 @@
if(!options_.Equals(other.options_)) return false;
if (!object.Equals(SourceContext, other.SourceContext)) return false;
if (Syntax != other.Syntax) return false;
+ if (Edition != other.Edition) return false;
return Equals(_unknownFields, other._unknownFields);
}
@@ -1276,6 +1338,7 @@
hash ^= options_.GetHashCode();
if (sourceContext_ != null) hash ^= SourceContext.GetHashCode();
if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.Proto2) hash ^= Syntax.GetHashCode();
+ if (Edition.Length != 0) hash ^= Edition.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
@@ -1308,6 +1371,10 @@
output.WriteRawTag(40);
output.WriteEnum((int) Syntax);
}
+ if (Edition.Length != 0) {
+ output.WriteRawTag(50);
+ output.WriteString(Edition);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
@@ -1332,6 +1399,10 @@
output.WriteRawTag(40);
output.WriteEnum((int) Syntax);
}
+ if (Edition.Length != 0) {
+ output.WriteRawTag(50);
+ output.WriteString(Edition);
+ }
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
@@ -1353,6 +1424,9 @@
if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.Proto2) {
size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax);
}
+ if (Edition.Length != 0) {
+ size += 1 + pb::CodedOutputStream.ComputeStringSize(Edition);
+ }
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
@@ -1379,6 +1453,9 @@
if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.Proto2) {
Syntax = other.Syntax;
}
+ if (other.Edition.Length != 0) {
+ Edition = other.Edition;
+ }
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1417,6 +1494,10 @@
Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break;
}
+ case 50: {
+ Edition = input.ReadString();
+ break;
+ }
}
}
#endif
@@ -1455,6 +1536,10 @@
Syntax = (global::Google.Protobuf.WellKnownTypes.Syntax) input.ReadEnum();
break;
}
+ case 50: {
+ Edition = input.ReadString();
+ break;
+ }
}
}
}
diff --git a/examples/Makefile b/examples/Makefile
index ef7a4ef..f7ee9b1 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -10,11 +10,12 @@
gotest: add_person_gotest list_people_gotest
java: add_person_java list_people_java
python: add_person_python list_people_python
+ruby: add_person_ruby list_people_ruby
clean:
- rm -f add_person_cpp list_people_cpp add_person_java list_people_java add_person_python list_people_python
+ rm -f add_person_cpp list_people_cpp add_person_java list_people_java add_person_python list_people_python add_person_ruby list_people_ruby
rm -f javac_middleman AddPerson*.class ListPeople*.class com/example/tutorial/protos/*.class
- rm -f protoc_middleman addressbook.pb.cc addressbook.pb.h addressbook_pb2.py com/example/tutorial/protos/*.java
+ rm -f protoc_middleman protoc_middleman_ruby addressbook.pb.cc addressbook.pb.h addressbook_pb2.py addressbook_pb.rb com/example/tutorial/protos/*.java
rm -f *.pyc
rm -f go/tutorialpb/*.pb.go add_person_go list_people_go
rm -f protoc_middleman_dart dart_tutorial/*.pb*.dart
@@ -39,6 +40,10 @@
pub get
@touch protoc_middleman_dart
+protoc_middleman_ruby: addressbook.proto
+ protoc $$PROTO_PATH --ruby_out=. addressbook.proto
+ @touch protoc_middleman_ruby
+
add_person_cpp: add_person.cc protoc_middleman
pkg-config --cflags protobuf # fails if protobuf is not installed
c++ -std=c++14 add_person.cc addressbook.pb.cc -o add_person_cpp `pkg-config --cflags --libs protobuf`
@@ -90,3 +95,15 @@
@echo '#! /bin/sh' > list_people_python
@echo './list_people.py "$$@"' >> list_people_python
@chmod +x list_people_python
+
+add_person_ruby: add_person.rb protoc_middleman_ruby
+ @echo "Writing shortcut script add_person_ruby..."
+ @echo '#! /bin/sh' > add_person_ruby
+ @echo './add_person.rb "$$@"' >> add_person_ruby
+ @chmod +x add_person_ruby
+
+list_people_ruby: list_people.rb protoc_middleman_ruby
+ @echo "Writing shortcut script list_people_ruby..."
+ @echo '#! /bin/sh' > list_people_ruby
+ @echo './list_people.rb "$$@"' >> list_people_ruby
+ @chmod +x list_people_ruby
diff --git a/examples/add_person.rb b/examples/add_person.rb
new file mode 100755
index 0000000..35b6db9
--- /dev/null
+++ b/examples/add_person.rb
@@ -0,0 +1,77 @@
+#! /usr/bin/env ruby
+
+# See README.md for information and build instructions.
+
+require './addressbook_pb'
+require 'pry'
+
+# creates Person object and fills it with data from user input
+def prompt_for_address()
+ person = Tutorial::Person.newlD()
+
+ puts "Enter person ID number:"
+ person.id = STDIN.gets.chomp.to_i
+ puts "Enter name:"
+ person.name = STDIN.gets.chomp
+
+ puts "Enter email address (blank for none):"
+ email = STDIN.gets.chomp
+
+ if email != ""
+ person.email = email
+ end
+
+ loop do
+ puts "Enter a phone number (or leave blank to finish):"
+ number = STDIN.gets.chomp
+
+ if number == ""
+ break
+ end
+
+ phone_number = Tutorial::Person::PhoneNumber.new(number: number)
+ puts "Is this a mobile, home or work phone?"
+ type = STDIN.gets.chomp
+
+ case type
+ when "mobile"
+ phone_number.type = :MOBILE
+ when "home"
+ phone_number.type = :HOME
+ when "work"
+ phone_number.type = :WORK
+ else
+ puts "Unknown phone type; leaving as default value."
+ end
+ person.phones.push(phone_number)
+ end
+ person
+end
+
+# Main procedure: Reads the entire address book from a file,
+# adds one person based on user input, then writes it back out to the same
+# file.
+if ARGV.length != 1
+ puts "Usage: #{$0} ADDRESS_BOOK_FILE"
+ exit(-1)
+end
+
+address_book = Tutorial::AddressBook.new()
+if File.exist?(ARGV[0])
+ # Read the existing address book if it exists
+ f = File.open(ARGV[0], "rb")
+ address_book = Tutorial::AddressBook.decode(f.read)
+ f.close
+else
+ puts "#{$PROGRAM_NAME}: File not found. Creating new file."
+end
+
+person = prompt_for_address
+
+# Add an address.
+address_book.people.push(person)
+
+# Write the new address book back to disk.
+f = File.open(ARGV[0], "wb")
+f.write(Tutorial::AddressBook.encode(address_book))
+f.close
diff --git a/examples/list_people.rb b/examples/list_people.rb
new file mode 100755
index 0000000..fa63361
--- /dev/null
+++ b/examples/list_people.rb
@@ -0,0 +1,42 @@
+#! /usr/bin/env ruby
+
+require './addressbook_pb'
+require 'pry'
+
+# Iterates though all people in the AddressBook and prints info about them.
+def list_people(address_book)
+ address_book.people.each do |person|
+ puts "Person ID: #{person.id}"
+ puts " Name: #{person.name}"
+ if person.email != ""
+ puts " Email: #{person.email}"
+ end
+
+ person.phones.each do |phone_number|
+ type =
+ case phone_number.type
+ when :MOBILE
+ "Mobile phone"
+ when :HOME
+ "Home phone"
+ when :WORK
+ "Work phone"
+ end
+ puts " #{type} #: #{phone_number.number}"
+ end
+ end
+end
+
+# Main procedure: Reads the entire address book from a file and prints all
+# the information inside.
+if ARGV.length != 1
+ puts "Usage: #{$PROGRAM_NAME} ADDRESS_BOOK_FILE"
+ exit(-1)
+end
+
+# Read the existing address book.
+f = File.open(ARGV[0], "rb")
+address_book = Tutorial::AddressBook.decode(f.read)
+f.close
+
+list_people(address_book)
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
index e792d7d..4491977 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java
@@ -52,7 +52,12 @@
/** Constructs a mutable list by default. */
AbstractProtobufList() {
- isMutable = true;
+ this(true);
+ }
+
+ /** Constructs an immutable list for EMPTY lists */
+ AbstractProtobufList(boolean isMutable) {
+ this.isMutable = isMutable;
}
@Override
@@ -130,7 +135,9 @@
@Override
public final void makeImmutable() {
- isMutable = false;
+ if (isMutable) {
+ isMutable = false;
+ }
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 451fce1..bd1e9fa 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -45,10 +45,7 @@
final class BooleanArrayList extends AbstractProtobufList<Boolean>
implements BooleanList, RandomAccess, PrimitiveNonBoxingCollection {
- private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(new boolean[0], 0);
- static {
- EMPTY_LIST.makeImmutable();
- }
+ private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(new boolean[0], 0, false);
public static BooleanArrayList emptyList() {
return EMPTY_LIST;
@@ -65,15 +62,16 @@
/** Constructs a new mutable {@code BooleanArrayList} with default capacity. */
BooleanArrayList() {
- this(new boolean[DEFAULT_CAPACITY], 0);
+ this(new boolean[DEFAULT_CAPACITY], 0, true);
}
/**
* Constructs a new mutable {@code BooleanArrayList} containing the same elements as {@code
* other}.
*/
- private BooleanArrayList(boolean[] other, int size) {
- array = other;
+ private BooleanArrayList(boolean[] other, int size, boolean isMutable) {
+ super(isMutable);
+ this.array = other;
this.size = size;
}
@@ -126,7 +124,7 @@
if (capacity < size) {
throw new IllegalArgumentException();
}
- return new BooleanArrayList(Arrays.copyOf(array, capacity), size);
+ return new BooleanArrayList(Arrays.copyOf(array, capacity), size, true);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
index 272c5a1..9537ccb 100644
--- a/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
+++ b/java/core/src/main/java/com/google/protobuf/DescriptorMessageInfoFactory.java
@@ -315,80 +315,81 @@
if (fd.getContainingOneof() != null) {
// Build a oneof member field.
builder.withField(buildOneofMember(messageType, fd, oneofState, enforceUtf8, enumVerifier));
- } else {
- Field field = field(messageType, fd);
- int number = fd.getNumber();
- FieldType type = getFieldType(fd);
-
- if (fd.isMapField()) {
- // Map field points to an auto-generated message entry type with the definition:
- // message MapEntry {
- // K key = 1;
- // V value = 2;
- // }
- final FieldDescriptor valueField = fd.getMessageType().findFieldByNumber(2);
- if (valueField.getJavaType() == Descriptors.FieldDescriptor.JavaType.ENUM) {
- enumVerifier =
- new Internal.EnumVerifier() {
- @Override
- public boolean isInRange(int number) {
- return valueField.getEnumType().findValueByNumber(number) != null;
- }
- };
- }
- builder.withField(
- forMapField(
- field,
- number,
- SchemaUtil.getMapDefaultEntry(messageType, fd.getName()),
- enumVerifier));
- continue;
- }
-
- if (fd.isRepeated()) {
- // Repeated fields are not presence-checked.
- if (enumVerifier != null) {
- if (fd.isPacked()) {
- builder.withField(
- forPackedFieldWithEnumVerifier(
- field, number, type, enumVerifier, cachedSizeField(messageType, fd)));
- } else {
- builder.withField(forFieldWithEnumVerifier(field, number, type, enumVerifier));
- }
- } else if (fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
- builder.withField(
- forRepeatedMessageField(
- field, number, type, getTypeForRepeatedMessageField(messageType, fd)));
- } else {
- if (fd.isPacked()) {
- builder.withField(
- forPackedField(field, number, type, cachedSizeField(messageType, fd)));
- } else {
- builder.withField(forField(field, number, type, enforceUtf8));
- }
- }
- continue;
- }
-
- if (bitField == null) {
- // Lazy-create the next bitfield since we know it must exist.
- bitField = bitField(messageType, bitFieldIndex);
- }
-
- // It's a presence-checked field.
- if (fd.isRequired()) {
- builder.withField(
- forProto2RequiredField(
- field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier));
- } else {
- builder.withField(
- forProto2OptionalField(
- field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier));
- }
+ continue;
}
- // Update the presence mask for the next iteration. If the shift clears out the mask, we will
- // go to the next bitField.
+ Field field = field(messageType, fd);
+ int number = fd.getNumber();
+ FieldType type = getFieldType(fd);
+
+ if (fd.isMapField()) {
+ // Map field points to an auto-generated message entry type with the definition:
+ // message MapEntry {
+ // K key = 1;
+ // V value = 2;
+ // }
+ final FieldDescriptor valueField = fd.getMessageType().findFieldByNumber(2);
+ if (valueField.getJavaType() == Descriptors.FieldDescriptor.JavaType.ENUM) {
+ enumVerifier =
+ new Internal.EnumVerifier() {
+ @Override
+ public boolean isInRange(int number) {
+ return valueField.getEnumType().findValueByNumber(number) != null;
+ }
+ };
+ }
+ builder.withField(
+ forMapField(
+ field,
+ number,
+ SchemaUtil.getMapDefaultEntry(messageType, fd.getName()),
+ enumVerifier));
+ continue;
+ }
+
+ if (fd.isRepeated()) {
+ // Repeated fields are not presence-checked.
+ if (enumVerifier != null) {
+ if (fd.isPacked()) {
+ builder.withField(
+ forPackedFieldWithEnumVerifier(
+ field, number, type, enumVerifier, cachedSizeField(messageType, fd)));
+ } else {
+ builder.withField(forFieldWithEnumVerifier(field, number, type, enumVerifier));
+ }
+ } else if (fd.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ builder.withField(
+ forRepeatedMessageField(
+ field, number, type, getTypeForRepeatedMessageField(messageType, fd)));
+ } else {
+ if (fd.isPacked()) {
+ builder.withField(
+ forPackedField(field, number, type, cachedSizeField(messageType, fd)));
+ } else {
+ builder.withField(forField(field, number, type, enforceUtf8));
+ }
+ }
+ continue;
+ }
+
+ if (bitField == null) {
+ // Lazy-create the next bitfield since we know it must exist.
+ bitField = bitField(messageType, bitFieldIndex);
+ }
+
+ // It's a presence-checked field.
+ if (fd.isRequired()) {
+ builder.withField(
+ forProto2RequiredField(
+ field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier));
+ } else {
+ builder.withField(
+ forProto2OptionalField(
+ field, number, type, bitField, presenceMask, enforceUtf8, enumVerifier));
+ }
+
+ // Update the presence mask for the next iteration. If the shift clears out the mask, we
+ // will go to the next bitField.
presenceMask <<= 1;
if (presenceMask == 0) {
bitField = null;
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index e5b973f..d22b504 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -634,10 +634,6 @@
extensions[i].setProto(proto.getExtension(i));
}
}
-
- boolean supportsUnknownEnumValue() {
- return getSyntax() == Syntax.PROTO3;
- }
}
// =================================================================
@@ -1329,6 +1325,30 @@
}
/**
+ * Determines if the given enum field is treated as closed based on legacy non-conformant
+ * behavior.
+ *
+ * <p>Conformant behavior determines closedness based on the enum and can be queried using
+ * {@code EnumDescriptor.isClosed()}.
+ *
+ * <p>Some runtimes currently have a quirk where non-closed enums are treated as closed when
+ * used as the type of fields defined in a `syntax = proto2;` file. This quirk is not present in
+ * all runtimes; as of writing, we know that:
+ *
+ * <ul>
+ * <li>C++, Java, and C++-based Python share this quirk.
+ * <li>UPB and UPB-based Python do not.
+ * <li>PHP and Ruby treat all enums as open regardless of declaration.
+ * </ul>
+ *
+ * <p>Care should be taken when using this function to respect the target runtime's enum
+ * handling quirks.
+ */
+ public boolean legacyEnumFieldTreatedAsClosed() {
+ return getType() == Type.ENUM && getFile().getSyntax() == Syntax.PROTO2;
+ }
+
+ /**
* Compare with another {@code FieldDescriptor}. This orders fields in "canonical" order, which
* simply means ascending order by field number. {@code other} must be a field of the same type.
* That is, {@code getContainingType()} must return the same {@code Descriptor} for both fields.
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index 4085653..40a3e79 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -45,10 +45,7 @@
final class DoubleArrayList extends AbstractProtobufList<Double>
implements DoubleList, RandomAccess, PrimitiveNonBoxingCollection {
- private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(new double[0], 0);
- static {
- EMPTY_LIST.makeImmutable();
- }
+ private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(new double[0], 0, false);
public static DoubleArrayList emptyList() {
return EMPTY_LIST;
@@ -65,14 +62,15 @@
/** Constructs a new mutable {@code DoubleArrayList} with default capacity. */
DoubleArrayList() {
- this(new double[DEFAULT_CAPACITY], 0);
+ this(new double[DEFAULT_CAPACITY], 0, true);
}
/**
* Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
*/
- private DoubleArrayList(double[] other, int size) {
- array = other;
+ private DoubleArrayList(double[] other, int size, boolean isMutable) {
+ super(isMutable);
+ this.array = other;
this.size = size;
}
@@ -126,7 +124,7 @@
if (capacity < size) {
throw new IllegalArgumentException();
}
- return new DoubleArrayList(Arrays.copyOf(array, capacity), size);
+ return new DoubleArrayList(Arrays.copyOf(array, capacity), size, true);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
index 738c303..e564a63 100644
--- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -535,11 +535,10 @@
fields.clearField(oldField);
}
oneofCases[index] = field;
- } else if (field.getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3) {
- if (!field.isRepeated()
- && field.getJavaType() != FieldDescriptor.JavaType.MESSAGE
- && value.equals(field.getDefaultValue())) {
- // In proto3, setting a field to its default value is equivalent to clearing the field.
+ } else if (!field.hasPresence()) {
+ if (!field.isRepeated() && value.equals(field.getDefaultValue())) {
+ // Setting a field without presence to its default value is equivalent to clearing the
+ // field.
fields.clearField(field);
return this;
}
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index e6feba8..023fd6c 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -45,10 +45,7 @@
final class FloatArrayList extends AbstractProtobufList<Float>
implements FloatList, RandomAccess, PrimitiveNonBoxingCollection {
- private static final FloatArrayList EMPTY_LIST = new FloatArrayList(new float[0], 0);
- static {
- EMPTY_LIST.makeImmutable();
- }
+ private static final FloatArrayList EMPTY_LIST = new FloatArrayList(new float[0], 0, false);
public static FloatArrayList emptyList() {
return EMPTY_LIST;
@@ -65,14 +62,15 @@
/** Constructs a new mutable {@code FloatArrayList} with default capacity. */
FloatArrayList() {
- this(new float[DEFAULT_CAPACITY], 0);
+ this(new float[DEFAULT_CAPACITY], 0, true);
}
/**
* Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
*/
- private FloatArrayList(float[] other, int size) {
- array = other;
+ private FloatArrayList(float[] other, int size, boolean isMutable) {
+ super(isMutable);
+ this.array = other;
this.size = size;
}
@@ -125,7 +123,7 @@
if (capacity < size) {
throw new IllegalArgumentException();
}
- return new FloatArrayList(Arrays.copyOf(array, capacity), size);
+ return new FloatArrayList(Arrays.copyOf(array, capacity), size, true);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
index 26cc5bb..e62a382 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -2646,7 +2646,7 @@
valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class);
getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor");
- supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+ supportUnknownEnumValue = !descriptor.legacyEnumFieldTreatedAsClosed();
if (supportUnknownEnumValue) {
getValueMethod = getMethodOrDie(messageClass, "get" + camelCaseName + "Value");
getValueMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName + "Value");
@@ -2705,7 +2705,7 @@
valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class);
getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor");
- supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+ supportUnknownEnumValue = !descriptor.legacyEnumFieldTreatedAsClosed();
if (supportUnknownEnumValue) {
getRepeatedValueMethod =
getMethodOrDie(messageClass, "get" + camelCaseName + "Value", int.class);
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
index ab9581a..3fb6ea2 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageV3.java
@@ -423,6 +423,26 @@
return makeMutableCopy(list);
}
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static LongList mutableCopy(LongList list) {
+ return makeMutableCopy(list);
+ }
+
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static FloatList mutableCopy(FloatList list) {
+ return makeMutableCopy(list);
+ }
+
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static DoubleList mutableCopy(DoubleList list) {
+ return makeMutableCopy(list);
+ }
+
+ // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
+ protected static BooleanList mutableCopy(BooleanList list) {
+ return makeMutableCopy(list);
+ }
+
protected static LongList emptyLongList() {
return LongArrayList.emptyList();
}
@@ -432,11 +452,6 @@
return new LongArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static LongList mutableCopy(LongList list) {
- return makeMutableCopy(list);
- }
-
protected static FloatList emptyFloatList() {
return FloatArrayList.emptyList();
}
@@ -446,11 +461,6 @@
return new FloatArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static FloatList mutableCopy(FloatList list) {
- return makeMutableCopy(list);
- }
-
protected static DoubleList emptyDoubleList() {
return DoubleArrayList.emptyList();
}
@@ -460,11 +470,6 @@
return new DoubleArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static DoubleList mutableCopy(DoubleList list) {
- return makeMutableCopy(list);
- }
-
protected static BooleanList emptyBooleanList() {
return BooleanArrayList.emptyList();
}
@@ -474,11 +479,6 @@
return new BooleanArrayList();
}
- // TODO(b/258340024): Redundant with makeMutableCopy(). Remove.
- protected static BooleanList mutableCopy(BooleanList list) {
- return makeMutableCopy(list);
- }
-
@SuppressWarnings("unchecked") // Guaranteed by proto runtime.
protected static <ListT extends ProtobufList<?>> ListT makeMutableCopy(ListT list) {
int size = list.size();
@@ -2407,10 +2407,7 @@
isOneofField =
descriptor.getContainingOneof() != null
&& !descriptor.getContainingOneof().isSynthetic();
- hasHasMethod =
- descriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO2
- || descriptor.hasOptionalKeyword()
- || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
+ hasHasMethod = descriptor.hasPresence();
ReflectionInvoker reflectionInvoker =
new ReflectionInvoker(
descriptor,
@@ -2892,7 +2889,7 @@
valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class);
getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor");
- supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+ supportUnknownEnumValue = !descriptor.legacyEnumFieldTreatedAsClosed();
if (supportUnknownEnumValue) {
getValueMethod = getMethodOrDie(messageClass, "get" + camelCaseName + "Value");
getValueMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName + "Value");
@@ -2953,7 +2950,7 @@
valueOfMethod = getMethodOrDie(type, "valueOf", EnumValueDescriptor.class);
getValueDescriptorMethod = getMethodOrDie(type, "getValueDescriptor");
- supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
+ supportUnknownEnumValue = !descriptor.legacyEnumFieldTreatedAsClosed();
if (supportUnknownEnumValue) {
getRepeatedValueMethod =
getMethodOrDie(messageClass, "get" + camelCaseName + "Value", int.class);
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
index 9daeebe..692da9c 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -45,10 +45,7 @@
final class IntArrayList extends AbstractProtobufList<Integer>
implements IntList, RandomAccess, PrimitiveNonBoxingCollection {
- private static final IntArrayList EMPTY_LIST = new IntArrayList(new int[0], 0);
- static {
- EMPTY_LIST.makeImmutable();
- }
+ private static final IntArrayList EMPTY_LIST = new IntArrayList(new int[0], 0, false);
public static IntArrayList emptyList() {
return EMPTY_LIST;
@@ -65,13 +62,14 @@
/** Constructs a new mutable {@code IntArrayList} with default capacity. */
IntArrayList() {
- this(new int[DEFAULT_CAPACITY], 0);
+ this(new int[DEFAULT_CAPACITY], 0, true);
}
/**
* Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
*/
- private IntArrayList(int[] other, int size) {
+ private IntArrayList(int[] other, int size, boolean isMutable) {
+ super(isMutable);
array = other;
this.size = size;
}
@@ -125,7 +123,7 @@
if (capacity < size) {
throw new IllegalArgumentException();
}
- return new IntArrayList(Arrays.copyOf(array, capacity), size);
+ return new IntArrayList(Arrays.copyOf(array, capacity), size, true);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
index 7ef9687..3ff5a3b 100644
--- a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java
@@ -61,11 +61,7 @@
public class LazyStringArrayList extends AbstractProtobufList<String>
implements LazyStringList, RandomAccess {
- private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
-
- static {
- EMPTY_LIST.makeImmutable();
- }
+ private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList(false);
/** Returns an empty immutable {@code LazyStringArrayList} instance */
public static LazyStringArrayList emptyList() {
@@ -87,6 +83,11 @@
this(DEFAULT_CAPACITY);
}
+ private LazyStringArrayList(boolean isMutable) {
+ super(isMutable);
+ this.list = Collections.emptyList();
+ }
+
public LazyStringArrayList(int initialCapacity) {
this(new ArrayList<Object>(initialCapacity));
}
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index bda43a4..b5ca4de 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -45,10 +45,7 @@
final class LongArrayList extends AbstractProtobufList<Long>
implements LongList, RandomAccess, PrimitiveNonBoxingCollection {
- private static final LongArrayList EMPTY_LIST = new LongArrayList(new long[0], 0);
- static {
- EMPTY_LIST.makeImmutable();
- }
+ private static final LongArrayList EMPTY_LIST = new LongArrayList(new long[0], 0, false);
public static LongArrayList emptyList() {
return EMPTY_LIST;
@@ -65,14 +62,15 @@
/** Constructs a new mutable {@code LongArrayList} with default capacity. */
LongArrayList() {
- this(new long[DEFAULT_CAPACITY], 0);
+ this(new long[DEFAULT_CAPACITY], 0, true);
}
/**
* Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
*/
- private LongArrayList(long[] other, int size) {
- array = other;
+ private LongArrayList(long[] other, int size, boolean isMutable) {
+ super(isMutable);
+ this.array = other;
this.size = size;
}
@@ -125,7 +123,7 @@
if (capacity < size) {
throw new IllegalArgumentException();
}
- return new LongArrayList(Arrays.copyOf(array, capacity), size);
+ return new LongArrayList(Arrays.copyOf(array, capacity), size, true);
}
@Override
diff --git a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
index 2a4d867..2675070 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java
@@ -95,7 +95,8 @@
/**
* Returns true if the given field is set. This is exactly equivalent to calling the generated
- * "has" accessor method corresponding to the field.
+ * "has" accessor method corresponding to the field. The return value of hasField() is
+ * semantically meaningful only for fields where field.hasPresence() == true.
*
* @throws IllegalArgumentException The field is a repeated field, or {@code
* field.getContainingType() != getDescriptorForType()}.
diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
index 0404042..06cb7cd 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -1199,10 +1199,7 @@
if (field.getLiteType() == WireFormat.FieldType.ENUM) {
while (input.getBytesUntilLimit() > 0) {
final int rawValue = input.readEnum();
- if (field.getFile().supportsUnknownEnumValue()) {
- target.addRepeatedField(
- field, field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue));
- } else {
+ if (field.legacyEnumFieldTreatedAsClosed()) {
final Object value = field.getEnumType().findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// add it to the unknown fields.
@@ -1213,6 +1210,9 @@
} else {
target.addRepeatedField(field, value);
}
+ } else {
+ target.addRepeatedField(
+ field, field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue));
}
}
} else {
@@ -1239,9 +1239,7 @@
}
case ENUM:
final int rawValue = input.readEnum();
- if (field.getFile().supportsUnknownEnumValue()) {
- value = field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue);
- } else {
+ if (field.legacyEnumFieldTreatedAsClosed()) {
value = field.getEnumType().findValueByNumber(rawValue);
// If the number isn't recognized as a valid value for this enum,
// add it to the unknown fields.
@@ -1251,6 +1249,8 @@
}
return true;
}
+ } else {
+ value = field.getEnumType().findValueByNumberCreatingIfUnknown(rawValue);
}
break;
default:
diff --git a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
index 33e4bd5..28b547c 100644
--- a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java
@@ -38,11 +38,7 @@
final class ProtobufArrayList<E> extends AbstractProtobufList<E> implements RandomAccess {
private static final ProtobufArrayList<Object> EMPTY_LIST =
- new ProtobufArrayList<Object>(new Object[0], 0);
-
- static {
- EMPTY_LIST.makeImmutable();
- }
+ new ProtobufArrayList<Object>(new Object[0], 0, false);
@SuppressWarnings("unchecked") // Guaranteed safe by runtime.
public static <E> ProtobufArrayList<E> emptyList() {
@@ -54,10 +50,11 @@
@SuppressWarnings("unchecked")
ProtobufArrayList() {
- this((E[]) new Object[DEFAULT_CAPACITY], 0);
+ this((E[]) new Object[DEFAULT_CAPACITY], 0, true);
}
- private ProtobufArrayList(E[] array, int size) {
+ private ProtobufArrayList(E[] array, int size, boolean isMutable) {
+ super(isMutable);
this.array = array;
this.size = size;
}
@@ -70,7 +67,7 @@
E[] newArray = Arrays.copyOf(array, capacity);
- return new ProtobufArrayList<E>(newArray, size);
+ return new ProtobufArrayList<E>(newArray, size, true);
}
@Override
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index 38e547c..79c710a 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -99,6 +99,7 @@
FileDescriptor file = UnittestProto.getDescriptor();
assertThat(file.getName()).isEqualTo("google/protobuf/unittest.proto");
+ assertThat(file.getSyntax()).isEqualTo(Descriptors.FileDescriptor.Syntax.PROTO2);
assertThat(file.getPackage()).isEqualTo("protobuf_unittest");
assertThat(file.getOptions().getJavaOuterClassname()).isEqualTo("UnittestProto");
assertThat(file.toProto().getName()).isEqualTo("google/protobuf/unittest.proto");
@@ -148,6 +149,17 @@
}
@Test
+ public void testFileDescriptorGetSyntax() throws Exception {
+ FileDescriptorProto proto2 = FileDescriptorProto.newBuilder().setSyntax("proto2").build();
+ FileDescriptor file2 = Descriptors.FileDescriptor.buildFrom(proto2, new FileDescriptor[0]);
+ assertThat(file2.getSyntax()).isEqualTo(Descriptors.FileDescriptor.Syntax.PROTO2);
+
+ FileDescriptorProto proto3 = FileDescriptorProto.newBuilder().setSyntax("proto3").build();
+ FileDescriptor file3 = Descriptors.FileDescriptor.buildFrom(proto3, new FileDescriptor[0]);
+ assertThat(file3.getSyntax()).isEqualTo(Descriptors.FileDescriptor.Syntax.PROTO3);
+ }
+
+ @Test
public void testDescriptor() throws Exception {
Descriptor messageType = TestAllTypes.getDescriptor();
Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
@@ -290,6 +302,130 @@
}
@Test
+ public void testFieldDescriptorLegacyEnumFieldTreatedAsClosed() throws Exception {
+ // Make an open enum definition.
+ FileDescriptorProto openEnumFile =
+ FileDescriptorProto.newBuilder()
+ .setName("open_enum.proto")
+ .setSyntax("proto3")
+ .addEnumType(
+ EnumDescriptorProto.newBuilder()
+ .setName("TestEnumOpen")
+ .addValue(
+ EnumValueDescriptorProto.newBuilder()
+ .setName("TestEnumOpen_VALUE0")
+ .setNumber(0)
+ .build())
+ .build())
+ .build();
+ FileDescriptor openFileDescriptor =
+ Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
+ EnumDescriptor openEnum = openFileDescriptor.getEnumTypes().get(0);
+ assertThat(openEnum.isClosed()).isFalse();
+
+ // Create a message that treats enum fields as closed.
+ FileDescriptorProto closedEnumFile =
+ FileDescriptorProto.newBuilder()
+ .setName("closed_enum_field.proto")
+ .addDependency("open_enum.proto")
+ .setSyntax("proto2")
+ .addEnumType(
+ EnumDescriptorProto.newBuilder()
+ .setName("TestEnum")
+ .addValue(
+ EnumValueDescriptorProto.newBuilder()
+ .setName("TestEnum_VALUE0")
+ .setNumber(0)
+ .build())
+ .build())
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("TestClosedEnumField")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setName("int_field")
+ .setNumber(1)
+ .setType(FieldDescriptorProto.Type.TYPE_INT32)
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .build())
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setName("open_enum")
+ .setNumber(2)
+ .setType(FieldDescriptorProto.Type.TYPE_ENUM)
+ .setTypeName("TestEnumOpen")
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .build())
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setName("closed_enum")
+ .setNumber(3)
+ .setType(FieldDescriptorProto.Type.TYPE_ENUM)
+ .setTypeName("TestEnum")
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .build())
+ .build())
+ .build();
+ Descriptor closedMessage =
+ Descriptors.FileDescriptor.buildFrom(
+ closedEnumFile, new FileDescriptor[] {openFileDescriptor})
+ .getMessageTypes()
+ .get(0);
+ assertThat(closedMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
+ .isFalse();
+
+ assertThat(closedMessage.findFieldByName("closed_enum").legacyEnumFieldTreatedAsClosed())
+ .isTrue();
+ assertThat(closedMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
+ .isTrue();
+ }
+
+ @Test
+ public void testFieldDescriptorLegacyEnumFieldTreatedAsOpen() throws Exception {
+ // Make an open enum definition and message that treats enum fields as open.
+ FileDescriptorProto openEnumFile =
+ FileDescriptorProto.newBuilder()
+ .setName("open_enum.proto")
+ .setSyntax("proto3")
+ .addEnumType(
+ EnumDescriptorProto.newBuilder()
+ .setName("TestEnumOpen")
+ .addValue(
+ EnumValueDescriptorProto.newBuilder()
+ .setName("TestEnumOpen_VALUE0")
+ .setNumber(0)
+ .build())
+ .build())
+ .addMessageType(
+ DescriptorProto.newBuilder()
+ .setName("TestOpenEnumField")
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setName("int_field")
+ .setNumber(1)
+ .setType(FieldDescriptorProto.Type.TYPE_INT32)
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .build())
+ .addField(
+ FieldDescriptorProto.newBuilder()
+ .setName("open_enum")
+ .setNumber(2)
+ .setType(FieldDescriptorProto.Type.TYPE_ENUM)
+ .setTypeName("TestEnumOpen")
+ .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
+ .build())
+ .build())
+ .build();
+ FileDescriptor openEnumFileDescriptor =
+ Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
+ Descriptor openMessage = openEnumFileDescriptor.getMessageTypes().get(0);
+ EnumDescriptor openEnum = openEnumFileDescriptor.findEnumTypeByName("TestEnumOpen");
+ assertThat(openEnum.isClosed()).isFalse();
+ assertThat(openMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed()).isFalse();
+ assertThat(openMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed()).isFalse();
+ }
+
+ @Test
public void testEnumDescriptor() throws Exception {
EnumDescriptor enumType = ForeignEnum.getDescriptor();
EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index cf0061e..c933504 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -57,6 +57,7 @@
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestOneof2;
import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestReservedFields;
import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet;
import java.io.StringReader;
import java.util.Arrays;
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index 96bc388..719980a 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -1925,10 +1925,10 @@
// Try to interpret the value as a number.
try {
int numericValue = parseInt32(json);
- if (enumDescriptor.getFile().getSyntax() == FileDescriptor.Syntax.PROTO3) {
- result = enumDescriptor.findValueByNumberCreatingIfUnknown(numericValue);
- } else {
+ if (enumDescriptor.isClosed()) {
result = enumDescriptor.findValueByNumber(numericValue);
+ } else {
+ result = enumDescriptor.findValueByNumberCreatingIfUnknown(numericValue);
}
} catch (InvalidProtocolBufferException e) {
// Fall through. This exception is about invalid int32 value we get from parseInt32() but
diff --git a/objectivec/BUILD.bazel b/objectivec/BUILD.bazel
index 1c45357..0965de5 100644
--- a/objectivec/BUILD.bazel
+++ b/objectivec/BUILD.bazel
@@ -1,20 +1,66 @@
load("@rules_cc//cc:defs.bzl", "objc_library")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
+load("@upb//cmake:build_defs.bzl", "staleness_test")
load("//conformance:defs.bzl", "conformance_test")
+load(":defs.bzl", "objc_proto_camel_case_name")
+
+# The WKTs have to be checked in to support the CocoaPods and Xcode builds. This
+# generule and test ensure the source are current.
+#
+# Within the ":objectivec" target, the outputs of the genrule are then used to
+# ensure they are always "current". This implementation is basically the same
+# has how the WKTs are handled in src/google/protobuf/BUILD.bazel for the C++
+# version. They share the potential downsides around layer checks and that
+# someone could #include the header with the `wkt/` prefix on the name.
+
+_WELL_KNOWN_TYPES = [
+ "any",
+ "api",
+ "duration",
+ "empty",
+ "field_mask",
+ "source_context",
+ "struct",
+ "timestamp",
+ "type",
+ "wrappers",
+]
+
+_OBJC_WKT_NAMES = [objc_proto_camel_case_name(x) for x in _WELL_KNOWN_TYPES]
+
+_OBJC_EXTS = [
+ ".pbobjc.h",
+ ".pbobjc.m",
+]
+
+genrule(
+ name = "gen_wkt_sources",
+ srcs = ["//src/google/protobuf:well_known_type_protos"],
+ outs = ["wkt/GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS],
+ cmd = " && ".join([
+ "$(execpath //:protoc) --objc_out=$(RULEDIR)/wkt --proto_path=src $(SRCS)",
+ ] + [
+ "mv $(RULEDIR)/wkt/google/protobuf/" + wkt + ext + " $(RULEDIR)/wkt/GPB" + wkt + ext
+ for wkt in _OBJC_WKT_NAMES
+ for ext in _OBJC_EXTS
+ ]),
+ exec_tools = ["//:protoc"],
+)
+
+staleness_test(
+ name = "well_known_types_staleness_test",
+ outs = ["GPB" + wkt + ext for wkt in _OBJC_WKT_NAMES for ext in _OBJC_EXTS],
+ generated_pattern = "wkt/%s",
+ tags = ["manual"],
+)
+
+################################################################################
+# Objective-C Runtime Library
+################################################################################
objc_library(
name = "objectivec",
hdrs = [
- "GPBAny.pbobjc.h",
- "GPBApi.pbobjc.h",
- "GPBDuration.pbobjc.h",
- "GPBEmpty.pbobjc.h",
- "GPBFieldMask.pbobjc.h",
- "GPBSourceContext.pbobjc.h",
- "GPBStruct.pbobjc.h",
- "GPBTimestamp.pbobjc.h",
- "GPBType.pbobjc.h",
- "GPBWrappers.pbobjc.h",
"GPBArray.h",
"GPBBootstrap.h",
"GPBCodedInputStream.h",
@@ -55,39 +101,30 @@
"GPBUnknownFieldSet_PackagePrivate.h",
"GPBUnknownField_PackagePrivate.h",
"GPBUtilities_PackagePrivate.h",
- ],
+ ] + ["wkt/GPB" + wkt + ".pbobjc.h" for wkt in _OBJC_WKT_NAMES],
copts = [
"-Wno-vla",
],
includes = [
".",
+ "wkt",
],
non_arc_srcs = [
- "GPBAny.pbobjc.m",
- "GPBApi.pbobjc.m",
"GPBArray.m",
"GPBCodedInputStream.m",
"GPBCodedOutputStream.m",
"GPBDescriptor.m",
"GPBDictionary.m",
- "GPBDuration.pbobjc.m",
- "GPBEmpty.pbobjc.m",
"GPBExtensionInternals.m",
"GPBExtensionRegistry.m",
- "GPBFieldMask.pbobjc.m",
"GPBMessage.m",
"GPBRootObject.m",
- "GPBSourceContext.pbobjc.m",
- "GPBStruct.pbobjc.m",
- "GPBTimestamp.pbobjc.m",
- "GPBType.pbobjc.m",
"GPBUnknownField.m",
"GPBUnknownFieldSet.m",
"GPBUtilities.m",
"GPBWellKnownTypes.m",
"GPBWireFormat.m",
- "GPBWrappers.pbobjc.m",
- ],
+ ] + ["wkt/GPB" + wkt + ".pbobjc.m" for wkt in _OBJC_WKT_NAMES],
target_compatible_with = select({
"@platforms//os:macos": [],
"@platforms//os:ios": [],
@@ -105,8 +142,8 @@
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_objc.txt",
- testee = "//conformance:conformance_objc",
target_compatible_with = ["@platforms//os:macos"],
+ testee = "//conformance:conformance_objc",
)
# -------------------------------------------------------------------
@@ -121,6 +158,34 @@
],
)
+# -------------------------------------------------------------------
+# Validation of pddm expansion.
+
+py_binary(
+ name = "pddm",
+ srcs = ["DevTools/pddm.py"],
+)
+
+py_test(
+ name = "pddm_tests",
+ size = "small",
+ srcs = [
+ "DevTools/pddm.py",
+ "DevTools/pddm_tests.py",
+ ],
+)
+
+sh_test(
+ name = "sources_pddm_expansion_test",
+ size = "small",
+ srcs = ["DevTools/sources_pddm_expansion_test.sh"],
+ data = [":pddm"] + glob([
+ "**/*.h",
+ "**/*.m",
+ "**/*.pddm",
+ ]),
+)
+
################################################################################
# Distribution files
################################################################################
diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh
index d091a95..16981f9 100755
--- a/objectivec/DevTools/full_mac_build.sh
+++ b/objectivec/DevTools/full_mac_build.sh
@@ -2,8 +2,6 @@
#
# Helper to do build so you don't have to remember all the steps/args.
-echo "::group::Run full mac build"
-
set -eu
# Some base locations.
@@ -12,7 +10,7 @@
readonly BazelFlags="${BAZEL_FLAGS:---announce_rc --macos_minimum_os=10.9}"
# Invoke with BAZEL=bazelisk to use that instead.
-readonly BazelBin="${BAZEL:-bazel} ${BAZEL_STARTUP_FLAGS:-}"
+readonly BazelBin="${BAZEL:-bazel}"
printUsage() {
NAME=$(basename "${0}")
@@ -29,9 +27,6 @@
Show this message
-c, --clean
Issue a clean before the normal build.
- -r, --regenerate-descriptors
- Run generate_descriptor_proto.sh to regenerate all the checked in
- proto sources.
--full-build
By default only protoc is built within protobuf, this option will
enable a full build/test of the entire protobuf project.
@@ -76,7 +71,6 @@
fi
DO_CLEAN=no
-REGEN_DESCRIPTORS=no
FULL_BUILD=no
DO_XCODE_IOS_TESTS=yes
DO_XCODE_OSX_TESTS=yes
@@ -94,9 +88,6 @@
-c | --clean )
DO_CLEAN=yes
;;
- -r | --regenerate-descriptors )
- REGEN_DESCRIPTORS=yes
- ;;
--full-build )
FULL_BUILD=yes
;;
@@ -190,21 +181,16 @@
fi
fi
-if [[ "${REGEN_DESCRIPTORS}" == "yes" ]] ; then
- header "Regenerating the descriptor sources."
- ./generate_descriptor_proto.sh
-fi
-
if [[ "${FULL_BUILD}" == "yes" ]] ; then
header "Build/Test: everything"
- time ${BazelBin} test //:protoc //:protobuf //src/... $BazelFlags
+ ${BazelBin} test //:protoc //:protobuf //src/... $BazelFlags
else
header "Building: protoc"
- time ${BazelBin} build //:protoc $BazelFlags
+ ${BazelBin} build //:protoc $BazelFlags
fi
# Ensure the WKT sources checked in are current.
-time objectivec/generate_well_known_types.sh --check-only $BazelFlags
+objectivec/generate_well_known_types.sh --check-only
header "Checking on the ObjC Runtime Code"
# Some of the kokoro machines don't have python3 yet, so fall back to python if need be.
@@ -233,8 +219,7 @@
if [[ "${XCODE_QUIET}" == "yes" ]] ; then
XCODEBUILD_TEST_BASE_IOS+=( -quiet )
fi
- # Don't need to worry about form factors or retina/non retina;
- # just pick a mix of OS Versions and 32/64 bit.
+ # Don't need to worry about form factors or retina/non retina.
# NOTE: Different Xcode have different simulated hardware/os support.
case "${XCODE_VERSION}" in
[6-9].* | 1[0-2].* )
@@ -242,9 +227,8 @@
exit 11
;;
13.* | 14.*)
- # Dropped 32bit as Apple doesn't seem support the simulators either.
XCODEBUILD_TEST_BASE_IOS+=(
- -destination "platform=iOS Simulator,name=iPhone 8,OS=latest" # 64bit
+ -destination "platform=iOS Simulator,name=iPhone 13,OS=latest"
)
;;
* )
@@ -271,8 +255,7 @@
"${XCODEBUILD}"
-project objectivec/ProtocolBuffers_OSX.xcodeproj
-scheme ProtocolBuffers
- # Since the ObjC 2.0 Runtime is required, 32bit OS X isn't supported.
- -destination "platform=OS X,arch=x86_64" # 64bit
+ -destination "platform=macOS"
)
if [[ "${XCODE_QUIET}" == "yes" ]] ; then
XCODEBUILD_TEST_BASE_OSX+=( -quiet )
@@ -331,10 +314,8 @@
if [[ "${DO_OBJC_CONFORMANCE_TESTS}" == "yes" ]] ; then
header "Running ObjC Conformance Tests"
- time ${BazelBin} test //objectivec:conformance_test $BazelFlags
+ ${BazelBin} test //objectivec:conformance_test $BazelFlags
fi
echo ""
echo "$(basename "${0}"): Success!"
-
-echo "::endgroup::"
diff --git a/objectivec/DevTools/sources_pddm_expansion_test.sh b/objectivec/DevTools/sources_pddm_expansion_test.sh
new file mode 100755
index 0000000..99e01a1
--- /dev/null
+++ b/objectivec/DevTools/sources_pddm_expansion_test.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/pddm \
+ --dry-run \
+ ${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/*.[hm] \
+ ${TEST_SRCDIR}/google3/third_party/protobuf/objectivec/Tests/*.[hm] \
+ || die "Update by running: objectivec/DevTools/pddm.py objectivec/*.[hm] objectivec/Tests/*.[hm]"
+
+echo "PASS"
diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m
index ad5c75e..c8464a2 100644
--- a/objectivec/GPBCodedInputStream.m
+++ b/objectivec/GPBCodedInputStream.m
@@ -65,12 +65,24 @@
userInfo:exceptionInfo] raise];
}
-static void CheckRecursionLimit(GPBCodedInputStreamState *state) {
+GPB_INLINE void CheckRecursionLimit(GPBCodedInputStreamState *state) {
if (state->recursionDepth >= kDefaultRecursionLimit) {
RaiseException(GPBCodedInputStreamErrorRecursionDepthExceeded, nil);
}
}
+GPB_INLINE void CheckFieldSize(uint64_t size) {
+ // Bytes and Strings have a max size of 2GB. And since messages are on the wire as bytes/length
+ // delimited, they also have a 2GB size limit. The C++ does the same sort of enforcement (see
+ // parse_context, delimited_message_util, message_lite, etc.).
+ // https://protobuf.dev/programming-guides/encoding/#cheat-sheet
+ if (size > 0x7fffffff) {
+ // TODO(thomasvl): Maybe a different error code for this, but adding one is a breaking
+ // change so reuse an existing one.
+ RaiseException(GPBCodedInputStreamErrorInvalidSize, nil);
+ }
+}
+
static void CheckSize(GPBCodedInputStreamState *state, size_t size) {
size_t newSize = state->bufferPos + size;
if (newSize > state->bufferSize) {
@@ -223,14 +235,16 @@
}
NSString *GPBCodedInputStreamReadRetainedString(GPBCodedInputStreamState *state) {
- int32_t size = ReadRawVarint32(state);
+ uint64_t size = GPBCodedInputStreamReadUInt64(state);
+ CheckFieldSize(size);
+ NSUInteger ns_size = (NSUInteger)size;
NSString *result;
if (size == 0) {
result = @"";
} else {
CheckSize(state, size);
result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos]
- length:size
+ length:ns_size
encoding:NSUTF8StringEncoding];
state->bufferPos += size;
if (!result) {
@@ -246,21 +260,23 @@
}
NSData *GPBCodedInputStreamReadRetainedBytes(GPBCodedInputStreamState *state) {
- int32_t size = ReadRawVarint32(state);
- if (size < 0) return nil;
+ uint64_t size = GPBCodedInputStreamReadUInt64(state);
+ CheckFieldSize(size);
+ NSUInteger ns_size = (NSUInteger)size;
CheckSize(state, size);
- NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos length:size];
+ NSData *result = [[NSData alloc] initWithBytes:state->bytes + state->bufferPos length:ns_size];
state->bufferPos += size;
return result;
}
NSData *GPBCodedInputStreamReadRetainedBytesNoCopy(GPBCodedInputStreamState *state) {
- int32_t size = ReadRawVarint32(state);
- if (size < 0) return nil;
+ uint64_t size = GPBCodedInputStreamReadUInt64(state);
+ CheckFieldSize(size);
+ NSUInteger ns_size = (NSUInteger)size;
CheckSize(state, size);
// Cast is safe because freeWhenDone is NO.
NSData *result = [[NSData alloc] initWithBytesNoCopy:(void *)(state->bytes + state->bufferPos)
- length:size
+ length:ns_size
freeWhenDone:NO];
state->bufferPos += size;
return result;
@@ -342,9 +358,12 @@
case GPBWireFormatFixed64:
SkipRawData(&state_, sizeof(int64_t));
return YES;
- case GPBWireFormatLengthDelimited:
- SkipRawData(&state_, ReadRawVarint32(&state_));
+ case GPBWireFormatLengthDelimited: {
+ uint64_t size = GPBCodedInputStreamReadUInt64(&state_);
+ CheckFieldSize(size);
+ SkipRawData(&state_, size);
return YES;
+ }
case GPBWireFormatStartGroup:
[self skipMessage];
GPBCodedInputStreamCheckLastTagWas(
@@ -443,7 +462,8 @@
- (void)readMessage:(GPBMessage *)message
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
CheckRecursionLimit(&state_);
- int32_t length = ReadRawVarint32(&state_);
+ uint64_t length = GPBCodedInputStreamReadUInt64(&state_);
+ CheckFieldSize(length);
size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length);
++state_.recursionDepth;
[message mergeFromCodedInputStream:self extensionRegistry:extensionRegistry];
@@ -457,7 +477,8 @@
field:(GPBFieldDescriptor *)field
parentMessage:(GPBMessage *)parentMessage {
CheckRecursionLimit(&state_);
- int32_t length = ReadRawVarint32(&state_);
+ uint64_t length = GPBCodedInputStreamReadUInt64(&state_);
+ CheckFieldSize(length);
size_t oldLimit = GPBCodedInputStreamPushLimit(&state_, length);
++state_.recursionDepth;
GPBDictionaryReadEntry(mapDictionary, self, extensionRegistry, field, parentMessage);
diff --git a/objectivec/GPBCodedOutputStream.h b/objectivec/GPBCodedOutputStream.h
index 42eac77..4969e5a 100644
--- a/objectivec/GPBCodedOutputStream.h
+++ b/objectivec/GPBCodedOutputStream.h
@@ -110,6 +110,11 @@
- (void)flush;
/**
+ * @return The number of bytes written out. Includes bytes not yet flused.
+ **/
+- (size_t)bytesWritten;
+
+/**
* Write the raw byte out.
*
* @param value The value to write out.
diff --git a/objectivec/GPBCodedOutputStream.m b/objectivec/GPBCodedOutputStream.m
index c21e7d2..da62715 100644
--- a/objectivec/GPBCodedOutputStream.m
+++ b/objectivec/GPBCodedOutputStream.m
@@ -48,6 +48,7 @@
uint8_t *bytes;
size_t size;
size_t position;
+ size_t bytesFlushed;
NSOutputStream *output;
} GPBOutputBufferState;
@@ -71,6 +72,7 @@
if (written != (NSInteger)state->position) {
[NSException raise:GPBCodedOutputStreamException_WriteFailed format:@""];
}
+ state->bytesFlushed += written;
state->position = 0;
}
}
@@ -192,6 +194,13 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
+- (size_t)bytesWritten {
+ // Could use NSStreamFileCurrentOffsetKey on state_.output if there is a stream, that could be
+ // expensive, manually tracking what is flush keeps things faster so message serialization can
+ // check it.
+ return state_.bytesFlushed + state_.position;
+}
+
- (void)writeDoubleNoTag:(double)value {
GPBWriteRawLittleEndian64(&state_, GPBConvertDoubleToInt64(value));
}
@@ -886,6 +895,7 @@
if (written != (NSInteger)length) {
[NSException raise:GPBCodedOutputStreamException_WriteFailed format:@""];
}
+ state_.bytesFlushed += written;
}
}
}
diff --git a/objectivec/GPBMessage.h b/objectivec/GPBMessage.h
index 5b7ce0c..5d55df1 100644
--- a/objectivec/GPBMessage.h
+++ b/objectivec/GPBMessage.h
@@ -61,6 +61,12 @@
**/
extern NSString *const GPBErrorReasonKey;
+/**
+ * An exception name raised during serialization when the message would be
+ * larger than the 2GB limit.
+ **/
+extern NSString *const GPBMessageExceptionMessageTooLarge;
+
CF_EXTERN_C_END
/**
@@ -276,7 +282,25 @@
* unsuccessful.
**/
- (void)mergeFromData:(NSData *)data
- extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry;
+ extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
+ __attribute__((deprecated(
+ "Use -mergeFromData:extensionRegistry:error: instead, especaily if calling from Swift.")));
+
+/**
+ * Parses the given data as this message's class, and merges those values into
+ * this message.
+ *
+ * @param data The binary representation of the message to merge.
+ * @param extensionRegistry The extension registry to use to look up extensions.
+ * @param errorPtr An optional error pointer to fill in with a failure
+ * reason if the data can not be parsed. Will only be
+ * filled in if the data failed to be parsed.
+ *
+ * @return Boolean indicating success. errorPtr will only be fill in on failure.
+ **/
+- (BOOL)mergeFromData:(NSData *)data
+ extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
+ error:(NSError **)errorPtr;
/**
* Merges the fields from another message (of the same type) into this
@@ -293,6 +317,10 @@
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
*
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output;
@@ -302,6 +330,11 @@
* @param output The output stream into which to write the message.
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeToOutputStream:(NSOutputStream *)output;
@@ -312,6 +345,11 @@
* @param output The coded output stream into which to write the message.
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output;
@@ -322,6 +360,11 @@
* @param output The output stream into which to write the message.
*
* @note This can raise the GPBCodedOutputStreamException_* exceptions.
+ *
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
**/
- (void)writeDelimitedToOutputStream:(NSOutputStream *)output;
@@ -336,6 +379,11 @@
* @note In DEBUG ONLY, the message is also checked for all required field,
* if one is missing, nil will be returned.
*
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
+ *
* @return The binary representation of the message.
**/
- (nullable NSData *)data;
@@ -347,6 +395,11 @@
* @note This value is not cached, so if you are using it repeatedly, it is
* recommended to keep a local copy.
*
+ * @note The most common cause of this failing is from one thread calling this
+ * while another thread has a reference to this message or a message used
+ * within a field and that other thread mutating the message while this
+ * serialization is taking place.
+ *
* @return The binary representation of the size along with the message.
**/
- (NSData *)delimitedData;
diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m
index 3342179..a6bedeb 100644
--- a/objectivec/GPBMessage.m
+++ b/objectivec/GPBMessage.m
@@ -28,6 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#import <Foundation/Foundation.h>
#import "GPBMessage_PackagePrivate.h"
#import <objc/message.h>
@@ -46,6 +47,12 @@
#import "GPBUnknownFieldSet_PackagePrivate.h"
#import "GPBUtilities_PackagePrivate.h"
+// Returns a new instance that was automatically created by |autocreator| for
+// its field |field|.
+static GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, GPBMessage *autocreator,
+ GPBFieldDescriptor *field)
+ __attribute__((ns_returns_retained));
+
// Direct access is use for speed, to avoid even internally declaring things
// read/write, etc. The warning is enabled in the project to ensure code calling
// protos can turn on -Wdirect-ivar-access without issues.
@@ -58,6 +65,16 @@
static NSString *const kGPBDataCoderKey = @"GPBData";
+// Length-delimited has a max size of 2GB, and thus messages do also.
+// src/google/protobuf/message_lite also does this enforcement on the C++ side. Validation for
+// parsing is done with GPBCodedInputStream; but for messages, it is less checks to do it within
+// the message side since the input stream code calls these same bottlenecks.
+// https://protobuf.dev/programming-guides/encoding/#cheat-sheet
+static const size_t kMaximumMessageSize = 0x7fffffff;
+
+NSString *const GPBMessageExceptionMessageTooLarge =
+ GPBNSStringifySymbol(GPBMessageExceptionMessageTooLarge);
+
//
// PLEASE REMEMBER:
//
@@ -110,7 +127,7 @@
__attribute__((ns_returns_retained));
static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self);
-#ifdef DEBUG
+#if defined(DEBUG) && DEBUG
static NSError *MessageError(NSInteger code, NSDictionary *userInfo) {
return [NSError errorWithDomain:GPBMessageErrorDomain code:code userInfo:userInfo];
}
@@ -638,52 +655,93 @@
#endif // !defined(__clang_analyzer__)
-static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension,
- GPBMessage *messageToGetExtension,
- GPBCodedInputStream *input,
- id<GPBExtensionRegistry> extensionRegistry,
- GPBMessage *existingValue)
- __attribute__((ns_returns_retained));
-
-// Note that this returns a retained value intentionally.
-static id NewSingleValueFromInputStream(GPBExtensionDescriptor *extension,
- GPBMessage *messageToGetExtension,
- GPBCodedInputStream *input,
- id<GPBExtensionRegistry> extensionRegistry,
- GPBMessage *existingValue) {
+static void DecodeSingleValueFromInputStream(GPBExtensionDescriptor *extension,
+ GPBMessage *messageToGetExtension,
+ GPBCodedInputStream *input,
+ id<GPBExtensionRegistry> extensionRegistry,
+ BOOL isRepeated, GPBMessage *targetMessage) {
GPBExtensionDescription *description = extension->description_;
+#if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
+ if (GPBDataTypeIsMessage(description->dataType)) {
+ NSCAssert(targetMessage != nil, @"Internal error: must have a target message");
+ } else {
+ NSCAssert(targetMessage == nil, @"Internal error: should not have a target message");
+ }
+#endif
GPBCodedInputStreamState *state = &input->state_;
+ id nsValue;
switch (description->dataType) {
- case GPBDataTypeBool:
- return [[NSNumber alloc] initWithBool:GPBCodedInputStreamReadBool(state)];
- case GPBDataTypeFixed32:
- return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadFixed32(state)];
- case GPBDataTypeSFixed32:
- return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSFixed32(state)];
- case GPBDataTypeFloat:
- return [[NSNumber alloc] initWithFloat:GPBCodedInputStreamReadFloat(state)];
- case GPBDataTypeFixed64:
- return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadFixed64(state)];
- case GPBDataTypeSFixed64:
- return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSFixed64(state)];
- case GPBDataTypeDouble:
- return [[NSNumber alloc] initWithDouble:GPBCodedInputStreamReadDouble(state)];
- case GPBDataTypeInt32:
- return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadInt32(state)];
- case GPBDataTypeInt64:
- return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadInt64(state)];
- case GPBDataTypeSInt32:
- return [[NSNumber alloc] initWithInt:GPBCodedInputStreamReadSInt32(state)];
- case GPBDataTypeSInt64:
- return [[NSNumber alloc] initWithLongLong:GPBCodedInputStreamReadSInt64(state)];
- case GPBDataTypeUInt32:
- return [[NSNumber alloc] initWithUnsignedInt:GPBCodedInputStreamReadUInt32(state)];
- case GPBDataTypeUInt64:
- return [[NSNumber alloc] initWithUnsignedLongLong:GPBCodedInputStreamReadUInt64(state)];
+ case GPBDataTypeBool: {
+ BOOL value = GPBCodedInputStreamReadBool(state);
+ nsValue = [[NSNumber alloc] initWithBool:value];
+ break;
+ }
+ case GPBDataTypeFixed32: {
+ uint32_t value = GPBCodedInputStreamReadFixed32(state);
+ nsValue = [[NSNumber alloc] initWithUnsignedInt:value];
+ break;
+ }
+ case GPBDataTypeSFixed32: {
+ int32_t value = GPBCodedInputStreamReadSFixed32(state);
+ nsValue = [[NSNumber alloc] initWithInt:value];
+ break;
+ }
+ case GPBDataTypeFloat: {
+ float value = GPBCodedInputStreamReadFloat(state);
+ nsValue = [[NSNumber alloc] initWithFloat:value];
+ break;
+ }
+ case GPBDataTypeFixed64: {
+ uint64_t value = GPBCodedInputStreamReadFixed64(state);
+ nsValue = [[NSNumber alloc] initWithUnsignedLongLong:value];
+ break;
+ }
+ case GPBDataTypeSFixed64: {
+ int64_t value = GPBCodedInputStreamReadSFixed64(state);
+ nsValue = [[NSNumber alloc] initWithLongLong:value];
+ break;
+ }
+ case GPBDataTypeDouble: {
+ double value = GPBCodedInputStreamReadDouble(state);
+ nsValue = [[NSNumber alloc] initWithDouble:value];
+ break;
+ }
+ case GPBDataTypeInt32: {
+ int32_t value = GPBCodedInputStreamReadInt32(state);
+ nsValue = [[NSNumber alloc] initWithInt:value];
+ break;
+ }
+ case GPBDataTypeInt64: {
+ int64_t value = GPBCodedInputStreamReadInt64(state);
+ nsValue = [[NSNumber alloc] initWithLongLong:value];
+ break;
+ }
+ case GPBDataTypeSInt32: {
+ int32_t value = GPBCodedInputStreamReadSInt32(state);
+ nsValue = [[NSNumber alloc] initWithInt:value];
+ break;
+ }
+ case GPBDataTypeSInt64: {
+ int64_t value = GPBCodedInputStreamReadSInt64(state);
+ nsValue = [[NSNumber alloc] initWithLongLong:value];
+ break;
+ }
+ case GPBDataTypeUInt32: {
+ uint32_t value = GPBCodedInputStreamReadUInt32(state);
+ nsValue = [[NSNumber alloc] initWithUnsignedInt:value];
+ break;
+ }
+ case GPBDataTypeUInt64: {
+ uint64_t value = GPBCodedInputStreamReadUInt64(state);
+ nsValue = [[NSNumber alloc] initWithUnsignedLongLong:value];
+ break;
+ }
case GPBDataTypeBytes:
- return GPBCodedInputStreamReadRetainedBytes(state);
+ nsValue = GPBCodedInputStreamReadRetainedBytes(state);
+ break;
case GPBDataTypeString:
- return GPBCodedInputStreamReadRetainedString(state);
+ nsValue = GPBCodedInputStreamReadRetainedString(state);
+ break;
case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(&input->state_);
GPBEnumDescriptor *enumDescriptor = extension.enumDescriptor;
@@ -691,43 +749,44 @@
// will be considers not closed, so casing to the enum type for a switch
// could cause things to fall off the end of a switch.
if (!enumDescriptor.isClosed || enumDescriptor.enumVerifier(val)) {
- return [[NSNumber alloc] initWithInt:val];
+ nsValue = [[NSNumber alloc] initWithInt:val];
} else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(messageToGetExtension);
[unknownFields mergeVarintField:extension->description_->fieldNumber value:val];
- return nil;
+ nsValue = nil;
}
+ break;
}
case GPBDataTypeGroup:
case GPBDataTypeMessage: {
- GPBMessage *message;
- if (existingValue) {
- message = [existingValue retain];
- } else {
- GPBDescriptor *descriptor = [extension.msgClass descriptor];
- message = [[descriptor.messageClass alloc] init];
- }
-
if (description->dataType == GPBDataTypeGroup) {
[input readGroup:description->fieldNumber
- message:message
+ message:targetMessage
extensionRegistry:extensionRegistry];
} else {
// description->dataType == GPBDataTypeMessage
if (GPBExtensionIsWireFormat(description)) {
// For MessageSet fields the message length will have already been
// read.
- [message mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
+ [targetMessage mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
} else {
- [input readMessage:message extensionRegistry:extensionRegistry];
+ [input readMessage:targetMessage extensionRegistry:extensionRegistry];
}
}
-
- return message;
+ // Nothing to add below since the caller provided the message (and added it).
+ nsValue = nil;
+ break;
}
- }
+ } // switch
- return nil;
+ if (nsValue) {
+ if (isRepeated) {
+ [messageToGetExtension addExtension:extension value:nsValue];
+ } else {
+ [messageToGetExtension setExtension:extension value:nsValue];
+ }
+ [nsValue release];
+ }
}
static void ExtensionMergeFromInputStream(GPBExtensionDescriptor *extension, BOOL isPackedOnStream,
@@ -737,38 +796,45 @@
GPBExtensionDescription *description = extension->description_;
GPBCodedInputStreamState *state = &input->state_;
if (isPackedOnStream) {
+#if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
NSCAssert(GPBExtensionIsRepeated(description), @"How was it packed if it isn't repeated?");
+#endif
int32_t length = GPBCodedInputStreamReadInt32(state);
size_t limit = GPBCodedInputStreamPushLimit(state, length);
while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
- id value = NewSingleValueFromInputStream(extension, message, input, extensionRegistry, nil);
- if (value) {
- [message addExtension:extension value:value];
- [value release];
- }
+ DecodeSingleValueFromInputStream(extension, message, input, extensionRegistry,
+ /*isRepeated=*/YES, nil);
}
GPBCodedInputStreamPopLimit(state, limit);
} else {
- id existingValue = nil;
BOOL isRepeated = GPBExtensionIsRepeated(description);
- if (!isRepeated && GPBDataTypeIsMessage(description->dataType)) {
- existingValue = [message getExistingExtension:extension];
- }
- id value =
- NewSingleValueFromInputStream(extension, message, input, extensionRegistry, existingValue);
- if (value) {
+ GPBMessage *targetMessage = nil;
+ if (GPBDataTypeIsMessage(description->dataType)) {
+ // For messages/groups create the targetMessage out here and add it to the objects graph in
+ // advance, that way if DecodeSingleValueFromInputStream() throw for a parsing issue, the
+ // object won't be leaked.
if (isRepeated) {
- [message addExtension:extension value:value];
+ GPBDescriptor *descriptor = [extension.msgClass descriptor];
+ targetMessage = [[descriptor.messageClass alloc] init];
+ [message addExtension:extension value:targetMessage];
+ [targetMessage release];
} else {
- [message setExtension:extension value:value];
+ targetMessage = [message getExistingExtension:extension];
+ if (!targetMessage) {
+ GPBDescriptor *descriptor = [extension.msgClass descriptor];
+ targetMessage = [[descriptor.messageClass alloc] init];
+ [message setExtension:extension value:targetMessage];
+ [targetMessage release];
+ }
}
- [value release];
}
+ DecodeSingleValueFromInputStream(extension, message, input, extensionRegistry, isRepeated,
+ targetMessage);
}
}
-GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, GPBMessage *autocreator,
- GPBFieldDescriptor *field) {
+static GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, GPBMessage *autocreator,
+ GPBFieldDescriptor *field) {
GPBMessage *message = [[msgClass alloc] init];
message->autocreator_ = autocreator;
message->autocreatorField_ = [field retain];
@@ -964,27 +1030,18 @@
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
if ((self = [self init])) {
- @try {
- [self mergeFromData:data extensionRegistry:extensionRegistry];
- if (errorPtr) {
- *errorPtr = nil;
- }
- } @catch (NSException *exception) {
+ if (![self mergeFromData:data extensionRegistry:extensionRegistry error:errorPtr]) {
[self release];
self = nil;
- if (errorPtr) {
- *errorPtr = ErrorFromException(exception);
- }
- }
-#ifdef DEBUG
- if (self && !self.initialized) {
+#if defined(DEBUG) && DEBUG
+ } else if (!self.initialized) {
[self release];
self = nil;
if (errorPtr) {
*errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
}
- }
#endif
+ }
}
return self;
}
@@ -1005,7 +1062,7 @@
*errorPtr = ErrorFromException(exception);
}
}
-#ifdef DEBUG
+#if defined(DEBUG) && DEBUG
if (self && !self.initialized) {
[self release];
self = nil;
@@ -1298,24 +1355,34 @@
}
- (NSData *)data {
-#ifdef DEBUG
+#if defined(DEBUG) && DEBUG
if (!self.initialized) {
return nil;
}
#endif
- NSMutableData *data = [NSMutableData dataWithLength:[self serializedSize]];
+ size_t expectedSize = [self serializedSize];
+ if (expectedSize > kMaximumMessageSize) {
+ return nil;
+ }
+ NSMutableData *data = [NSMutableData dataWithLength:expectedSize];
GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithData:data];
@try {
[self writeToCodedOutputStream:stream];
} @catch (NSException *exception) {
- // This really shouldn't happen. The only way writeToCodedOutputStream:
- // could throw is if something in the library has a bug and the
- // serializedSize was wrong.
-#ifdef DEBUG
+ // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
+ // failed to match between computing the size and writing out the bytes. However, the more
+ // common cause is while one thread was writing out the data, some other thread had a reference
+ // to this message or a message used as a nested field, and that other thread mutated that
+ // message, causing the pre computed serializedSize to no longer match the final size after
+ // serialization. It is not safe to mutate a message while accessing it from another thread.
+#if defined(DEBUG) && DEBUG
NSLog(@"%@: Internal exception while building message data: %@", [self class], exception);
#endif
data = nil;
}
+#if defined(DEBUG) && DEBUG
+ NSAssert(!data || [stream bytesWritten] == expectedSize, @"Internal error within the library");
+#endif
[stream release];
return data;
}
@@ -1328,10 +1395,13 @@
@try {
[self writeDelimitedToCodedOutputStream:stream];
} @catch (NSException *exception) {
- // This really shouldn't happen. The only way writeToCodedOutputStream:
- // could throw is if something in the library has a bug and the
- // serializedSize was wrong.
-#ifdef DEBUG
+ // This really shouldn't happen. Normally, this could mean there was a bug in the library and it
+ // failed to match between computing the size and writing out the bytes. However, the more
+ // common cause is while one thread was writing out the data, some other thread had a reference
+ // to this message or a message used as a nested field, and that other thread mutated that
+ // message, causing the pre computed serializedSize to no longer match the final size after
+ // serialization. It is not safe to mutate a message while accessing it from another thread.
+#if defined(DEBUG) && DEBUG
NSLog(@"%@: Internal exception while building message delimitedData: %@", [self class],
exception);
#endif
@@ -1344,8 +1414,16 @@
- (void)writeToOutputStream:(NSOutputStream *)output {
GPBCodedOutputStream *stream = [[GPBCodedOutputStream alloc] initWithOutputStream:output];
- [self writeToCodedOutputStream:stream];
- [stream release];
+ @try {
+ [self writeToCodedOutputStream:stream];
+ size_t bytesWritten = [stream bytesWritten];
+ if (bytesWritten > kMaximumMessageSize) {
+ [NSException raise:GPBMessageExceptionMessageTooLarge
+ format:@"Message would have been %zu bytes", bytesWritten];
+ }
+ } @finally {
+ [stream release];
+ }
}
- (void)writeToCodedOutputStream:(GPBCodedOutputStream *)output {
@@ -1379,13 +1457,28 @@
- (void)writeDelimitedToOutputStream:(NSOutputStream *)output {
GPBCodedOutputStream *codedOutput = [[GPBCodedOutputStream alloc] initWithOutputStream:output];
- [self writeDelimitedToCodedOutputStream:codedOutput];
- [codedOutput release];
+ @try {
+ [self writeDelimitedToCodedOutputStream:codedOutput];
+ } @finally {
+ [codedOutput release];
+ }
}
- (void)writeDelimitedToCodedOutputStream:(GPBCodedOutputStream *)output {
- [output writeRawVarintSizeTAs32:[self serializedSize]];
+ size_t expectedSize = [self serializedSize];
+ if (expectedSize > kMaximumMessageSize) {
+ [NSException raise:GPBMessageExceptionMessageTooLarge
+ format:@"Message would have been %zu bytes", expectedSize];
+ }
+ [output writeRawVarintSizeTAs32:expectedSize];
+#if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
+ size_t initialSize = [output bytesWritten];
+#endif
[self writeToCodedOutputStream:output];
+#if defined(DEBUG) && DEBUG && !defined(NS_BLOCK_ASSERTIONS)
+ NSAssert(([output bytesWritten] - initialSize) == expectedSize,
+ @"Internal error within the library");
+#endif
}
- (void)writeField:(GPBFieldDescriptor *)field toCodedOutputStream:(GPBCodedOutputStream *)output {
@@ -1821,7 +1914,7 @@
//%PDDM-EXPAND-END (18 expansions)
-// clang-format off
+ // clang-format on
}
}
@@ -1848,8 +1941,7 @@
value = [autocreatedExtensionMap_ objectForKey:extension];
if (!value) {
// Auto create the message extensions to match normal fields.
- value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self,
- extension);
+ value = CreateMessageWithAutocreatorForExtension(extension.msgClass, self, extension);
if (autocreatedExtensionMap_ == nil) {
autocreatedExtensionMap_ = [[NSMutableDictionary alloc] init];
@@ -1926,8 +2018,7 @@
GPBExtensionDescriptor *descriptor = extension;
if (GPBExtensionIsMessage(descriptor) && !descriptor.isRepeated) {
- GPBMessage *autocreatedValue =
- [[autocreatedExtensionMap_ objectForKey:extension] retain];
+ GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
// Must remove from the map before calling GPBClearMessageAutocreator() so
// that GPBClearMessageAutocreator() knows its safe to clear.
[autocreatedExtensionMap_ removeObjectForKey:extension];
@@ -1959,9 +2050,7 @@
GPBBecomeVisibleToAutocreator(self);
}
-- (void)setExtension:(GPBExtensionDescriptor *)extension
- index:(NSUInteger)idx
- value:(id)value {
+- (void)setExtension:(GPBExtensionDescriptor *)extension index:(NSUInteger)idx value:(id)value {
CheckExtension(self, extension);
if (!extension.repeated) {
@@ -1991,28 +2080,35 @@
#pragma mark - mergeFrom
-- (void)mergeFromData:(NSData *)data
- extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
+- (void)mergeFromData:(NSData *)data extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
- [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
- [input checkLastTagWas:0];
- [input release];
+ @try {
+ [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
+ [input checkLastTagWas:0];
+ } @finally {
+ [input release];
+ }
}
-#pragma mark - mergeDelimitedFrom
-
-- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
- extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry {
- GPBCodedInputStreamState *state = &input->state_;
- if (GPBCodedInputStreamIsAtEnd(state)) {
- return;
+- (BOOL)mergeFromData:(NSData *)data
+ extensionRegistry:(nullable id<GPBExtensionRegistry>)extensionRegistry
+ error:(NSError **)errorPtr {
+ GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
+ @try {
+ [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry];
+ [input checkLastTagWas:0];
+ if (errorPtr) {
+ *errorPtr = nil;
+ }
+ } @catch (NSException *exception) {
+ [input release];
+ if (errorPtr) {
+ *errorPtr = ErrorFromException(exception);
+ }
+ return NO;
}
- NSData *data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
- if (data == nil) {
- return;
- }
- [self mergeFromData:data extensionRegistry:extensionRegistry];
- [data release];
+ [input release];
+ return YES;
}
#pragma mark - Parse From Data Support
@@ -2024,49 +2120,53 @@
+ (instancetype)parseFromData:(NSData *)data
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
- return [[[self alloc] initWithData:data
- extensionRegistry:extensionRegistry
+ return [[[self alloc] initWithData:data extensionRegistry:extensionRegistry
error:errorPtr] autorelease];
}
+ (instancetype)parseFromCodedInputStream:(GPBCodedInputStream *)input
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
- return
- [[[self alloc] initWithCodedInputStream:input
- extensionRegistry:extensionRegistry
- error:errorPtr] autorelease];
+ return [[[self alloc] initWithCodedInputStream:input
+ extensionRegistry:extensionRegistry
+ error:errorPtr] autorelease];
}
#pragma mark - Parse Delimited From Data Support
+ (instancetype)parseDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
- extensionRegistry:
- (id<GPBExtensionRegistry>)extensionRegistry
+ extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry
error:(NSError **)errorPtr {
- GPBMessage *message = [[[self alloc] init] autorelease];
- @try {
- [message mergeDelimitedFromCodedInputStream:input
- extensionRegistry:extensionRegistry];
- if (errorPtr) {
- *errorPtr = nil;
- }
+ GPBCodedInputStreamState *state = &input->state_;
+ // This doesn't completely match the C++, but if the stream has nothing, just make an empty
+ // message.
+ if (GPBCodedInputStreamIsAtEnd(state)) {
+ return [[[self alloc] init] autorelease];
}
- @catch (NSException *exception) {
- message = nil;
+
+ // Manually extract the data and parse it. If we read a varint and push a limit, that consumes
+ // some of the recursion buffer which isn't correct, it also can result in a change in error
+ // codes for attempts to parse partial data; and there are projects sensitive to that, so this
+ // maintains existing error flows.
+
+ // Extract the data, but in a "no copy" mode since we will immediately parse it so this NSData
+ // is transient.
+ NSData *data = nil;
+ @try {
+ data = GPBCodedInputStreamReadRetainedBytesNoCopy(state);
+ } @catch (NSException *exception) {
if (errorPtr) {
*errorPtr = ErrorFromException(exception);
}
+ return nil;
}
-#ifdef DEBUG
- if (message && !message.initialized) {
- message = nil;
- if (errorPtr) {
- *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil);
- }
+
+ GPBMessage *result = [self parseFromData:data extensionRegistry:extensionRegistry error:errorPtr];
+ [data release];
+ if (result && errorPtr) {
+ *errorPtr = nil;
}
-#endif
- return message;
+ return result;
}
#pragma mark - Unknown Field Support
@@ -2098,12 +2198,10 @@
if (tag == GPBWireFormatMessageSetTypeIdTag) {
typeId = GPBCodedInputStreamReadUInt32(state);
if (typeId != 0) {
- extension = [extensionRegistry extensionForDescriptor:[self descriptor]
- fieldNumber:typeId];
+ extension = [extensionRegistry extensionForDescriptor:[self descriptor] fieldNumber:typeId];
}
} else if (tag == GPBWireFormatMessageSetMessageTag) {
- rawBytes =
- [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
+ rawBytes = [GPBCodedInputStreamReadRetainedBytesNoCopy(state) autorelease];
} else {
if (![input skipField:tag]) {
break;
@@ -2115,14 +2213,13 @@
if (rawBytes != nil && typeId != 0) {
if (extension != nil) {
- GPBCodedInputStream *newInput =
- [[GPBCodedInputStream alloc] initWithData:rawBytes];
- ExtensionMergeFromInputStream(extension,
- extension.packable,
- newInput,
- extensionRegistry,
- self);
- [newInput release];
+ GPBCodedInputStream *newInput = [[GPBCodedInputStream alloc] initWithData:rawBytes];
+ @try {
+ ExtensionMergeFromInputStream(extension, extension.packable, newInput, extensionRegistry,
+ self);
+ } @finally {
+ [newInput release];
+ }
} else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
// rawBytes was created via a NoCopy, so it can be reusing a
@@ -2142,9 +2239,8 @@
int32_t fieldNumber = GPBWireFormatGetTagFieldNumber(tag);
GPBDescriptor *descriptor = [self descriptor];
- GPBExtensionDescriptor *extension =
- [extensionRegistry extensionForDescriptor:descriptor
- fieldNumber:fieldNumber];
+ GPBExtensionDescriptor *extension = [extensionRegistry extensionForDescriptor:descriptor
+ fieldNumber:fieldNumber];
if (extension == nil) {
if (descriptor.wireFormat && GPBWireFormatMessageSetItemTag == tag) {
[self parseMessageSet:input extensionRegistry:extensionRegistry];
@@ -2152,23 +2248,14 @@
}
} else {
if (extension.wireType == wireType) {
- ExtensionMergeFromInputStream(extension,
- extension.packable,
- input,
- extensionRegistry,
- self);
+ ExtensionMergeFromInputStream(extension, extension.packable, input, extensionRegistry, self);
return YES;
}
// Primitive, repeated types can be packed on unpacked on the wire, and are
// parsed either way.
- if ([extension isRepeated] &&
- !GPBDataTypeIsObject(extension->description_->dataType) &&
+ if ([extension isRepeated] && !GPBDataTypeIsObject(extension->description_->dataType) &&
(extension.alternateWireType == wireType)) {
- ExtensionMergeFromInputStream(extension,
- !extension.packable,
- input,
- extensionRegistry,
- self);
+ ExtensionMergeFromInputStream(extension, !extension.packable, input, extensionRegistry, self);
return YES;
}
}
@@ -2187,38 +2274,38 @@
#pragma mark - MergeFromCodedInputStream Support
-static void MergeSingleFieldFromCodedInputStream(
- GPBMessage *self, GPBFieldDescriptor *field,
- GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
+static void MergeSingleFieldFromCodedInputStream(GPBMessage *self, GPBFieldDescriptor *field,
+ GPBCodedInputStream *input,
+ id<GPBExtensionRegistry> extensionRegistry) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
-#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
- case GPBDataType##NAME: { \
- TYPE val = GPBCodedInputStreamRead##NAME(&input->state_); \
- GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val); \
- break; \
- }
-#define CASE_SINGLE_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \
- GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val); \
- break; \
- }
- CASE_SINGLE_POD(Bool, BOOL, Bool)
- CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
- CASE_SINGLE_POD(SFixed32, int32_t, Int32)
- CASE_SINGLE_POD(Float, float, Float)
- CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
- CASE_SINGLE_POD(SFixed64, int64_t, Int64)
- CASE_SINGLE_POD(Double, double, Double)
- CASE_SINGLE_POD(Int32, int32_t, Int32)
- CASE_SINGLE_POD(Int64, int64_t, Int64)
- CASE_SINGLE_POD(SInt32, int32_t, Int32)
- CASE_SINGLE_POD(SInt64, int64_t, Int64)
- CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
- CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
- CASE_SINGLE_OBJECT(Bytes)
- CASE_SINGLE_OBJECT(String)
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
+ case GPBDataType##NAME: { \
+ TYPE val = GPBCodedInputStreamRead##NAME(&input->state_); \
+ GPBSet##FUNC_TYPE##IvarWithFieldPrivate(self, field, val); \
+ break; \
+ }
+#define CASE_SINGLE_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ id val = GPBCodedInputStreamReadRetained##NAME(&input->state_); \
+ GPBSetRetainedObjectIvarWithFieldPrivate(self, field, val); \
+ break; \
+ }
+ CASE_SINGLE_POD(Bool, BOOL, Bool)
+ CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+ CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+ CASE_SINGLE_POD(Float, float, Float)
+ CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+ CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+ CASE_SINGLE_POD(Double, double, Double)
+ CASE_SINGLE_POD(Int32, int32_t, Int32)
+ CASE_SINGLE_POD(Int64, int64_t, Int64)
+ CASE_SINGLE_POD(SInt32, int32_t, Int32)
+ CASE_SINGLE_POD(SInt64, int64_t, Int64)
+ CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+ CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+ CASE_SINGLE_OBJECT(Bytes)
+ CASE_SINGLE_OBJECT(String)
#undef CASE_SINGLE_POD
#undef CASE_SINGLE_OBJECT
@@ -2226,13 +2313,12 @@
if (GPBGetHasIvarField(self, field)) {
// GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
// check again.
- GPBMessage *message =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
[input readMessage:message extensionRegistry:extensionRegistry];
} else {
GPBMessage *message = [[field.msgClass alloc] init];
- [input readMessage:message extensionRegistry:extensionRegistry];
GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
+ [input readMessage:message extensionRegistry:extensionRegistry];
}
break;
}
@@ -2241,17 +2327,12 @@
if (GPBGetHasIvarField(self, field)) {
// GPBGetObjectIvarWithFieldNoAutocreate() avoids doing the has
// check again.
- GPBMessage *message =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
- [input readGroup:GPBFieldNumber(field)
- message:message
- extensionRegistry:extensionRegistry];
+ GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
} else {
GPBMessage *message = [[field.msgClass alloc] init];
- [input readGroup:GPBFieldNumber(field)
- message:message
- extensionRegistry:extensionRegistry];
GPBSetRetainedObjectIvarWithFieldPrivate(self, field, message);
+ [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
}
break;
}
@@ -2268,9 +2349,9 @@
} // switch
}
-static void MergeRepeatedPackedFieldFromCodedInputStream(
- GPBMessage *self, GPBFieldDescriptor *field,
- GPBCodedInputStream *input) {
+static void MergeRepeatedPackedFieldFromCodedInputStream(GPBMessage *self,
+ GPBFieldDescriptor *field,
+ GPBCodedInputStream *input) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
GPBCodedInputStreamState *state = &input->state_;
id genericArray = GetOrCreateArrayIvarWithField(self, field);
@@ -2278,25 +2359,25 @@
size_t limit = GPBCodedInputStreamPushLimit(state, length);
while (GPBCodedInputStreamBytesUntilLimit(state) > 0) {
switch (fieldDataType) {
-#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
- case GPBDataType##NAME: { \
- TYPE val = GPBCodedInputStreamRead##NAME(state); \
- [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
- break; \
- }
- CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
- CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
- CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
- CASE_REPEATED_PACKED_POD(Float, float, Float)
- CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
- CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
- CASE_REPEATED_PACKED_POD(Double, double, Double)
- CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
- CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
- CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
- CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
- CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
- CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
+#define CASE_REPEATED_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
+ case GPBDataType##NAME: { \
+ TYPE val = GPBCodedInputStreamRead##NAME(state); \
+ [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
+ break; \
+ }
+ CASE_REPEATED_PACKED_POD(Bool, BOOL, Bool)
+ CASE_REPEATED_PACKED_POD(Fixed32, uint32_t, UInt32)
+ CASE_REPEATED_PACKED_POD(SFixed32, int32_t, Int32)
+ CASE_REPEATED_PACKED_POD(Float, float, Float)
+ CASE_REPEATED_PACKED_POD(Fixed64, uint64_t, UInt64)
+ CASE_REPEATED_PACKED_POD(SFixed64, int64_t, Int64)
+ CASE_REPEATED_PACKED_POD(Double, double, Double)
+ CASE_REPEATED_PACKED_POD(Int32, int32_t, Int32)
+ CASE_REPEATED_PACKED_POD(Int64, int64_t, Int64)
+ CASE_REPEATED_PACKED_POD(SInt32, int32_t, Int32)
+ CASE_REPEATED_PACKED_POD(SInt64, int64_t, Int64)
+ CASE_REPEATED_PACKED_POD(UInt32, uint32_t, UInt32)
+ CASE_REPEATED_PACKED_POD(UInt64, uint64_t, UInt64)
#undef CASE_REPEATED_PACKED_POD
case GPBDataTypeBytes:
@@ -2309,7 +2390,7 @@
case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(state);
if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
- [(GPBEnumArray*)genericArray addRawValue:val];
+ [(GPBEnumArray *)genericArray addRawValue:val];
} else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
[unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
@@ -2317,66 +2398,68 @@
break;
}
} // switch
- } // while(BytesUntilLimit() > 0)
+ } // while(BytesUntilLimit() > 0)
GPBCodedInputStreamPopLimit(state, limit);
}
static void MergeRepeatedNotPackedFieldFromCodedInputStream(
- GPBMessage *self, GPBFieldDescriptor *field,
- GPBCodedInputStream *input, id<GPBExtensionRegistry>extensionRegistry) {
+ GPBMessage *self, GPBFieldDescriptor *field, GPBCodedInputStream *input,
+ id<GPBExtensionRegistry> extensionRegistry) {
GPBCodedInputStreamState *state = &input->state_;
id genericArray = GetOrCreateArrayIvarWithField(self, field);
switch (GPBGetFieldDataType(field)) {
#define CASE_REPEATED_NOT_PACKED_POD(NAME, TYPE, ARRAY_TYPE) \
- case GPBDataType##NAME: { \
- TYPE val = GPBCodedInputStreamRead##NAME(state); \
- [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
- break; \
- }
-#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- id val = GPBCodedInputStreamReadRetained##NAME(state); \
- [(NSMutableArray*)genericArray addObject:val]; \
- [val release]; \
- break; \
- }
- CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
- CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
- CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
- CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
- CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
- CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
- CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
- CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
- CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
- CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
- CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
- CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
- CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
- CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
- CASE_REPEATED_NOT_PACKED_OBJECT(String)
+ case GPBDataType##NAME: { \
+ TYPE val = GPBCodedInputStreamRead##NAME(state); \
+ [(GPB##ARRAY_TYPE##Array *)genericArray addValue:val]; \
+ break; \
+ }
+#define CASE_REPEATED_NOT_PACKED_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ id val = GPBCodedInputStreamReadRetained##NAME(state); \
+ [(NSMutableArray *)genericArray addObject:val]; \
+ [val release]; \
+ break; \
+ }
+ CASE_REPEATED_NOT_PACKED_POD(Bool, BOOL, Bool)
+ CASE_REPEATED_NOT_PACKED_POD(Fixed32, uint32_t, UInt32)
+ CASE_REPEATED_NOT_PACKED_POD(SFixed32, int32_t, Int32)
+ CASE_REPEATED_NOT_PACKED_POD(Float, float, Float)
+ CASE_REPEATED_NOT_PACKED_POD(Fixed64, uint64_t, UInt64)
+ CASE_REPEATED_NOT_PACKED_POD(SFixed64, int64_t, Int64)
+ CASE_REPEATED_NOT_PACKED_POD(Double, double, Double)
+ CASE_REPEATED_NOT_PACKED_POD(Int32, int32_t, Int32)
+ CASE_REPEATED_NOT_PACKED_POD(Int64, int64_t, Int64)
+ CASE_REPEATED_NOT_PACKED_POD(SInt32, int32_t, Int32)
+ CASE_REPEATED_NOT_PACKED_POD(SInt64, int64_t, Int64)
+ CASE_REPEATED_NOT_PACKED_POD(UInt32, uint32_t, UInt32)
+ CASE_REPEATED_NOT_PACKED_POD(UInt64, uint64_t, UInt64)
+ CASE_REPEATED_NOT_PACKED_OBJECT(Bytes)
+ CASE_REPEATED_NOT_PACKED_OBJECT(String)
#undef CASE_REPEATED_NOT_PACKED_POD
#undef CASE_NOT_PACKED_OBJECT
case GPBDataTypeMessage: {
GPBMessage *message = [[field.msgClass alloc] init];
- [input readMessage:message extensionRegistry:extensionRegistry];
- [(NSMutableArray*)genericArray addObject:message];
+ [(NSMutableArray *)genericArray addObject:message];
+ // The array will now retain message, so go ahead and release it in case
+ // -readMessage:extensionRegistry: throws so it won't be leaked.
[message release];
+ [input readMessage:message extensionRegistry:extensionRegistry];
break;
}
case GPBDataTypeGroup: {
GPBMessage *message = [[field.msgClass alloc] init];
- [input readGroup:GPBFieldNumber(field)
- message:message
- extensionRegistry:extensionRegistry];
- [(NSMutableArray*)genericArray addObject:message];
+ [(NSMutableArray *)genericArray addObject:message];
+ // The array will now retain message, so go ahead and release it in case
+ // -readGroup:extensionRegistry: throws so it won't be leaked.
[message release];
+ [input readGroup:GPBFieldNumber(field) message:message extensionRegistry:extensionRegistry];
break;
}
case GPBDataTypeEnum: {
int32_t val = GPBCodedInputStreamReadEnum(state);
if (!GPBFieldIsClosedEnum(field) || [field isValidEnumValue:val]) {
- [(GPBEnumArray*)genericArray addRawValue:val];
+ [(GPBEnumArray *)genericArray addRawValue:val];
} else {
GPBUnknownFieldSet *unknownFields = GetOrMakeUnknownFields(self);
[unknownFields mergeVarintField:GPBFieldNumber(field) value:val];
@@ -2406,30 +2489,28 @@
if (GPBFieldTag(fieldDescriptor) == tag) {
GPBFieldType fieldType = fieldDescriptor.fieldType;
if (fieldType == GPBFieldTypeSingle) {
- MergeSingleFieldFromCodedInputStream(self, fieldDescriptor,
- input, extensionRegistry);
+ MergeSingleFieldFromCodedInputStream(self, fieldDescriptor, input, extensionRegistry);
// Well formed protos will only have a single field once, advance
// the starting index to the next field.
startingIndex += 1;
} else if (fieldType == GPBFieldTypeRepeated) {
if (fieldDescriptor.isPackable) {
- MergeRepeatedPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input);
+ MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
// Well formed protos will only have a repeated field that is
// packed once, advance the starting index to the next field.
startingIndex += 1;
} else {
- MergeRepeatedNotPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input, extensionRegistry);
+ MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
+ extensionRegistry);
}
} else { // fieldType == GPBFieldTypeMap
// GPB*Dictionary or NSDictionary, exact type doesn't matter at this
// point.
id map = GetOrCreateMapIvarWithField(self, fieldDescriptor);
[input readMapEntry:map
- extensionRegistry:extensionRegistry
- field:fieldDescriptor
- parentMessage:self];
+ extensionRegistry:extensionRegistry
+ field:fieldDescriptor
+ parentMessage:self];
}
merged = YES;
break;
@@ -2450,14 +2531,13 @@
(GPBFieldAlternateTag(fieldDescriptor) == tag)) {
BOOL alternateIsPacked = !fieldDescriptor.isPackable;
if (alternateIsPacked) {
- MergeRepeatedPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input);
+ MergeRepeatedPackedFieldFromCodedInputStream(self, fieldDescriptor, input);
// Well formed protos will only have a repeated field that is
// packed once, advance the starting index to the next field.
startingIndex += 1;
} else {
- MergeRepeatedNotPackedFieldFromCodedInputStream(
- self, fieldDescriptor, input, extensionRegistry);
+ MergeRepeatedNotPackedFieldFromCodedInputStream(self, fieldDescriptor, input,
+ extensionRegistry);
}
merged = YES;
break;
@@ -2472,9 +2552,7 @@
// zero signals EOF / limit reached
return;
} else {
- if (![self parseUnknownField:input
- extensionRegistry:extensionRegistry
- tag:tag]) {
+ if (![self parseUnknownField:input extensionRegistry:extensionRegistry tag:tag]) {
// it's an endgroup tag
return;
}
@@ -2489,8 +2567,7 @@
- (void)mergeFrom:(GPBMessage *)other {
Class selfClass = [self class];
Class otherClass = [other class];
- if (!([selfClass isSubclassOfClass:otherClass] ||
- [otherClass isSubclassOfClass:selfClass])) {
+ if (!([selfClass isSubclassOfClass:otherClass] || [otherClass isSubclassOfClass:selfClass])) {
[NSException raise:NSInvalidArgumentException
format:@"Classes must match %@ != %@", selfClass, otherClass];
}
@@ -2512,39 +2589,32 @@
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
case GPBDataTypeBool:
- GPBSetBoolIvarWithFieldPrivate(
- self, field, GPBGetMessageBoolField(other, field));
+ GPBSetBoolIvarWithFieldPrivate(self, field, GPBGetMessageBoolField(other, field));
break;
case GPBDataTypeSFixed32:
case GPBDataTypeEnum:
case GPBDataTypeInt32:
case GPBDataTypeSInt32:
- GPBSetInt32IvarWithFieldPrivate(
- self, field, GPBGetMessageInt32Field(other, field));
+ GPBSetInt32IvarWithFieldPrivate(self, field, GPBGetMessageInt32Field(other, field));
break;
case GPBDataTypeFixed32:
case GPBDataTypeUInt32:
- GPBSetUInt32IvarWithFieldPrivate(
- self, field, GPBGetMessageUInt32Field(other, field));
+ GPBSetUInt32IvarWithFieldPrivate(self, field, GPBGetMessageUInt32Field(other, field));
break;
case GPBDataTypeSFixed64:
case GPBDataTypeInt64:
case GPBDataTypeSInt64:
- GPBSetInt64IvarWithFieldPrivate(
- self, field, GPBGetMessageInt64Field(other, field));
+ GPBSetInt64IvarWithFieldPrivate(self, field, GPBGetMessageInt64Field(other, field));
break;
case GPBDataTypeFixed64:
case GPBDataTypeUInt64:
- GPBSetUInt64IvarWithFieldPrivate(
- self, field, GPBGetMessageUInt64Field(other, field));
+ GPBSetUInt64IvarWithFieldPrivate(self, field, GPBGetMessageUInt64Field(other, field));
break;
case GPBDataTypeFloat:
- GPBSetFloatIvarWithFieldPrivate(
- self, field, GPBGetMessageFloatField(other, field));
+ GPBSetFloatIvarWithFieldPrivate(self, field, GPBGetMessageFloatField(other, field));
break;
case GPBDataTypeDouble:
- GPBSetDoubleIvarWithFieldPrivate(
- self, field, GPBGetMessageDoubleField(other, field));
+ GPBSetDoubleIvarWithFieldPrivate(self, field, GPBGetMessageDoubleField(other, field));
break;
case GPBDataTypeBytes:
case GPBDataTypeString: {
@@ -2556,8 +2626,7 @@
case GPBDataTypeGroup: {
id otherVal = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
if (GPBGetHasIvar(self, hasIndex, fieldNumber)) {
- GPBMessage *message =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ GPBMessage *message = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
[message mergeFrom:otherVal];
} else {
GPBMessage *message = [otherVal copy];
@@ -2565,27 +2634,23 @@
}
break;
}
- } // switch()
+ } // switch()
} else if (fieldType == GPBFieldTypeRepeated) {
// In the case of a list, they need to be appended, and there is no
// _hasIvar to worry about setting.
- id otherArray =
- GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+ id otherArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
if (otherArray) {
GPBDataType fieldDataType = field->description_->dataType;
if (GPBDataTypeIsObject(fieldDataType)) {
- NSMutableArray *resultArray =
- GetOrCreateArrayIvarWithField(self, field);
+ NSMutableArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
[resultArray addObjectsFromArray:otherArray];
} else if (fieldDataType == GPBDataTypeEnum) {
- GPBEnumArray *resultArray =
- GetOrCreateArrayIvarWithField(self, field);
+ GPBEnumArray *resultArray = GetOrCreateArrayIvarWithField(self, field);
[resultArray addRawValuesFromArray:otherArray];
} else {
// The array type doesn't matter, that all implement
// -addValuesFromArray:.
- GPBInt32Array *resultArray =
- GetOrCreateArrayIvarWithField(self, field);
+ GPBInt32Array *resultArray = GetOrCreateArrayIvarWithField(self, field);
[resultArray addValuesFromArray:otherArray];
}
}
@@ -2596,27 +2661,23 @@
if (otherDict) {
GPBDataType keyDataType = field.mapKeyDataType;
GPBDataType valueDataType = field->description_->dataType;
- if (GPBDataTypeIsObject(keyDataType) &&
- GPBDataTypeIsObject(valueDataType)) {
- NSMutableDictionary *resultDict =
- GetOrCreateMapIvarWithField(self, field);
+ if (GPBDataTypeIsObject(keyDataType) && GPBDataTypeIsObject(valueDataType)) {
+ NSMutableDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
[resultDict addEntriesFromDictionary:otherDict];
} else if (valueDataType == GPBDataTypeEnum) {
// The exact type doesn't matter, just need to know it is a
// GPB*EnumDictionary.
- GPBInt32EnumDictionary *resultDict =
- GetOrCreateMapIvarWithField(self, field);
+ GPBInt32EnumDictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
[resultDict addRawEntriesFromDictionary:otherDict];
} else {
// The exact type doesn't matter, they all implement
// -addEntriesFromDictionary:.
- GPBInt32Int32Dictionary *resultDict =
- GetOrCreateMapIvarWithField(self, field);
+ GPBInt32Int32Dictionary *resultDict = GetOrCreateMapIvarWithField(self, field);
[resultDict addEntriesFromDictionary:otherDict];
}
}
} // if (fieldType)..else if...else
- } // for(fields)
+ } // for(fields)
// Unknown fields.
if (!unknownFields_) {
@@ -2632,8 +2693,7 @@
}
if (extensionMap_ == nil) {
- extensionMap_ =
- CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
+ extensionMap_ = CloneExtensionMap(other->extensionMap_, NSZoneFromPointer(self));
} else {
for (GPBExtensionDescriptor *extension in other->extensionMap_) {
id otherValue = [other->extensionMap_ objectForKey:extension];
@@ -2671,8 +2731,7 @@
}
if (isMessageExtension && !extension.isRepeated) {
- GPBMessage *autocreatedValue =
- [[autocreatedExtensionMap_ objectForKey:extension] retain];
+ GPBMessage *autocreatedValue = [[autocreatedExtensionMap_ objectForKey:extension] retain];
// Must remove from the map before calling GPBClearMessageAutocreator()
// so that GPBClearMessageAutocreator() knows its safe to clear.
[autocreatedExtensionMap_ removeObjectForKey:extension];
@@ -2706,10 +2765,8 @@
// NOTE: These are NSArray/GPB*Array or NSDictionary/GPB*Dictionary, but
// the type doesn't really matter as the objects all support -count and
// -isEqual:.
- NSArray *resultMapOrArray =
- GPBGetObjectIvarWithFieldNoAutocreate(self, field);
- NSArray *otherMapOrArray =
- GPBGetObjectIvarWithFieldNoAutocreate(other, field);
+ NSArray *resultMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(self, field);
+ NSArray *otherMapOrArray = GPBGetObjectIvarWithFieldNoAutocreate(other, field);
// nil and empty are equal
if (resultMapOrArray.count != 0 || otherMapOrArray.count != 0) {
if (![resultMapOrArray isEqual:otherMapOrArray]) {
@@ -2787,9 +2844,9 @@
}
break;
}
- } // switch()
- } // if(mapOrArray)...else
- } // for(fields)
+ } // switch()
+ } // if(mapOrArray)...else
+ } // for(fields)
// nil and empty are equal
if (extensionMap_.count != 0 || otherMsg->extensionMap_.count != 0) {
@@ -2800,8 +2857,7 @@
// nil and empty are equal
GPBUnknownFieldSet *otherUnknowns = otherMsg->unknownFields_;
- if ([unknownFields_ countOfFields] != 0 ||
- [otherUnknowns countOfFields] != 0) {
+ if ([unknownFields_ countOfFields] != 0 || [otherUnknowns countOfFields] != 0) {
if (![unknownFields_ isEqual:otherUnknowns]) {
return NO;
}
@@ -2904,7 +2960,7 @@
result = prime * result + (NSUInteger)[[*valPtr class] descriptor];
break;
}
- } // switch()
+ } // switch()
}
}
@@ -2917,8 +2973,8 @@
- (NSString *)description {
NSString *textFormat = GPBTextFormatForMessage(self, @" ");
- NSString *description = [NSString
- stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
+ NSString *description =
+ [NSString stringWithFormat:@"<%@ %p>: {\n%@}", [self class], self, textFormat];
return description;
}
@@ -2956,44 +3012,43 @@
uint32_t fieldNumber = GPBFieldNumber(fieldDescriptor);
switch (fieldDataType) {
-#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
- case GPBDataType##NAME: { \
- TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
- result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
- break; \
- }
-#define CASE_SINGLE_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
- result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
- break; \
- }
- CASE_SINGLE_POD(Bool, BOOL, Bool)
- CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
- CASE_SINGLE_POD(SFixed32, int32_t, Int32)
- CASE_SINGLE_POD(Float, float, Float)
- CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
- CASE_SINGLE_POD(SFixed64, int64_t, Int64)
- CASE_SINGLE_POD(Double, double, Double)
- CASE_SINGLE_POD(Int32, int32_t, Int32)
- CASE_SINGLE_POD(Int64, int64_t, Int64)
- CASE_SINGLE_POD(SInt32, int32_t, Int32)
- CASE_SINGLE_POD(SInt64, int64_t, Int64)
- CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
- CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
- CASE_SINGLE_OBJECT(Bytes)
- CASE_SINGLE_OBJECT(String)
- CASE_SINGLE_OBJECT(Message)
- CASE_SINGLE_OBJECT(Group)
- CASE_SINGLE_POD(Enum, int32_t, Int32)
+#define CASE_SINGLE_POD(NAME, TYPE, FUNC_TYPE) \
+ case GPBDataType##NAME: { \
+ TYPE fieldVal = GPBGetMessage##FUNC_TYPE##Field(self, fieldDescriptor); \
+ result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
+ break; \
+ }
+#define CASE_SINGLE_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ id fieldVal = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor); \
+ result += GPBCompute##NAME##Size(fieldNumber, fieldVal); \
+ break; \
+ }
+ CASE_SINGLE_POD(Bool, BOOL, Bool)
+ CASE_SINGLE_POD(Fixed32, uint32_t, UInt32)
+ CASE_SINGLE_POD(SFixed32, int32_t, Int32)
+ CASE_SINGLE_POD(Float, float, Float)
+ CASE_SINGLE_POD(Fixed64, uint64_t, UInt64)
+ CASE_SINGLE_POD(SFixed64, int64_t, Int64)
+ CASE_SINGLE_POD(Double, double, Double)
+ CASE_SINGLE_POD(Int32, int32_t, Int32)
+ CASE_SINGLE_POD(Int64, int64_t, Int64)
+ CASE_SINGLE_POD(SInt32, int32_t, Int32)
+ CASE_SINGLE_POD(SInt64, int64_t, Int64)
+ CASE_SINGLE_POD(UInt32, uint32_t, UInt32)
+ CASE_SINGLE_POD(UInt64, uint64_t, UInt64)
+ CASE_SINGLE_OBJECT(Bytes)
+ CASE_SINGLE_OBJECT(String)
+ CASE_SINGLE_OBJECT(Message)
+ CASE_SINGLE_OBJECT(Group)
+ CASE_SINGLE_POD(Enum, int32_t, Int32)
#undef CASE_SINGLE_POD
#undef CASE_SINGLE_OBJECT
}
- // Repeated Fields
+ // Repeated Fields
} else if (fieldType == GPBFieldTypeRepeated) {
- id genericArray =
- GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+ id genericArray = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
NSUInteger count = [genericArray count];
if (count == 0) {
continue; // Nothing to add.
@@ -3001,41 +3056,41 @@
__block size_t dataSize = 0;
switch (fieldDataType) {
-#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) \
- CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
-#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) \
- case GPBDataType##NAME: { \
- GPB##ARRAY_TYPE##Array *array = genericArray; \
- [array enumerate##ARRAY_ACCESSOR_NAME##ValuesWithBlock:^(TYPE value, __unused NSUInteger idx, __unused BOOL *stop) { \
- dataSize += GPBCompute##NAME##SizeNoTag(value); \
- }]; \
- break; \
- }
-#define CASE_REPEATED_OBJECT(NAME) \
- case GPBDataType##NAME: { \
- for (id value in genericArray) { \
- dataSize += GPBCompute##NAME##SizeNoTag(value); \
- } \
- break; \
- }
- CASE_REPEATED_POD(Bool, BOOL, Bool)
- CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
- CASE_REPEATED_POD(SFixed32, int32_t, Int32)
- CASE_REPEATED_POD(Float, float, Float)
- CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
- CASE_REPEATED_POD(SFixed64, int64_t, Int64)
- CASE_REPEATED_POD(Double, double, Double)
- CASE_REPEATED_POD(Int32, int32_t, Int32)
- CASE_REPEATED_POD(Int64, int64_t, Int64)
- CASE_REPEATED_POD(SInt32, int32_t, Int32)
- CASE_REPEATED_POD(SInt64, int64_t, Int64)
- CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
- CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
- CASE_REPEATED_OBJECT(Bytes)
- CASE_REPEATED_OBJECT(String)
- CASE_REPEATED_OBJECT(Message)
- CASE_REPEATED_OBJECT(Group)
- CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
+#define CASE_REPEATED_POD(NAME, TYPE, ARRAY_TYPE) CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, )
+#define CASE_REPEATED_POD_EXTRA(NAME, TYPE, ARRAY_TYPE, ARRAY_ACCESSOR_NAME) \
+ case GPBDataType##NAME: { \
+ GPB##ARRAY_TYPE##Array *array = genericArray; \
+ [array enumerate##ARRAY_ACCESSOR_NAME## \
+ ValuesWithBlock:^(TYPE value, __unused NSUInteger idx, __unused BOOL * stop) { \
+ dataSize += GPBCompute##NAME##SizeNoTag(value); \
+ }]; \
+ break; \
+ }
+#define CASE_REPEATED_OBJECT(NAME) \
+ case GPBDataType##NAME: { \
+ for (id value in genericArray) { \
+ dataSize += GPBCompute##NAME##SizeNoTag(value); \
+ } \
+ break; \
+ }
+ CASE_REPEATED_POD(Bool, BOOL, Bool)
+ CASE_REPEATED_POD(Fixed32, uint32_t, UInt32)
+ CASE_REPEATED_POD(SFixed32, int32_t, Int32)
+ CASE_REPEATED_POD(Float, float, Float)
+ CASE_REPEATED_POD(Fixed64, uint64_t, UInt64)
+ CASE_REPEATED_POD(SFixed64, int64_t, Int64)
+ CASE_REPEATED_POD(Double, double, Double)
+ CASE_REPEATED_POD(Int32, int32_t, Int32)
+ CASE_REPEATED_POD(Int64, int64_t, Int64)
+ CASE_REPEATED_POD(SInt32, int32_t, Int32)
+ CASE_REPEATED_POD(SInt64, int64_t, Int64)
+ CASE_REPEATED_POD(UInt32, uint32_t, UInt32)
+ CASE_REPEATED_POD(UInt64, uint64_t, UInt64)
+ CASE_REPEATED_OBJECT(Bytes)
+ CASE_REPEATED_OBJECT(String)
+ CASE_REPEATED_OBJECT(Message)
+ CASE_REPEATED_OBJECT(Group)
+ CASE_REPEATED_POD_EXTRA(Enum, int32_t, Enum, Raw)
#undef CASE_REPEATED_POD
#undef CASE_REPEATED_POD_EXTRA
#undef CASE_REPEATED_OBJECT
@@ -3053,20 +3108,18 @@
result += count * tagSize;
}
- // Map<> Fields
+ // Map<> Fields
} else { // fieldType == GPBFieldTypeMap
if (GPBDataTypeIsObject(fieldDataType) &&
(fieldDescriptor.mapKeyDataType == GPBDataTypeString)) {
// If key type was string, then the map is an NSDictionary.
- NSDictionary *map =
- GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+ NSDictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
if (map) {
result += GPBDictionaryComputeSizeInternalHelper(map, fieldDescriptor);
}
} else {
// Type will be GPB*GroupDictionary, exact type doesn't matter.
- GPBInt32Int32Dictionary *map =
- GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
+ GPBInt32Int32Dictionary *map = GPBGetObjectIvarWithFieldNoAutocreate(self, fieldDescriptor);
result += [map computeSerializedSizeAsField:fieldDescriptor];
}
}
@@ -3102,40 +3155,40 @@
ResolveIvarAccessorMethodResult *result) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
-#define CASE_GET(NAME, TYPE, TRUE_NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj) { \
- return GPBGetMessage##TRUE_NAME##Field(obj, field); \
- }); \
- result->encodingSelector = @selector(get##NAME); \
- break; \
- }
-#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj) { \
- return GPBGetObjectIvarWithField(obj, field); \
- }); \
- result->encodingSelector = @selector(get##NAME); \
- break; \
- }
- CASE_GET(Bool, BOOL, Bool)
- CASE_GET(Fixed32, uint32_t, UInt32)
- CASE_GET(SFixed32, int32_t, Int32)
- CASE_GET(Float, float, Float)
- CASE_GET(Fixed64, uint64_t, UInt64)
- CASE_GET(SFixed64, int64_t, Int64)
- CASE_GET(Double, double, Double)
- CASE_GET(Int32, int32_t, Int32)
- CASE_GET(Int64, int64_t, Int64)
- CASE_GET(SInt32, int32_t, Int32)
- CASE_GET(SInt64, int64_t, Int64)
- CASE_GET(UInt32, uint32_t, UInt32)
- CASE_GET(UInt64, uint64_t, UInt64)
- CASE_GET_OBJECT(Bytes, id, Object)
- CASE_GET_OBJECT(String, id, Object)
- CASE_GET_OBJECT(Message, id, Object)
- CASE_GET_OBJECT(Group, id, Object)
- CASE_GET(Enum, int32_t, Enum)
+#define CASE_GET(NAME, TYPE, TRUE_NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+ return GPBGetMessage##TRUE_NAME##Field(obj, field); \
+ }); \
+ result->encodingSelector = @selector(get##NAME); \
+ break; \
+ }
+#define CASE_GET_OBJECT(NAME, TYPE, TRUE_NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj) { \
+ return GPBGetObjectIvarWithField(obj, field); \
+ }); \
+ result->encodingSelector = @selector(get##NAME); \
+ break; \
+ }
+ CASE_GET(Bool, BOOL, Bool)
+ CASE_GET(Fixed32, uint32_t, UInt32)
+ CASE_GET(SFixed32, int32_t, Int32)
+ CASE_GET(Float, float, Float)
+ CASE_GET(Fixed64, uint64_t, UInt64)
+ CASE_GET(SFixed64, int64_t, Int64)
+ CASE_GET(Double, double, Double)
+ CASE_GET(Int32, int32_t, Int32)
+ CASE_GET(Int64, int64_t, Int64)
+ CASE_GET(SInt32, int32_t, Int32)
+ CASE_GET(SInt64, int64_t, Int64)
+ CASE_GET(UInt32, uint32_t, UInt32)
+ CASE_GET(UInt64, uint64_t, UInt64)
+ CASE_GET_OBJECT(Bytes, id, Object)
+ CASE_GET_OBJECT(String, id, Object)
+ CASE_GET_OBJECT(Message, id, Object)
+ CASE_GET_OBJECT(Group, id, Object)
+ CASE_GET(Enum, int32_t, Enum)
#undef CASE_GET
}
}
@@ -3145,40 +3198,40 @@
ResolveIvarAccessorMethodResult *result) {
GPBDataType fieldDataType = GPBGetFieldDataType(field);
switch (fieldDataType) {
-#define CASE_SET(NAME, TYPE, TRUE_NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \
- return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value); \
- }); \
- result->encodingSelector = @selector(set##NAME:); \
- break; \
- }
-#define CASE_SET_COPY(NAME) \
- case GPBDataType##NAME: { \
- result->impToAdd = imp_implementationWithBlock(^(id obj, id value) { \
- return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
- }); \
- result->encodingSelector = @selector(set##NAME:); \
- break; \
- }
- CASE_SET(Bool, BOOL, Bool)
- CASE_SET(Fixed32, uint32_t, UInt32)
- CASE_SET(SFixed32, int32_t, Int32)
- CASE_SET(Float, float, Float)
- CASE_SET(Fixed64, uint64_t, UInt64)
- CASE_SET(SFixed64, int64_t, Int64)
- CASE_SET(Double, double, Double)
- CASE_SET(Int32, int32_t, Int32)
- CASE_SET(Int64, int64_t, Int64)
- CASE_SET(SInt32, int32_t, Int32)
- CASE_SET(SInt64, int64_t, Int64)
- CASE_SET(UInt32, uint32_t, UInt32)
- CASE_SET(UInt64, uint64_t, UInt64)
- CASE_SET_COPY(Bytes)
- CASE_SET_COPY(String)
- CASE_SET(Message, id, Object)
- CASE_SET(Group, id, Object)
- CASE_SET(Enum, int32_t, Enum)
+#define CASE_SET(NAME, TYPE, TRUE_NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj, TYPE value) { \
+ return GPBSet##TRUE_NAME##IvarWithFieldPrivate(obj, field, value); \
+ }); \
+ result->encodingSelector = @selector(set##NAME:); \
+ break; \
+ }
+#define CASE_SET_COPY(NAME) \
+ case GPBDataType##NAME: { \
+ result->impToAdd = imp_implementationWithBlock(^(id obj, id value) { \
+ return GPBSetRetainedObjectIvarWithFieldPrivate(obj, field, [value copy]); \
+ }); \
+ result->encodingSelector = @selector(set##NAME:); \
+ break; \
+ }
+ CASE_SET(Bool, BOOL, Bool)
+ CASE_SET(Fixed32, uint32_t, UInt32)
+ CASE_SET(SFixed32, int32_t, Int32)
+ CASE_SET(Float, float, Float)
+ CASE_SET(Fixed64, uint64_t, UInt64)
+ CASE_SET(SFixed64, int64_t, Int64)
+ CASE_SET(Double, double, Double)
+ CASE_SET(Int32, int32_t, Int32)
+ CASE_SET(Int64, int64_t, Int64)
+ CASE_SET(SInt32, int32_t, Int32)
+ CASE_SET(SInt64, int64_t, Int64)
+ CASE_SET(UInt32, uint32_t, UInt32)
+ CASE_SET(UInt64, uint64_t, UInt64)
+ CASE_SET_COPY(Bytes)
+ CASE_SET_COPY(String)
+ CASE_SET(Message, id, Object)
+ CASE_SET(Group, id, Object)
+ CASE_SET(Enum, int32_t, Enum)
#undef CASE_SET
}
}
@@ -3217,8 +3270,7 @@
result.impToAdd = imp_implementationWithBlock(^(id obj, BOOL value) {
if (value) {
[NSException raise:NSInvalidArgumentException
- format:@"%@: %@ can only be set to NO (to clear field).",
- [obj class],
+ format:@"%@: %@ can only be set to NO (to clear field).", [obj class],
NSStringFromSelector(field->setHasSel_)];
}
GPBClearMessageField(obj, field);
@@ -3262,8 +3314,7 @@
result.impToAdd = imp_implementationWithBlock(^(id obj) {
// Type doesn't matter, all *Array and *Dictionary types support
// -count.
- NSArray *arrayOrMap =
- GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
+ NSArray *arrayOrMap = GPBGetObjectIvarWithFieldNoAutocreate(obj, field);
return [arrayOrMap count];
});
result.encodingSelector = @selector(getArrayCount);
@@ -3272,8 +3323,7 @@
}
}
if (result.impToAdd) {
- const char *encoding =
- GPBMessageEncodingForSelector(result.encodingSelector, YES);
+ const char *encoding = GPBMessageEncodingForSelector(result.encodingSelector, YES);
Class msgClass = descriptor.messageClass;
BOOL methodAdded = class_addMethod(msgClass, sel, result.impToAdd, encoding);
// class_addMethod() is documented as also failing if the method was already
@@ -3307,10 +3357,12 @@
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [self init];
if (self) {
- NSData *data =
- [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
+ NSData *data = [aDecoder decodeObjectOfClass:[NSData class] forKey:kGPBDataCoderKey];
if (data.length) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
[self mergeFromData:data extensionRegistry:nil];
+#pragma clang diagnostic pop
}
}
return self;
@@ -3355,8 +3407,7 @@
#if defined(DEBUG) && DEBUG
if (field.fieldType != GPBFieldTypeRepeated) {
[NSException raise:NSInvalidArgumentException
- format:@"%@.%@ is not a repeated field.",
- [self class], field.name];
+ format:@"%@.%@ is not a repeated field.", [self class], field.name];
}
#endif
return GetOrCreateArrayIvarWithField(self, field);
@@ -3367,8 +3418,7 @@
#if defined(DEBUG) && DEBUG
if (field.fieldType != GPBFieldTypeMap) {
[NSException raise:NSInvalidArgumentException
- format:@"%@.%@ is not a map<> field.",
- [self class], field.name];
+ format:@"%@.%@ is not a map<> field.", [self class], field.name];
}
#endif
return GetOrCreateMapIvarWithField(self, field);
diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h
index 70b47a5..8dc82e4 100644
--- a/objectivec/GPBMessage_PackagePrivate.h
+++ b/objectivec/GPBMessage_PackagePrivate.h
@@ -80,26 +80,12 @@
- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input
extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry;
-// Parses the next delimited message of this type from the input and merges it
-// with this message.
-- (void)mergeDelimitedFromCodedInputStream:(GPBCodedInputStream *)input
- extensionRegistry:(id<GPBExtensionRegistry>)extensionRegistry;
-
- (void)addUnknownMapEntry:(int32_t)fieldNum value:(NSData *)data;
@end
CF_EXTERN_C_BEGIN
-// Call this before using the readOnlySemaphore_. This ensures it is created only once.
-void GPBPrepareReadOnlySemaphore(GPBMessage *self);
-
-// Returns a new instance that was automatically created by |autocreator| for
-// its field |field|.
-GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, GPBMessage *autocreator,
- GPBFieldDescriptor *field)
- __attribute__((ns_returns_retained));
-
// Returns whether |message| autocreated this message. This is NO if the message
// was not autocreated by |message| or if it has been mutated since
// autocreation.
diff --git a/objectivec/GPBProtocolBuffers_RuntimeSupport.h b/objectivec/GPBProtocolBuffers_RuntimeSupport.h
index 804a68a..297173d 100644
--- a/objectivec/GPBProtocolBuffers_RuntimeSupport.h
+++ b/objectivec/GPBProtocolBuffers_RuntimeSupport.h
@@ -36,7 +36,6 @@
// clang-format on
#import "GPBDescriptor_PackagePrivate.h"
-#import "GPBExtensionInternals.h"
-#import "GPBMessage_PackagePrivate.h"
+#import "GPBMessage.h"
#import "GPBRootObject_PackagePrivate.h"
#import "GPBUtilities_PackagePrivate.h"
diff --git a/objectivec/GPBStruct.pbobjc.h b/objectivec/GPBStruct.pbobjc.h
index b0cc299..8f2f12c 100644
--- a/objectivec/GPBStruct.pbobjc.h
+++ b/objectivec/GPBStruct.pbobjc.h
@@ -32,7 +32,7 @@
* `NullValue` is a singleton enumeration to represent the null value for the
* `Value` type union.
*
- * The JSON representation for `NullValue` is JSON `null`.
+ * The JSON representation for `NullValue` is JSON `null`.
**/
typedef GPB_ENUM(GPBNullValue) {
/**
diff --git a/objectivec/GPBType.pbobjc.h b/objectivec/GPBType.pbobjc.h
index 35a03f9..28638fa 100644
--- a/objectivec/GPBType.pbobjc.h
+++ b/objectivec/GPBType.pbobjc.h
@@ -43,6 +43,9 @@
/** Syntax `proto3`. */
GPBSyntax_SyntaxProto3 = 1,
+
+ /** Syntax `editions`. */
+ GPBSyntax_SyntaxEditions = 2,
};
GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void);
@@ -184,6 +187,7 @@
GPBType_FieldNumber_OptionsArray = 4,
GPBType_FieldNumber_SourceContext = 5,
GPBType_FieldNumber_Syntax = 6,
+ GPBType_FieldNumber_Edition = 7,
};
/**
@@ -217,6 +221,9 @@
/** The source syntax. */
@property(nonatomic, readwrite) GPBSyntax syntax;
+/** The source edition string, only valid when syntax is SYNTAX_EDITIONS. */
+@property(nonatomic, readwrite, copy, null_resettable) NSString *edition;
+
@end
/**
@@ -323,6 +330,7 @@
GPBEnum_FieldNumber_OptionsArray = 3,
GPBEnum_FieldNumber_SourceContext = 4,
GPBEnum_FieldNumber_Syntax = 5,
+ GPBEnum_FieldNumber_Edition = 6,
};
/**
@@ -351,6 +359,9 @@
/** The source syntax. */
@property(nonatomic, readwrite) GPBSyntax syntax;
+/** The source edition string, only valid when syntax is SYNTAX_EDITIONS. */
+@property(nonatomic, readwrite, copy, null_resettable) NSString *edition;
+
@end
/**
diff --git a/objectivec/GPBType.pbobjc.m b/objectivec/GPBType.pbobjc.m
index 04e262c..db7a41f 100644
--- a/objectivec/GPBType.pbobjc.m
+++ b/objectivec/GPBType.pbobjc.m
@@ -54,10 +54,12 @@
if (!descriptor) {
GPB_DEBUG_CHECK_RUNTIME_VERSIONS();
static const char *valueNames =
- "SyntaxProto2\000SyntaxProto3\000";
+ "SyntaxProto2\000SyntaxProto3\000SyntaxEditions"
+ "\000";
static const int32_t values[] = {
GPBSyntax_SyntaxProto2,
GPBSyntax_SyntaxProto3,
+ GPBSyntax_SyntaxEditions,
};
GPBEnumDescriptor *worker =
[GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBSyntax)
@@ -78,6 +80,7 @@
switch (value__) {
case GPBSyntax_SyntaxProto2:
case GPBSyntax_SyntaxProto3:
+ case GPBSyntax_SyntaxEditions:
return YES;
default:
return NO;
@@ -212,6 +215,7 @@
@dynamic optionsArray, optionsArray_Count;
@dynamic hasSourceContext, sourceContext;
@dynamic syntax;
+@dynamic edition;
typedef struct GPBType__storage_ {
uint32_t _has_storage_[1];
@@ -221,6 +225,7 @@
NSMutableArray *oneofsArray;
NSMutableArray *optionsArray;
GPBSourceContext *sourceContext;
+ NSString *edition;
} GPBType__storage_;
// This method is threadsafe because it is initially called
@@ -284,6 +289,15 @@
.flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor | GPBFieldClearHasIvarOnZero),
.dataType = GPBDataTypeEnum,
},
+ {
+ .name = "edition",
+ .dataTypeSpecific.clazz = Nil,
+ .number = GPBType_FieldNumber_Edition,
+ .hasIndex = 3,
+ .offset = (uint32_t)offsetof(GPBType__storage_, edition),
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero),
+ .dataType = GPBDataTypeString,
+ },
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:GPBObjCClass(GPBType)
@@ -497,6 +511,7 @@
@dynamic optionsArray, optionsArray_Count;
@dynamic hasSourceContext, sourceContext;
@dynamic syntax;
+@dynamic edition;
typedef struct GPBEnum__storage_ {
uint32_t _has_storage_[1];
@@ -505,6 +520,7 @@
NSMutableArray *enumvalueArray;
NSMutableArray *optionsArray;
GPBSourceContext *sourceContext;
+ NSString *edition;
} GPBEnum__storage_;
// This method is threadsafe because it is initially called
@@ -559,6 +575,15 @@
.flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldHasEnumDescriptor | GPBFieldClearHasIvarOnZero),
.dataType = GPBDataTypeEnum,
},
+ {
+ .name = "edition",
+ .dataTypeSpecific.clazz = Nil,
+ .number = GPBEnum_FieldNumber_Edition,
+ .hasIndex = 3,
+ .offset = (uint32_t)offsetof(GPBEnum__storage_, edition),
+ .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero),
+ .dataType = GPBDataTypeString,
+ },
};
GPBDescriptor *localDescriptor =
[GPBDescriptor allocDescriptorForClass:GPBObjCClass(GPBEnum)
diff --git a/objectivec/GPBUnknownFieldSet.m b/objectivec/GPBUnknownFieldSet.m
index dcd4b44..fd36935 100644
--- a/objectivec/GPBUnknownFieldSet.m
+++ b/objectivec/GPBUnknownFieldSet.m
@@ -289,13 +289,6 @@
}
}
-- (void)mergeFromData:(NSData *)data {
- GPBCodedInputStream *input = [[GPBCodedInputStream alloc] initWithData:data];
- [self mergeFromCodedInputStream:input];
- [input checkLastTagWas:0];
- [input release];
-}
-
- (void)mergeVarintField:(int32_t)number value:(int32_t)value {
checkNumber(number);
[[self mutableFieldForNumber:number create:YES] addVarint:value];
@@ -325,10 +318,12 @@
}
case GPBWireFormatStartGroup: {
GPBUnknownFieldSet *unknownFieldSet = [[GPBUnknownFieldSet alloc] init];
- [input readUnknownGroup:number message:unknownFieldSet];
GPBUnknownField *field = [self mutableFieldForNumber:number create:YES];
[field addGroup:unknownFieldSet];
+ // The field will now retain unknownFieldSet, so go ahead and release it in case
+ // -readUnknownGroup:message: throws so it won't be leaked.
[unknownFieldSet release];
+ [input readUnknownGroup:number message:unknownFieldSet];
return YES;
}
case GPBWireFormatEndGroup:
diff --git a/objectivec/GPBUnknownFieldSet_PackagePrivate.h b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
index e27127a..b65bdaa 100644
--- a/objectivec/GPBUnknownFieldSet_PackagePrivate.h
+++ b/objectivec/GPBUnknownFieldSet_PackagePrivate.h
@@ -50,7 +50,6 @@
- (void)mergeUnknownFields:(GPBUnknownFieldSet *)other;
- (void)mergeFromCodedInputStream:(GPBCodedInputStream *)input;
-- (void)mergeFromData:(NSData *)data;
- (void)mergeVarintField:(int32_t)number value:(int32_t)value;
- (BOOL)mergeFieldFrom:(int32_t)tag input:(GPBCodedInputStream *)input;
diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m
index 0504062..0d0d327 100644
--- a/objectivec/Tests/GPBCodedInputStreamTests.m
+++ b/objectivec/Tests/GPBCodedInputStreamTests.m
@@ -28,6 +28,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#import <Foundation/Foundation.h>
#import "GPBTestUtilities.h"
#import "GPBCodedInputStream.h"
@@ -370,10 +371,23 @@
@"should throw a GPBCodedInputStreamException exception ");
}
-- (void)testBytesWithNegativeSize {
- NSData* data = bytes(0xFF, 0xFF, 0xFF, 0xFF, 0x0F);
+- (void)testBytesOver2GB {
+ NSData* data = bytes(0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x01, 0x02, 0x03); // don't need all the bytes
GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data];
- XCTAssertNil([input readBytes]);
+ @try {
+ __unused NSData* result = [input readBytes];
+ XCTFail(@"Should have thrown");
+ } @catch (NSException* anException) {
+ // Ensure the correct error within the exception.
+ XCTAssertTrue([anException isKindOfClass:[NSException class]]);
+ XCTAssertEqualObjects(anException.name, GPBCodedInputStreamException);
+ NSDictionary* userInfo = anException.userInfo;
+ XCTAssertNotNil(userInfo);
+ NSError* err = userInfo[GPBCodedInputStreamUnderlyingErrorKey];
+ XCTAssertNotNil(err);
+ XCTAssertEqualObjects(err.domain, GPBCodedInputStreamErrorDomain);
+ XCTAssertEqual(err.code, GPBCodedInputStreamErrorInvalidSize);
+ }
}
// Verifies fix for b/10315336.
diff --git a/objectivec/Tests/GPBCodedOutputStreamTests.m b/objectivec/Tests/GPBCodedOutputStreamTests.m
index a619cae..6218f51 100644
--- a/objectivec/Tests/GPBCodedOutputStreamTests.m
+++ b/objectivec/Tests/GPBCodedOutputStreamTests.m
@@ -80,7 +80,9 @@
NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
GPBCodedOutputStream* output = [GPBCodedOutputStream streamWithOutputStream:rawOutput];
[output writeRawLittleEndian32:(int32_t)value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
NSData* actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -90,7 +92,9 @@
rawOutput = [NSOutputStream outputStreamToMemory];
output = [GPBCodedOutputStream streamWithOutputStream:rawOutput bufferSize:blockSize];
[output writeRawLittleEndian32:(int32_t)value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -101,7 +105,9 @@
NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
GPBCodedOutputStream* output = [GPBCodedOutputStream streamWithOutputStream:rawOutput];
[output writeRawLittleEndian64:value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
NSData* actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -111,7 +117,9 @@
rawOutput = [NSOutputStream outputStreamToMemory];
output = [GPBCodedOutputStream streamWithOutputStream:rawOutput bufferSize:blockSize];
[output writeRawLittleEndian64:value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -124,7 +132,9 @@
NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
GPBCodedOutputStream* output = [GPBCodedOutputStream streamWithOutputStream:rawOutput];
[output writeRawVarint32:(int32_t)value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
NSData* actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -137,7 +147,9 @@
NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
GPBCodedOutputStream* output = [GPBCodedOutputStream streamWithOutputStream:rawOutput];
[output writeRawVarint64:value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
NSData* actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -155,7 +167,9 @@
bufferSize:blockSize];
[output writeRawVarint32:(int32_t)value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
NSData* actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -167,7 +181,9 @@
bufferSize:blockSize];
[output writeRawVarint64:value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
NSData* actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual);
@@ -181,7 +197,9 @@
NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory];
GPBCodedOutputStream* output = [GPBCodedOutputStream streamWithOutputStream:rawOutput];
[output writeStringNoTag:value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
NSData* actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual, @"%@", contextMessage);
@@ -191,7 +209,9 @@
rawOutput = [NSOutputStream outputStreamToMemory];
output = [GPBCodedOutputStream streamWithOutputStream:rawOutput bufferSize:blockSize];
[output writeStringNoTag:value];
+ XCTAssertEqual(output.bytesWritten, data.length);
[output flush];
+ XCTAssertEqual(output.bytesWritten, data.length);
actual = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
XCTAssertEqualObjects(data, actual, @"%@", contextMessage);
diff --git a/objectivec/Tests/GPBMessageTests+Serialization.m b/objectivec/Tests/GPBMessageTests+Serialization.m
index 3c2381c..5a7dc16 100644
--- a/objectivec/Tests/GPBMessageTests+Serialization.m
+++ b/objectivec/Tests/GPBMessageTests+Serialization.m
@@ -1266,12 +1266,17 @@
XCTAssertEqual(error.code, GPBCodedInputStreamErrorRecursionDepthExceeded);
}
-- (void)testParseDelimitedDataWithNegativeSize {
- NSData *data = DataFromCStr("\xFF\xFF\xFF\xFF\x0F");
+- (void)testParseDelimitedDataOver2GB {
+ NSData *data = DataFromCStr("\xFF\xFF\xFF\xFF\x0F\x01\x02\0x3"); // Don't need all the bytes
GPBCodedInputStream *input = [GPBCodedInputStream streamWithData:data];
NSError *error;
- [GPBMessage parseDelimitedFromCodedInputStream:input extensionRegistry:nil error:&error];
- XCTAssertNil(error);
+ GPBMessage *result = [GPBMessage parseDelimitedFromCodedInputStream:input
+ extensionRegistry:nil
+ error:&error];
+ XCTAssertNil(result);
+ XCTAssertNotNil(error);
+ XCTAssertEqualObjects(error.domain, GPBCodedInputStreamErrorDomain);
+ XCTAssertEqual(error.code, GPBCodedInputStreamErrorInvalidSize);
}
#ifdef DEBUG
diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m
index 6a1d48b..2e595f6 100644
--- a/objectivec/Tests/GPBMessageTests.m
+++ b/objectivec/Tests/GPBMessageTests.m
@@ -224,7 +224,11 @@
result = [self mergeExtensionsDestination];
NSData *data = [[self mergeExtensionsSource] data];
XCTAssertNotNil(data);
- [result mergeFromData:data extensionRegistry:[UnittestRoot extensionRegistry]];
+ NSError *error = nil;
+ XCTAssertTrue([result mergeFromData:data
+ extensionRegistry:[UnittestRoot extensionRegistry]
+ error:&error]);
+ XCTAssertNil(error);
resultData = [result data];
XCTAssertEqualObjects(resultData, mergeResultData);
XCTAssertEqualObjects(result, [self mergeExtensionsResult]);
diff --git a/objectivec/Tests/GPBUnknownFieldSetTest.m b/objectivec/Tests/GPBUnknownFieldSetTest.m
index b98f52e..dbb6eb4 100644
--- a/objectivec/Tests/GPBUnknownFieldSetTest.m
+++ b/objectivec/Tests/GPBUnknownFieldSetTest.m
@@ -381,7 +381,8 @@
NSData* data = [fields data];
GPBUnknownFieldSet* parsed = [[[GPBUnknownFieldSet alloc] init] autorelease];
- [parsed mergeFromData:data];
+ GPBCodedInputStream* input = [[[GPBCodedInputStream alloc] initWithData:data] autorelease];
+ [parsed mergeFromCodedInputStream:input];
GPBUnknownField* field2 = [parsed getField:1];
XCTAssertEqual(field2.varintList.count, (NSUInteger)1);
XCTAssertEqual(0x7FFFFFFFFFFFFFFFULL, [field2.varintList valueAtIndex:0]);
diff --git a/objectivec/defs.bzl b/objectivec/defs.bzl
new file mode 100644
index 0000000..5535868
--- /dev/null
+++ b/objectivec/defs.bzl
@@ -0,0 +1,68 @@
+"""Starlark helpers for Objective-C protos."""
+
+# State constants for objc_proto_camel_case_name.
+_last_was_other = 0
+_last_was_lowercase = 1
+_last_was_uppercase = 2
+_last_was_number = 3
+
+def objc_proto_camel_case_name(name):
+ """A Starlark version of the ObjC generator's CamelCase name transform.
+
+ This needs to track
+ src/google/protobuf/compiler/objectivec/names.cc's UnderscoresToCamelCase()
+
+ NOTE: This code is written to model the C++ in protoc's ObjC generator so it
+ is easier to confirm that the algorithms between the implementations match.
+ The customizations for starlark performance are:
+ - The cascade within the loop is reordered and special cases "_" to
+ optimize for google3 inputs.
+ - The "last was" state is handled via integers instead of three booleans.
+
+ The `first_capitalized` argument in the C++ code is left off this code and
+ it acts as if the value were `True`.
+
+ Args:
+ name: The proto file name to convert to camel case. The extension should
+ already be removed.
+
+ Returns:
+ The converted proto name to camel case.
+ """
+ segments = []
+ current = ""
+ last_was = _last_was_other
+ for c in name.elems():
+ if c.islower():
+ # lowercase letter can follow a lowercase or uppercase letter.
+ if last_was != _last_was_lowercase and last_was != _last_was_uppercase:
+ segments.append(current)
+ current = c.upper()
+ else:
+ current += c
+ last_was = _last_was_lowercase
+ elif c == "_": # more common than rest, special case it.
+ last_was = _last_was_other
+ elif c.isdigit():
+ if last_was != _last_was_number:
+ segments.append(current)
+ current = ""
+ current += c
+ last_was = _last_was_number
+ elif c.isupper():
+ if last_was != _last_was_uppercase:
+ segments.append(current)
+ current = c
+ else:
+ current += c.lower()
+ last_was = _last_was_uppercase
+ else:
+ last_was = _last_was_other
+ segments.append(current)
+ result = ""
+ for x in segments:
+ if x in ("Url", "Http", "Https"):
+ result += x.upper()
+ else:
+ result += x
+ return result
diff --git a/objectivec/generate_well_known_types.sh b/objectivec/generate_well_known_types.sh
index 7e23a99..4b77412 100755
--- a/objectivec/generate_well_known_types.sh
+++ b/objectivec/generate_well_known_types.sh
@@ -9,8 +9,7 @@
readonly ObjCDir="${ScriptDir}"
readonly ProtoRootDir="${ObjCDir}/.."
-# Invoke with BAZEL=bazelisk to use that instead.
-readonly BazelBin="${BAZEL:-bazel} ${BAZEL_STARTUP_FLAGS:-}"
+cd "${ProtoRootDir}"
# Flag for continuous integration to check that everything is current.
CHECK_ONLY=0
@@ -19,7 +18,11 @@
shift
fi
-cd "${ProtoRootDir}"
+readonly PROTOC_PATH="${PROTOC:-${ProtoRootDir}/bazel-bin/protoc}"
+if [[ ! -x "${PROTOC_PATH}" ]] ; then
+ echo "Failed to find executable protoc: ${PROTOC_PATH}"
+ exit 1
+fi
if [[ ! -e src/google/protobuf/stubs/common.h ]]; then
cat >&2 << __EOF__
@@ -29,9 +32,6 @@
exit 1
fi
-# Make sure the compiler is current.
-${BazelBin} build //:protoc $@
-
cd src
declare -a RUNTIME_PROTO_FILES=( \
google/protobuf/any.proto \
@@ -50,7 +50,7 @@
# Generate to a temp directory to see if they match.
TMP_DIR=$(mktemp -d)
trap "rm -rf ${TMP_DIR}" EXIT
-${ProtoRootDir}/bazel-bin/protoc --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]}
+"${PROTOC_PATH}" --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]}
DID_COPY=0
for PROTO_FILE in "${RUNTIME_PROTO_FILES[@]}"; do
diff --git a/php/ext/google/protobuf/array.c b/php/ext/google/protobuf/array.c
index 72c7809..09daffa 100644
--- a/php/ext/google/protobuf/array.c
+++ b/php/ext/google/protobuf/array.c
@@ -406,13 +406,13 @@
return;
}
- if (size == 0 || index != size - 1) {
+ if (size == 0 || index < 0 || index >= size) {
php_error_docref(NULL, E_USER_ERROR, "Cannot remove element at %ld.\n",
index);
return;
}
- upb_Array_Resize(intern->array, size - 1, Arena_Get(&intern->arena));
+ upb_Array_Delete(intern->array, index, 1);
}
/**
diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c
index 2dac3ad..ef95724 100644
--- a/php/ext/google/protobuf/php-upb.c
+++ b/php/ext/google/protobuf/php-upb.c
@@ -641,12 +641,14 @@
[kUpb_FieldType_Bytes] = _upb_mapsorter_cmpstr,
};
-static bool _upb_mapsorter_resize(_upb_mapsorter* s, _upb_sortedmap* sorted,
- int size) {
+bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
+ const upb_Map* map, _upb_sortedmap* sorted) {
+ int map_size = _upb_Map_Size(map);
sorted->start = s->size;
sorted->pos = sorted->start;
- sorted->end = sorted->start + size;
+ sorted->end = sorted->start + map_size;
+ // Grow s->entries if necessary.
if (sorted->end > s->cap) {
s->cap = upb_Log2CeilingSize(sorted->end);
s->entries = realloc(s->entries, s->cap * sizeof(*s->entries));
@@ -654,17 +656,9 @@
}
s->size = sorted->end;
- return true;
-}
-
-bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
- const upb_Map* map, _upb_sortedmap* sorted) {
- int map_size = _upb_Map_Size(map);
-
- if (!_upb_mapsorter_resize(s, sorted, map_size)) return false;
// Copy non-empty entries from the table to s->entries.
- const void** dst = &s->entries[sorted->start];
+ upb_tabent const** dst = &s->entries[sorted->start];
const upb_tabent* src = map->table.t.entries;
const upb_tabent* end = src + upb_table_size(&map->table.t);
for (; src < end; src++) {
@@ -680,29 +674,6 @@
compar[key_type]);
return true;
}
-
-static int _upb_mapsorter_cmpext(const void* _a, const void* _b) {
- const upb_Message_Extension* const* a = _a;
- const upb_Message_Extension* const* b = _b;
- uint32_t a_num = (*a)->ext->field.number;
- uint32_t b_num = (*b)->ext->field.number;
- assert(a_num != b_num);
- return a_num < b_num ? -1 : 1;
-}
-
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s,
- const upb_Message_Extension* exts, size_t count,
- _upb_sortedmap* sorted) {
- if (!_upb_mapsorter_resize(s, sorted, count)) return false;
-
- for (size_t i = 0; i < count; i++) {
- s->entries[sorted->start + i] = &exts[i];
- }
-
- qsort(&s->entries[sorted->start], count, sizeof(*s->entries),
- _upb_mapsorter_cmpext);
- return true;
-}
/* This file was generated by upbc (the upb compiler) from the input
* file:
*
@@ -2254,7 +2225,7 @@
n = len + 1;
p = upb_Arena_Malloc(a, n);
if (p) {
- if (len != 0) memcpy(p, s, len);
+ memcpy(p, s, len);
p[len] = 0;
}
return p;
@@ -7590,27 +7561,9 @@
_upb_DefBuilder_FailJmp(ctx);
}
-// Verify a relative identifier string. The loop is branchless for speed.
-static void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx,
- upb_StringView name) {
- bool good = name.size > 0;
-
- for (size_t i = 0; i < name.size; i++) {
- const char c = name.data[i];
- const char d = c | 0x20; // force lowercase
- const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_');
- const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0);
-
- good &= is_alpha | is_numer;
- }
-
- if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false);
-}
-
const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx,
const char* prefix,
upb_StringView name) {
- _upb_DefBuilder_CheckIdentNotFull(ctx, name);
if (prefix) {
// ret = prefix + '.' + name;
size_t n = strlen(prefix);
@@ -7726,7 +7679,7 @@
return true;
}
-static int TryGetHexDigit(const char** src, const char* end) {
+static char TryGetHexDigit(const char** src, const char* end) {
char ch;
if (!TryGetChar(src, end, &ch)) return -1;
if ('0' <= ch && ch <= '9') {
@@ -7743,10 +7696,10 @@
static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx,
const upb_FieldDef* f,
const char** src, const char* end) {
- int hex_digit = TryGetHexDigit(src, end);
+ char hex_digit = TryGetHexDigit(src, end);
if (hex_digit < 0) {
_upb_DefBuilder_Errf(
- ctx, "\\x must be followed by at least one hex digit (field='%s')",
+ ctx, "\\x cannot be followed by non-hex digit in field '%s' default",
upb_FieldDef_FullName(f));
return 0;
}
@@ -7922,7 +7875,7 @@
}
bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext,
- const upb_FieldDef* f) {
+ upb_FieldDef* f) {
return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f),
s->arena);
}
@@ -8154,6 +8107,12 @@
const upb_MiniTableFile* layout, upb_Status* status) {
const upb_StringView name = UPB_DESC(FileDescriptorProto_name)(file_proto);
+ if (name.size == 0) {
+ upb_Status_SetErrorFormat(status,
+ "missing name in google_protobuf_FileDescriptorProto");
+ return NULL;
+ }
+
// Determine whether we already know about this file.
{
upb_value v;
@@ -8545,6 +8504,7 @@
e->file = _upb_DefBuilder_File(ctx);
name = UPB_DESC(EnumDescriptorProto_name)(enum_proto);
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
_upb_DefBuilder_Add(ctx, e->full_name,
@@ -9354,14 +9314,7 @@
}
const upb_StringView name = UPB_DESC(FieldDescriptorProto_name)(field_proto);
-
- f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
- f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto);
- f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto);
- f->is_proto3_optional =
- UPB_DESC(FieldDescriptorProto_proto3_optional)(field_proto);
- f->msgdef = m;
- f->scope.oneof = NULL;
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
f->has_json_name = UPB_DESC(FieldDescriptorProto_has_json_name)(field_proto);
if (f->has_json_name) {
@@ -9373,6 +9326,14 @@
}
if (!f->json_name) _upb_DefBuilder_OomErr(ctx);
+ f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
+ f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto);
+ f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto);
+ f->is_proto3_optional =
+ UPB_DESC(FieldDescriptorProto_proto3_optional)(field_proto);
+ f->msgdef = m;
+ f->scope.oneof = NULL;
+
const bool has_type = UPB_DESC(FieldDescriptorProto_has_type)(field_proto);
const bool has_type_name =
UPB_DESC(FieldDescriptorProto_has_type_name)(field_proto);
@@ -9502,24 +9463,19 @@
}
_upb_MessageDef_InsertField(ctx, m, f);
-}
-upb_FieldDef* _upb_Extensions_New(
- upb_DefBuilder* ctx, int n,
- const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix,
- upb_MessageDef* m) {
- _upb_DefType_CheckPadding(sizeof(upb_FieldDef));
- upb_FieldDef* defs =
- (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n);
+ if (!ctx->layout) return;
- for (int i = 0; i < n; i++) {
- upb_FieldDef* f = &defs[i];
-
- _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f);
- f->index_ = i;
+ const upb_MiniTable* mt = upb_MessageDef_MiniTable(m);
+ const upb_MiniTableField* fields = mt->fields;
+ for (int i = 0; i < mt->field_count; i++) {
+ if (fields[i].number == f->number_) {
+ f->layout_index = i;
+ return;
+ }
}
- return defs;
+ UPB_ASSERT(false); // It should be impossible to reach this point.
}
upb_FieldDef* _upb_FieldDefs_New(
@@ -9530,23 +9486,28 @@
upb_FieldDef* defs =
(upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n);
- uint32_t previous = 0;
- for (int i = 0; i < n; i++) {
- upb_FieldDef* f = &defs[i];
+ // If we are creating extensions then is_sorted will be NULL.
+ // If we are not creating extensions then is_sorted will be non-NULL.
+ if (is_sorted) {
+ uint32_t previous = 0;
+ for (int i = 0; i < n; i++) {
+ upb_FieldDef* f = &defs[i];
- _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f);
- f->index_ = i;
- if (!ctx->layout) {
- // Speculate that the def fields are sorted. We will always sort the
- // MiniTable fields, so if defs are sorted then indices will match.
- //
- // If this is incorrect, we will overwrite later.
- f->layout_index = i;
+ _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f);
+ f->index_ = i;
+ if (!ctx->layout) f->layout_index = i;
+
+ const uint32_t current = f->number_;
+ if (previous > current) *is_sorted = false;
+ previous = current;
}
+ } else {
+ for (int i = 0; i < n; i++) {
+ upb_FieldDef* f = &defs[i];
- const uint32_t current = f->number_;
- if (previous > current) *is_sorted = false;
- previous = current;
+ _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f);
+ f->index_ = i;
+ }
}
return defs;
@@ -9602,9 +9563,6 @@
return (v1 < v2) ? -1 : (v1 > v2);
}
-// _upb_FieldDefs_Sorted() is mostly a pure function of its inputs, but has one
-// critical side effect that we depend on: it sets layout_index appropriately
-// for non-sorted lists of fields.
const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n,
upb_Arena* a) {
// TODO(salo): Replace this arena alloc with a persistent scratch buffer.
@@ -9662,10 +9620,7 @@
"field number %u in extension %s has no extension range in message %s",
(unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m));
}
-}
-void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx,
- const upb_FieldDef* f) {
const upb_MiniTableExtension* ext = _upb_FieldDef_ExtensionMiniTable(f);
if (ctx->layout) {
@@ -9684,8 +9639,8 @@
sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef);
}
bool ok2 = upb_MiniTableExtension_Build(desc.data, desc.size, mut_ext,
- upb_MessageDef_MiniTable(f->msgdef),
- sub, ctx->status);
+ upb_MessageDef_MiniTable(m), sub,
+ ctx->status);
if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table");
}
@@ -9742,7 +9697,6 @@
const UPB_DESC(FileOptions) * opts;
const char* name;
const char* package;
- const char* edition;
const upb_FileDef** deps;
const int32_t* public_deps;
@@ -9779,10 +9733,6 @@
return f->package ? f->package : "";
}
-const char* upb_FileDef_Edition(const upb_FileDef* f) {
- return f->edition ? f->edition : "";
-}
-
const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; }
upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; }
@@ -9930,14 +9880,13 @@
}
}
- upb_StringView name = UPB_DESC(FileDescriptorProto_name)(file_proto);
- file->name = strviewdup(ctx, name);
- if (strlen(file->name) != name.size) {
- _upb_DefBuilder_Errf(ctx, "File name contained embedded NULL");
+ if (!UPB_DESC(FileDescriptorProto_has_name)(file_proto)) {
+ _upb_DefBuilder_Errf(ctx, "File has no name");
}
- upb_StringView package = UPB_DESC(FileDescriptorProto_package)(file_proto);
+ file->name = strviewdup(ctx, UPB_DESC(FileDescriptorProto_name)(file_proto));
+ upb_StringView package = UPB_DESC(FileDescriptorProto_package)(file_proto);
if (package.size) {
_upb_DefBuilder_CheckIdentFull(ctx, package);
file->package = strviewdup(ctx, package);
@@ -9945,18 +9894,6 @@
file->package = NULL;
}
- upb_StringView edition = UPB_DESC(FileDescriptorProto_edition)(file_proto);
-
- if (edition.size == 0) {
- file->edition = NULL;
- } else {
- // TODO(b/267770604): How should we validate this?
- file->edition = strviewdup(ctx, edition);
- if (strlen(file->edition) != edition.size) {
- _upb_DefBuilder_Errf(ctx, "Edition name contained embedded NULL");
- }
- }
-
if (UPB_DESC(FileDescriptorProto_has_syntax)(file_proto)) {
upb_StringView syntax = UPB_DESC(FileDescriptorProto_syntax)(file_proto);
@@ -10025,7 +9962,8 @@
// Create extensions.
exts = UPB_DESC(FileDescriptorProto_extension)(file_proto, &n);
file->top_lvl_ext_count = n;
- file->top_lvl_exts = _upb_Extensions_New(ctx, n, exts, file->package, NULL);
+ file->top_lvl_exts =
+ _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL);
// Create messages.
msgs = UPB_DESC(FileDescriptorProto_message_type)(file_proto, &n);
@@ -10049,19 +9987,11 @@
_upb_FieldDef_Resolve(ctx, file->package, f);
}
- for (int i = 0; i < file->top_lvl_msg_count; i++) {
- upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
- _upb_MessageDef_CreateMiniTable(ctx, (upb_MessageDef*)m);
- }
-
- for (int i = 0; i < file->top_lvl_ext_count; i++) {
- upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i);
- _upb_FieldDef_BuildMiniTableExtension(ctx, f);
- }
-
- for (int i = 0; i < file->top_lvl_msg_count; i++) {
- upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
- _upb_MessageDef_LinkMiniTable(ctx, m);
+ if (!ctx->layout) {
+ for (int i = 0; i < file->top_lvl_msg_count; i++) {
+ upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
+ _upb_MessageDef_LinkMiniTable(ctx, m);
+ }
}
if (file->ext_count) {
@@ -10574,8 +10504,6 @@
static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m) {
upb_StringView desc;
- // Note: this will assign layout_index for fields, so upb_FieldDef_MiniTable()
- // is safe to call only after this call.
bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc);
if (!ok) _upb_DefBuilder_OomErr(ctx);
@@ -10595,6 +10523,23 @@
_upb_FieldDef_Resolve(ctx, m->full_name, f);
}
+ if (!ctx->layout) {
+ m->layout = _upb_MessageDef_MakeMiniTable(ctx, m);
+ if (!m->layout) _upb_DefBuilder_OomErr(ctx);
+ }
+
+#ifndef NDEBUG
+ for (int i = 0; i < m->field_count; i++) {
+ const upb_FieldDef* f = upb_MessageDef_Field(m, i);
+ const int layout_index = _upb_FieldDef_LayoutIndex(f);
+ UPB_ASSERT(layout_index < m->layout->field_count);
+ const upb_MiniTableField* mt_f = &m->layout->fields[layout_index];
+ UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f));
+ UPB_ASSERT(upb_FieldDef_HasPresence(f) ==
+ upb_MiniTableField_HasPresence(mt_f));
+ }
+#endif
+
m->in_message_set = false;
for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) {
upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i);
@@ -10657,39 +10602,8 @@
if (!ok) _upb_DefBuilder_OomErr(ctx);
}
-void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m) {
- if (ctx->layout == NULL) {
- m->layout = _upb_MessageDef_MakeMiniTable(ctx, m);
- } else {
- UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count);
- m->layout = ctx->layout->msgs[ctx->msg_count++];
- UPB_ASSERT(m->field_count == m->layout->field_count);
-
- // We don't need the result of this call, but it will assign layout_index
- // for all the fields in O(n lg n) time.
- _upb_FieldDefs_Sorted(m->fields, m->field_count, ctx->tmp_arena);
- }
-
- for (int i = 0; i < m->nested_msg_count; i++) {
- upb_MessageDef* nested =
- (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i);
- _upb_MessageDef_CreateMiniTable(ctx, nested);
- }
-}
-
void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m) {
- for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) {
- const upb_FieldDef* ext = upb_MessageDef_NestedExtension(m, i);
- _upb_FieldDef_BuildMiniTableExtension(ctx, ext);
- }
-
- for (int i = 0; i < m->nested_msg_count; i++) {
- _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i));
- }
-
- if (ctx->layout) return;
-
for (int i = 0; i < m->field_count; i++) {
const upb_FieldDef* f = upb_MessageDef_Field(m, i);
const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f);
@@ -10717,17 +10631,9 @@
}
}
-#ifndef NDEBUG
- for (int i = 0; i < m->field_count; i++) {
- const upb_FieldDef* f = upb_MessageDef_Field(m, i);
- const int layout_index = _upb_FieldDef_LayoutIndex(f);
- UPB_ASSERT(layout_index < m->layout->field_count);
- const upb_MiniTableField* mt_f = &m->layout->fields[layout_index];
- UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f));
- UPB_ASSERT(upb_FieldDef_HasPresence(f) ==
- upb_MiniTableField_HasPresence(mt_f));
+ for (int i = 0; i < m->nested_msg_count; i++) {
+ _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i));
}
-#endif
}
static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) {
@@ -10860,6 +10766,7 @@
m->is_sorted = true;
name = UPB_DESC(DescriptorProto_name)(msg_proto);
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
_upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG));
@@ -10878,6 +10785,17 @@
ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena);
if (!ok) _upb_DefBuilder_OomErr(ctx);
+ if (ctx->layout) {
+ /* create_fielddef() below depends on this being set. */
+ UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count);
+ m->layout = ctx->layout->msgs[ctx->msg_count++];
+ UPB_ASSERT(n_field == m->layout->field_count);
+ } else {
+ /* Allocate now (to allow cross-linking), populate later. */
+ m->layout = _upb_DefBuilder_Alloc(
+ ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry));
+ }
+
UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto);
m->oneof_count = n_oneof;
@@ -10918,7 +10836,7 @@
const UPB_DESC(FieldDescriptorProto)* const* exts =
UPB_DESC(DescriptorProto_extension)(msg_proto, &n_ext);
m->nested_ext_count = n_ext;
- m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->full_name, m);
+ m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL);
const UPB_DESC(DescriptorProto)* const* msgs =
UPB_DESC(DescriptorProto_nested_type)(msg_proto, &n_msg);
@@ -11325,6 +11243,7 @@
s->file = _upb_DefBuilder_File(ctx);
name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto);
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
const char* package = _upb_FileDef_RawPackage(s->file);
s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name);
_upb_DefBuilder_Add(ctx, s->full_name,
@@ -14092,15 +14011,6 @@
encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup);
}
-static void encode_ext(upb_encstate* e, const upb_Message_Extension* ext,
- bool is_message_set) {
- if (UPB_UNLIKELY(is_message_set)) {
- encode_msgset_item(e, ext);
- } else {
- encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field);
- }
-}
-
static void encode_message(upb_encstate* e, const upb_Message* msg,
const upb_MiniTable* m, size_t* size) {
size_t pre_len = e->limit - e->ptr;
@@ -14130,17 +14040,12 @@
size_t ext_count;
const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count);
if (ext_count) {
- if (e->options & kUpb_EncodeOption_Deterministic) {
- _upb_sortedmap sorted;
- _upb_mapsorter_pushexts(&e->sorter, ext, ext_count, &sorted);
- while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
- encode_ext(e, ext, m->ext == kUpb_ExtMode_IsMessageSet);
- }
- _upb_mapsorter_popmap(&e->sorter, &sorted);
- } else {
- const upb_Message_Extension* end = ext + ext_count;
- for (; ext != end; ext++) {
- encode_ext(e, ext, m->ext == kUpb_ExtMode_IsMessageSet);
+ const upb_Message_Extension* end = ext + ext_count;
+ for (; ext != end; ext++) {
+ if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) {
+ encode_msgset_item(e, ext);
+ } else {
+ encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field);
}
}
}
diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h
index 3de3e6d..6b554cc 100644
--- a/php/ext/google/protobuf/php-upb.h
+++ b/php/ext/google/protobuf/php-upb.h
@@ -1422,6 +1422,179 @@
#include <stdlib.h>
+#ifndef UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
+#define UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
+
+
+// Must be last.
+
+struct upb_Decoder;
+typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr,
+ upb_Message* msg, intptr_t table,
+ uint64_t hasbits, uint64_t data);
+typedef struct {
+ uint64_t field_data;
+ _upb_FieldParser* field_parser;
+} _upb_FastTable_Entry;
+
+typedef enum {
+ kUpb_ExtMode_NonExtendable = 0, // Non-extendable message.
+ kUpb_ExtMode_Extendable = 1, // Normal extendable message.
+ kUpb_ExtMode_IsMessageSet = 2, // MessageSet message.
+ kUpb_ExtMode_IsMessageSet_ITEM =
+ 3, // MessageSet item (temporary only, see decode.c)
+
+ // During table building we steal a bit to indicate that the message is a map
+ // entry. *Only* used during table building!
+ kUpb_ExtMode_IsMapEntry = 4,
+} upb_ExtMode;
+
+// upb_MiniTable represents the memory layout of a given upb_MessageDef.
+// The members are public so generated code can initialize them,
+// but users MUST NOT directly read or write any of its members.
+struct upb_MiniTable {
+ const upb_MiniTableSub* subs;
+ const upb_MiniTableField* fields;
+
+ // Must be aligned to sizeof(void*). Doesn't include internal members like
+ // unknown fields, extension dict, pointer to msglayout, etc.
+ uint16_t size;
+
+ uint16_t field_count;
+ uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1
+ uint8_t dense_below;
+ uint8_t table_mask;
+ uint8_t required_count; // Required fields have the lowest hasbits.
+
+ // To statically initialize the tables of variable length, we need a flexible
+ // array member, and we need to compile in gnu99 mode (constant initialization
+ // of flexible array members is a GNU extension, not in C99 unfortunately.
+ _upb_FastTable_Entry fasttable[];
+};
+
+// Map entries aren't actually stored for map fields, they are only used during
+// parsing. For parsing, it helps a lot if all map entry messages have the same
+// layout. The layout code in mini_table/decode.c will ensure that all map
+// entries have this layout.
+//
+// Note that users can and do create map entries directly, which will also use
+// this layout.
+//
+// NOTE: sync with mini_table/decode.c.
+typedef struct {
+ // We only need 2 hasbits max, but due to alignment we'll use 8 bytes here,
+ // and the uint64_t helps make this clear.
+ uint64_t hasbits;
+ union {
+ upb_StringView str; // For str/bytes.
+ upb_value val; // For all other types.
+ } k;
+ union {
+ upb_StringView str; // For str/bytes.
+ upb_value val; // For all other types.
+ } v;
+} upb_MapEntryData;
+
+typedef struct {
+ void* internal_data;
+ upb_MapEntryData data;
+} upb_MapEntry;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Computes a bitmask in which the |l->required_count| lowest bits are set,
+// except that we skip the lowest bit (because upb never uses hasbit 0).
+//
+// Sample output:
+// requiredmask(1) => 0b10 (0x2)
+// requiredmask(5) => 0b111110 (0x3e)
+UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) {
+ int n = l->required_count;
+ assert(0 < n && n <= 63);
+ return ((1ULL << n) - 1) << 1;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif /* UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ */
+
+// Must be last.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// _upb_mapsorter sorts maps and provides ordered iteration over the entries.
+// Since maps can be recursive (map values can be messages which contain other
+// maps), _upb_mapsorter can contain a stack of maps.
+
+typedef struct {
+ upb_tabent const** entries;
+ int size;
+ int cap;
+} _upb_mapsorter;
+
+typedef struct {
+ int start;
+ int pos;
+ int end;
+} _upb_sortedmap;
+
+UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) {
+ s->entries = NULL;
+ s->size = 0;
+ s->cap = 0;
+}
+
+UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) {
+ if (s->entries) free(s->entries);
+}
+
+UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map,
+ _upb_sortedmap* sorted, upb_MapEntry* ent) {
+ if (sorted->pos == sorted->end) return false;
+ const upb_tabent* tabent = s->entries[sorted->pos++];
+ upb_StringView key = upb_tabstrview(tabent->key);
+ _upb_map_fromkey(key, &ent->data.k, map->key_size);
+ upb_value val = {tabent->val.val};
+ _upb_map_fromvalue(val, &ent->data.v, map->val_size);
+ return true;
+}
+
+UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s,
+ _upb_sortedmap* sorted) {
+ s->size = sorted->start;
+}
+
+bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
+ const upb_Map* map, _upb_sortedmap* sorted);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ */
+
+/*
+** Our memory representation for parsing tables and messages themselves.
+** Functions in this file are used by generated code and possibly reflection.
+**
+** The definitions in this file are internal to upb.
+**/
+
+#ifndef UPB_MESSAGE_INTERNAL_H_
+#define UPB_MESSAGE_INTERNAL_H_
+
+#include <stdlib.h>
+#include <string.h>
+
+
#ifndef UPB_MESSAGE_EXTENSION_INTERNAL_H_
#define UPB_MESSAGE_EXTENSION_INTERNAL_H_
@@ -1694,191 +1867,6 @@
#endif /* UPB_MESSAGE_EXTENSION_INTERNAL_H_ */
-#ifndef UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
-#define UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
-
-
-// Must be last.
-
-struct upb_Decoder;
-typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr,
- upb_Message* msg, intptr_t table,
- uint64_t hasbits, uint64_t data);
-typedef struct {
- uint64_t field_data;
- _upb_FieldParser* field_parser;
-} _upb_FastTable_Entry;
-
-typedef enum {
- kUpb_ExtMode_NonExtendable = 0, // Non-extendable message.
- kUpb_ExtMode_Extendable = 1, // Normal extendable message.
- kUpb_ExtMode_IsMessageSet = 2, // MessageSet message.
- kUpb_ExtMode_IsMessageSet_ITEM =
- 3, // MessageSet item (temporary only, see decode.c)
-
- // During table building we steal a bit to indicate that the message is a map
- // entry. *Only* used during table building!
- kUpb_ExtMode_IsMapEntry = 4,
-} upb_ExtMode;
-
-// upb_MiniTable represents the memory layout of a given upb_MessageDef.
-// The members are public so generated code can initialize them,
-// but users MUST NOT directly read or write any of its members.
-struct upb_MiniTable {
- const upb_MiniTableSub* subs;
- const upb_MiniTableField* fields;
-
- // Must be aligned to sizeof(void*). Doesn't include internal members like
- // unknown fields, extension dict, pointer to msglayout, etc.
- uint16_t size;
-
- uint16_t field_count;
- uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1
- uint8_t dense_below;
- uint8_t table_mask;
- uint8_t required_count; // Required fields have the lowest hasbits.
-
- // To statically initialize the tables of variable length, we need a flexible
- // array member, and we need to compile in gnu99 mode (constant initialization
- // of flexible array members is a GNU extension, not in C99 unfortunately.
- _upb_FastTable_Entry fasttable[];
-};
-
-// Map entries aren't actually stored for map fields, they are only used during
-// parsing. For parsing, it helps a lot if all map entry messages have the same
-// layout. The layout code in mini_table/decode.c will ensure that all map
-// entries have this layout.
-//
-// Note that users can and do create map entries directly, which will also use
-// this layout.
-//
-// NOTE: sync with mini_table/decode.c.
-typedef struct {
- // We only need 2 hasbits max, but due to alignment we'll use 8 bytes here,
- // and the uint64_t helps make this clear.
- uint64_t hasbits;
- union {
- upb_StringView str; // For str/bytes.
- upb_value val; // For all other types.
- } k;
- union {
- upb_StringView str; // For str/bytes.
- upb_value val; // For all other types.
- } v;
-} upb_MapEntryData;
-
-typedef struct {
- void* internal_data;
- upb_MapEntryData data;
-} upb_MapEntry;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Computes a bitmask in which the |l->required_count| lowest bits are set,
-// except that we skip the lowest bit (because upb never uses hasbit 0).
-//
-// Sample output:
-// requiredmask(1) => 0b10 (0x2)
-// requiredmask(5) => 0b111110 (0x3e)
-UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) {
- int n = l->required_count;
- assert(0 < n && n <= 63);
- return ((1ULL << n) - 1) << 1;
-}
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-
-#endif /* UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ */
-
-// Must be last.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// _upb_mapsorter sorts maps and provides ordered iteration over the entries.
-// Since maps can be recursive (map values can be messages which contain other
-// maps), _upb_mapsorter can contain a stack of maps.
-
-typedef struct {
- void const** entries;
- int size;
- int cap;
-} _upb_mapsorter;
-
-typedef struct {
- int start;
- int pos;
- int end;
-} _upb_sortedmap;
-
-UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) {
- s->entries = NULL;
- s->size = 0;
- s->cap = 0;
-}
-
-UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) {
- if (s->entries) free(s->entries);
-}
-
-UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map,
- _upb_sortedmap* sorted, upb_MapEntry* ent) {
- if (sorted->pos == sorted->end) return false;
- const upb_tabent* tabent = (const upb_tabent*)s->entries[sorted->pos++];
- upb_StringView key = upb_tabstrview(tabent->key);
- _upb_map_fromkey(key, &ent->data.k, map->key_size);
- upb_value val = {tabent->val.val};
- _upb_map_fromvalue(val, &ent->data.v, map->val_size);
- return true;
-}
-
-UPB_INLINE bool _upb_sortedmap_nextext(_upb_mapsorter* s,
- _upb_sortedmap* sorted,
- const upb_Message_Extension** ext) {
- if (sorted->pos == sorted->end) return false;
- *ext = (const upb_Message_Extension*)s->entries[sorted->pos++];
- return true;
-}
-
-UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s,
- _upb_sortedmap* sorted) {
- s->size = sorted->start;
-}
-
-bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
- const upb_Map* map, _upb_sortedmap* sorted);
-
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s,
- const upb_Message_Extension* exts, size_t count,
- _upb_sortedmap* sorted);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-
-#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ */
-
-/*
-** Our memory representation for parsing tables and messages themselves.
-** Functions in this file are used by generated code and possibly reflection.
-**
-** The definitions in this file are internal to upb.
-**/
-
-#ifndef UPB_MESSAGE_INTERNAL_H_
-#define UPB_MESSAGE_INTERNAL_H_
-
-#include <stdlib.h>
-#include <string.h>
-
-
#ifndef UPB_MINI_TABLE_EXTENSION_REGISTRY_H_
#define UPB_MINI_TABLE_EXTENSION_REGISTRY_H_
@@ -8338,7 +8326,6 @@
const char* upb_FileDef_Name(const upb_FileDef* f);
const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f);
const char* upb_FileDef_Package(const upb_FileDef* f);
-const char* upb_FileDef_Edition(const upb_FileDef* f);
const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f);
const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i);
@@ -8724,7 +8711,7 @@
upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s);
bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext,
- const upb_FieldDef* f);
+ upb_FieldDef* f);
bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v,
upb_Status* status);
bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size,
@@ -10210,6 +10197,23 @@
void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name,
bool full);
+// Verify a relative identifier string. The loop is branchless for speed.
+UPB_INLINE void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx,
+ upb_StringView name) {
+ bool good = name.size > 0;
+
+ for (size_t i = 0; i < name.size; i++) {
+ const char c = name.data[i];
+ const char d = c | 0x20; // force lowercase
+ const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_');
+ const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0);
+
+ good &= is_alpha | is_numer;
+ }
+
+ if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false);
+}
+
// Verify a full identifier string. This is slightly more complicated than
// verifying a relative identifier string because we must track '.' chars.
UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx,
@@ -10313,14 +10317,6 @@
uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f);
void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix,
upb_FieldDef* f);
-void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx,
- const upb_FieldDef* f);
-
-// Allocate and initialize an array of |n| extensions (field defs).
-upb_FieldDef* _upb_Extensions_New(
- upb_DefBuilder* ctx, int n,
- const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix,
- upb_MessageDef* m);
// Allocate and initialize an array of |n| field defs.
upb_FieldDef* _upb_FieldDefs_New(
@@ -10385,7 +10381,6 @@
void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m,
const upb_FieldDef* f);
bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n);
-void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m);
void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m);
void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m);
diff --git a/php/generate_descriptor_protos.sh b/php/generate_descriptor_protos.sh
index a9af40c..56d95d8 100755
--- a/php/generate_descriptor_protos.sh
+++ b/php/generate_descriptor_protos.sh
@@ -6,11 +6,11 @@
set -e
if [[ -z "${PROTOC}" ]]; then
- PROTOC=$(realpath protoc)
+ PROTOC=$(pwd)/protoc
fi
if [ ! -f $PROTOC ]; then
${BAZEL:-bazel} $BAZEL_STARTUP_FLAGS build -c opt //:protoc $BAZEL_FLAGS
- PROTOC=$(realpath bazel-bin/protoc)
+ PROTOC=$(pwd)/bazel-bin/protoc
fi
if test ! -e src/google/protobuf/stubs/common.h; then
diff --git a/php/src/Google/Protobuf/Internal/RepeatedField.php b/php/src/Google/Protobuf/Internal/RepeatedField.php
index ea7971f..f6ecd1c 100644
--- a/php/src/Google/Protobuf/Internal/RepeatedField.php
+++ b/php/src/Google/Protobuf/Internal/RepeatedField.php
@@ -219,13 +219,13 @@
public function offsetUnset($offset)
{
$count = count($this->container);
- if (!is_numeric($offset) || $count === 0 || $offset !== $count - 1) {
+ if (!is_numeric($offset) || $count === 0 || $offset < 0 || $offset >= $count) {
trigger_error(
"Cannot remove element at the given index",
E_USER_ERROR);
return;
}
- array_pop($this->container);
+ array_splice($this->container, $offset, 1);
}
/**
diff --git a/php/tests/ArrayTest.php b/php/tests/ArrayTest.php
index 9e8fcb8..2cade79 100644
--- a/php/tests/ArrayTest.php
+++ b/php/tests/ArrayTest.php
@@ -655,4 +655,31 @@
$arr2 = clone $arr;
$this->assertSame($arr[0], $arr2[0]);
}
+
+ #########################################################
+ # Test offsetUnset
+ #########################################################
+
+ public function testOffsetUnset()
+ {
+ $arr = new RepeatedField(GPBType::INT32);
+ $arr[] = 0;
+ $arr[] = 1;
+ $arr[] = 2;
+
+ $this->assertSame(3, count($arr));
+ $this->assertSame(0, $arr[0]);
+ $this->assertSame(1, $arr[1]);
+ $this->assertSame(2, $arr[2]);
+
+ $arr->offsetUnset(1);
+ $this->assertSame(0, $arr[0]);
+ $this->assertSame(2, $arr[1]);
+
+ $arr->offsetUnset(0);
+ $this->assertSame(2, $arr[0]);
+
+ $arr->offsetUnset(0);
+ $this->assertCount(0, $arr);
+ }
}
diff --git a/php/tests/compile_extension.sh b/php/tests/compile_extension.sh
index 5f7a6cc..91ed1d4 100755
--- a/php/tests/compile_extension.sh
+++ b/php/tests/compile_extension.sh
@@ -33,6 +33,6 @@
echo "$FINGERPRINT" > BUILD_STAMP
fi
-make
-TEST_PHP_ARGS="-q" make test
+make -j8
+TEST_PHP_ARGS="-q" make -j8 test
popd > /dev/null
diff --git a/pkg/BUILD.bazel b/pkg/BUILD.bazel
index 4edda57..4f7e446 100644
--- a/pkg/BUILD.bazel
+++ b/pkg/BUILD.bazel
@@ -404,6 +404,7 @@
"//src/google/protobuf/compiler/php",
"//src/google/protobuf/compiler/python",
"//src/google/protobuf/compiler/ruby",
+ "//src/google/protobuf/compiler/rust",
],
dist_deps = [
":protobuf",
diff --git a/protobuf_deps.bzl b/protobuf_deps.bzl
index 5686623..fee1e9c 100644
--- a/protobuf_deps.bzl
+++ b/protobuf_deps.bzl
@@ -149,7 +149,7 @@
_github_archive(
name = "upb",
repo = "https://github.com/protocolbuffers/upb",
- commit = "9d69c47896648691e854b7078478ed4320efbcab",
- sha256 = "4b67f05495abfd886227fdae841cdf8c54d0e99b9907ed15b318a451082e9647",
+ commit = "662497f1d3dcced2bba1620cea9aae8b484bd3cd",
+ sha256 = "57c87ca4145d2cbc162a6c613b114b9325b577f4f6525bd78747a34b3d03627c",
patches = ["@com_google_protobuf//build_defs:upb.patch"],
)
diff --git a/python/README.md b/python/README.md
index 6549fb6..dc4b1d0 100644
--- a/python/README.md
+++ b/python/README.md
@@ -1,130 +1,105 @@
-Protocol Buffers - Google's data interchange format
-===================================================
+# Protocol Buffers Python
-Copyright 2008 Google Inc.
+This directory contains the Protobuf library for Python.
-This directory contains the Python Protocol Buffers runtime library.
+In most cases you should install the library using `pip` or another package
+manager:
-Normally, this directory comes as part of the protobuf package, available
-from:
+```
+$ pip install protobuf
+```
- https://developers.google.com/protocol-buffers/
+The packages released on https://pypi.org/project/protobuf/#files include both a
+source distribution and binary wheels.
-The complete package includes the C++ source code, which includes the
-Protocol Compiler (protoc). If you downloaded this package from PyPI
-or some other Python-specific source, you may have received only the
-Python part of the code. In this case, you will need to obtain the
-Protocol Compiler from some other source before you can use this
-package.
+For user documentation about how to use Protobuf Python, see
+https://protobuf.dev/getting-started/pythontutorial/
-Development Warning
-===================
+# Building packages from this repo
-The pure python performance is slow. For better performance please
-use python c++ implementation.
+If for some reason you wish to build the packages directly from this repo, you
+can use the following Bazel commands:
-Installation
-============
+```
+$ bazel build @upb//python/dist:source_wheel
+$ bazel build @upb//python/dist:binary_wheel
+```
-1) Make sure you have Python 3.7 or newer. If in doubt, run:
+The binary wheel will build against whatever version of Python is installed on
+your system. The source package is always the same and does not depend on a
+local version of Python.
- $ python -V
+# Implementation backends
-2) Make sure you have Bazel 0.5.4 or later (or CMake 3.5 or later).
+There are three separate implementations of Python Protobuf. All of them offer
+the same API and are thus functionally the same, though they have very different
+performance characteristics.
-3) If you do not have setuptools installed, note that it will be
- downloaded and installed automatically as soon as you run `setup.py`.
- If you would rather install it manually, you may do so by following
- the instructions on [this page](https://packaging.python.org/en/latest/tutorials/installing-packages/).
+The runtime library contains a switching layer that can choose between these
+backends at runtime. Normally it will choose between them automatically, using
+priority-ordered list, and skipping any backends that are not available. However
+you can request a specific backend by setting the
+`PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION` environment variable to one of the
+following values:
-4) Build the C++ code, or install a binary distribution of `protoc`. If
- you install a binary distribution, make sure that it is the same
- version as this package. If in doubt, run:
+1. **upb**: Built on the
+ [upb C library](https://github.com/protocolbuffers/upb), this is a new
+ extension module
+ [released in 4.21.0](https://protobuf.dev/news/2022-05-06/). It offers
+ better performance than any of the previous backends, and it is now the
+ default. It is distributed in our PyPI packages, and requires no special
+ installation. The code for this module lives in
+ [@upb/python](https://github.com/protocolbuffers/upb/tree/main/python).
+1. **cpp**: This extension module wraps the C++ protobuf library. It is
+ deprecated and is no longer released in our PyPI packages, however it is
+ still used in some legacy cases where apps want to perform zero-copy message
+ sharing between Python and C++. It must be installed separately before it
+ can be used. The code for this module lives in
+ [google/protobuf/pyext](https://github.com/protocolbuffers/protobuf/tree/main/python/google/protobuf/pyext).
+1. **python**: The pure-Python backend, this does not require any extension
+ module to be present on the system. The code for the pure-Python backend
+ lives in [google/protobuf/internal](google/protobuf/internal)
- $ protoc --version
+The order given above is the general priority order, with `upb` being preferred
+the most and the `python` backend preferred the least. However this ordering can
+be overridden by the presence of a
+`google.protobuf.internal._api_implementation` module. See the logic in
+[api_implementation.py](https://github.com/protocolbuffers/protobuf/blob/main/python/google/protobuf/internal/api_implementation.py)
+for details.
-5) Build and run the tests:
+You can check which backend you are using with the following snippet:
- $ python setup.py build
- $ python setup.py test
+```
+$ python
+Python 3.10.9 (main, Dec 7 2022, 13:47:07) [GCC 12.2.0] on linux
+Type "help", "copyright", "credits" or "license" for more information.
+>>> from google.protobuf.internal import api_implementation
+>>> print(api_implementation.Type())
+upb
+```
- To build, test, and use the C++ implementation, you must first compile
- `libprotobuf.so` using either [Bazel](../README.md) or [CMake](../src/README.md):
+This is not an officially-supported or stable API, but it is useful for ad hoc
+diagnostics.
- On OS X:
+More information about sharing messages between Python and C++ is available
+here: https://protobuf.dev/reference/python/python-generated/#sharing-messages
- If you are running a Homebrew-provided Python, you must make sure another
- version of protobuf is not already installed, as Homebrew's Python will
- search `/usr/local/lib` for `libprotobuf.so` before it searches the compiled
- binaries.
+# Code generator
- You can either unlink Homebrew's protobuf or install the `libprotobuf` you
- built earlier:
+The code for the Protobuf Python code generator lives in
+[//src/google/protobuf/compiler/python](https://github.com/protocolbuffers/protobuf/tree/main/src/google/protobuf/compiler/python).
+The code generator can output two different files for each proto `foo.proto`:
- $ brew unlink protobuf
+* **foo_pb2.py**: The module you import to actually use the protos.
+* **foo_pb2.pyi**: A stub file that describes the interface of the protos.
- or
+The `foo_pb2.pyi` file is useful for IDEs or for users who want to read the
+output file. The `foo_pb2.py` file is optimized for fast loading and is not
+readable at all.
- $ (cd .. && cmake . && make install)
+Note that the pyi file is only generated if you pass the `pyi_out` option to
+`protoc`:
- On other *nix:
-
- You must make `libprotobuf.so` dynamically available. You can either
- install libprotobuf you built earlier, or set `LD_LIBRARY_PATH`:
-
- $ (cd .. && cmake . && make -j20 install)
-
- or
-
- $ export LD_LIBRARY_PATH=../bazel-bin
-
- To build the C++ implementation run:
-
- $ python setup.py build --cpp_implementation
-
- Then run the tests like so:
-
- $ python setup.py test --cpp_implementation
-
- If some tests fail, this library may not work correctly on your
- system. Continue at your own risk.
-
- Please note that there is a known problem with some versions of
- Python on Cygwin which causes the tests to fail after printing the
- error: `sem_init: Resource temporarily unavailable`. This appears
- to be a [bug either in Cygwin or in
- Python](http://www.cygwin.com/ml/cygwin/2005-07/msg01378.html).
-
- We do not know if or when it might be fixed. We also do not know
- how likely it is that this bug will affect users in practice.
-
-6) Install:
-
- $ python setup.py install
-
- or:
-
- $ (cd .. && make install)
- $ python setup.py install --cpp_implementation
-
- This step may require superuser privileges.
- NOTE: To use C++ implementation, you need to export an environment
- variable before running your program. See the "C++ Implementation"
- section below for more details.
-
-Usage
-=====
-
-The complete documentation for Protocol Buffers is available via the
-web at:
-
- https://developers.google.com/protocol-buffers/
-
-C++ Implementation
-==================
-
-The C++ implementation for Python messages is built as a Python extension to
-improve the overall protobuf Python performance.
-
-To use the C++ implementation, you need to install the C++ protobuf runtime
-library, please see instructions in the parent directory.
+```
+$ protoc --python_out=pyi_out:output_dir
+```
diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py
index 291b97d..a4370ac 100644
--- a/python/google/protobuf/internal/generator_test.py
+++ b/python/google/protobuf/internal/generator_test.py
@@ -49,6 +49,7 @@
from google.protobuf import unittest_mset_pb2
from google.protobuf import unittest_mset_wire_format_pb2
from google.protobuf import unittest_pb2
+from google.protobuf import unittest_retention_pb2
from google.protobuf import unittest_custom_options_pb2
from google.protobuf import unittest_no_generic_services_pb2
@@ -152,6 +153,82 @@
# TODO(gps): We really should test for the presence of the enum_opt1
# extension and for its value to be set to -789.
+ # Options that are explicitly marked RETENTION_SOURCE should not be present
+ # in the descriptors in the binary.
+ def testOptionRetention(self):
+ # Direct options
+ options = unittest_retention_pb2.DESCRIPTOR.GetOptions()
+ self.assertTrue(options.HasExtension(unittest_retention_pb2.plain_option))
+ self.assertTrue(
+ options.HasExtension(unittest_retention_pb2.runtime_retention_option)
+ )
+ self.assertFalse(
+ options.HasExtension(unittest_retention_pb2.source_retention_option)
+ )
+
+ def check_options_message_is_stripped_correctly(options):
+ self.assertEqual(options.plain_field, 1)
+ self.assertEqual(options.runtime_retention_field, 2)
+ self.assertFalse(options.HasField('source_retention_field'))
+ self.assertEqual(options.source_retention_field, 0)
+
+ # Verify that our test OptionsMessage is stripped correctly on all
+ # different entity types.
+ check_options_message_is_stripped_correctly(
+ options.Extensions[unittest_retention_pb2.file_option]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2.TopLevelMessage.DESCRIPTOR.GetOptions().Extensions[
+ unittest_retention_pb2.message_option
+ ]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2.TopLevelMessage.NestedMessage.DESCRIPTOR.GetOptions().Extensions[
+ unittest_retention_pb2.message_option
+ ]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2._TOPLEVELENUM.GetOptions().Extensions[
+ unittest_retention_pb2.enum_option
+ ]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2._TOPLEVELMESSAGE_NESTEDENUM.GetOptions().Extensions[
+ unittest_retention_pb2.enum_option
+ ]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2._TOPLEVELENUM.values[0]
+ .GetOptions()
+ .Extensions[unittest_retention_pb2.enum_entry_option]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2.DESCRIPTOR.extensions_by_name['i']
+ .GetOptions()
+ .Extensions[unittest_retention_pb2.field_option]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2.TopLevelMessage.DESCRIPTOR.fields[0]
+ .GetOptions()
+ .Extensions[unittest_retention_pb2.field_option]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2.TopLevelMessage.DESCRIPTOR.oneofs[0]
+ .GetOptions()
+ .Extensions[unittest_retention_pb2.oneof_option]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2.DESCRIPTOR.services_by_name['Service']
+ .GetOptions()
+ .Extensions[unittest_retention_pb2.service_option]
+ )
+ check_options_message_is_stripped_correctly(
+ unittest_retention_pb2.DESCRIPTOR.services_by_name['Service']
+ .methods[0]
+ .GetOptions()
+ .Extensions[unittest_retention_pb2.method_option]
+ )
+
def testNestedTypes(self):
self.assertEqual(
set(unittest_pb2.TestAllTypes.DESCRIPTOR.nested_types),
diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py
index 48077b0..d1102b8 100644
--- a/python/google/protobuf/internal/proto_builder_test.py
+++ b/python/google/protobuf/internal/proto_builder_test.py
@@ -33,8 +33,8 @@
import collections
import unittest
-from google.protobuf import descriptor_pb2 # pylint: disable=g-import-not-at-top
from google.protobuf import descriptor
+from google.protobuf import descriptor_pb2
from google.protobuf import descriptor_pool
from google.protobuf import proto_builder
from google.protobuf import text_format
@@ -43,6 +43,8 @@
class ProtoBuilderTest(unittest.TestCase):
def setUp(self):
+ super().setUp()
+
self.ordered_fields = collections.OrderedDict([
('foo', descriptor_pb2.FieldDescriptorProto.TYPE_INT64),
('bar', descriptor_pb2.FieldDescriptorProto.TYPE_STRING),
diff --git a/python/google/protobuf/message_factory.py b/python/google/protobuf/message_factory.py
index fac1165..74dd4a6 100644
--- a/python/google/protobuf/message_factory.py
+++ b/python/google/protobuf/message_factory.py
@@ -163,10 +163,9 @@
Returns:
A class describing the passed in descriptor.
"""
- # TODO(b/258832141): add this warning
- # warnings.warn('MessageFactory class is deprecated. Please use '
- # 'GetMessageClass() instead of MessageFactory.GetPrototype. '
- # 'MessageFactory class will be removed after 2024.')
+ warnings.warn('MessageFactory class is deprecated. Please use '
+ 'GetMessageClass() instead of MessageFactory.GetPrototype. '
+ 'MessageFactory class will be removed after 2024.')
return GetMessageClass(descriptor)
def CreatePrototype(self, descriptor):
@@ -181,10 +180,9 @@
Returns:
A class describing the passed in descriptor.
"""
- # TODO(b/258832141): add this warning
- # warnings.warn('Directly call CreatePrototype is wrong. Please use '
- # 'GetMessageClass() method instead. Directly use '
- # 'CreatePrototype will raise error after July 2023.')
+ warnings.warn('Directly call CreatePrototype is wrong. Please use '
+ 'GetMessageClass() method instead. Directly use '
+ 'CreatePrototype will raise error after July 2023.')
return _InternalCreateMessageClass(descriptor)
def GetMessages(self, files):
@@ -201,11 +199,10 @@
any dependent messages as well as any messages defined in the same file as
a specified message.
"""
- # TODO(b/258832141): add this warning
- # warnings.warn('MessageFactory class is deprecated. Please use '
- # 'GetMessageClassesForFiles() instead of '
- # 'MessageFactory.GetMessages(). MessageFactory class '
- # 'will be removed after 2024.')
+ warnings.warn('MessageFactory class is deprecated. Please use '
+ 'GetMessageClassesForFiles() instead of '
+ 'MessageFactory.GetMessages(). MessageFactory class '
+ 'will be removed after 2024.')
return GetMessageClassesForFiles(files, self.pool)
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index 7d690c1..d2784fd 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -437,7 +437,10 @@
self->version++;
}
- if (!PythonToMapValueRef(self, v, reflection->SupportsUnknownEnumValues(),
+ if (!PythonToMapValueRef(self, v,
+ !self->parent_field_descriptor->message_type()
+ ->map_value()
+ ->legacy_enum_field_treated_as_closed(),
&value)) {
return -1;
}
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 3ff31e2..d5693bb 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -2300,7 +2300,7 @@
}
case FieldDescriptor::CPPTYPE_ENUM: {
PROTOBUF_CHECK_GET_INT32(arg, value, -1);
- if (reflection->SupportsUnknownEnumValues()) {
+ if (!field_descriptor->legacy_enum_field_treated_as_closed()) {
reflection->SetEnumValue(message, field_descriptor, value);
} else {
const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
diff --git a/python/google/protobuf/pyext/repeated_scalar_container.cc b/python/google/protobuf/pyext/repeated_scalar_container.cc
index b19f004..ba24f0f 100644
--- a/python/google/protobuf/pyext/repeated_scalar_container.cc
+++ b/python/google/protobuf/pyext/repeated_scalar_container.cc
@@ -151,7 +151,7 @@
}
case FieldDescriptor::CPPTYPE_ENUM: {
PROTOBUF_CHECK_GET_INT32(arg, value, -1);
- if (reflection->SupportsUnknownEnumValues()) {
+ if (!field_descriptor->legacy_enum_field_treated_as_closed()) {
reflection->SetRepeatedEnumValue(message, field_descriptor, index,
value);
} else {
@@ -376,7 +376,7 @@
}
case FieldDescriptor::CPPTYPE_ENUM: {
PROTOBUF_CHECK_GET_INT32(item, value, nullptr);
- if (reflection->SupportsUnknownEnumValues()) {
+ if (!field_descriptor->legacy_enum_field_treated_as_closed()) {
reflection->AddEnumValue(message, field_descriptor, value);
} else {
const EnumDescriptor* enum_descriptor = field_descriptor->enum_type();
diff --git a/regenerate_stale_files.sh b/regenerate_stale_files.sh
index 1c38104..58c640b 100755
--- a/regenerate_stale_files.sh
+++ b/regenerate_stale_files.sh
@@ -15,6 +15,7 @@
# Run and fix all staleness tests.
${BazelBin} test src:cmake_lists_staleness_test "$@" || ./bazel-bin/src/cmake_lists_staleness_test --fix
${BazelBin} test src/google/protobuf:well_known_types_staleness_test "$@" || ./bazel-bin/src/google/protobuf/well_known_types_staleness_test --fix
+${BazelBin} test objectivec:well_known_types_staleness_test "$@" || ./bazel-bin/objectivec/well_known_types_staleness_test --fix
# Generate C# code.
# This doesn't currently have Bazel staleness tests, but there's an existing
diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c
index fb1f5dc..75555fc 100644
--- a/ruby/ext/google/protobuf_c/defs.c
+++ b/ruby/ext/google/protobuf_c/defs.c
@@ -223,6 +223,8 @@
typedef struct {
const upb_MessageDef* msgdef;
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
VALUE klass;
VALUE descriptor_pool;
} Descriptor;
@@ -238,7 +240,7 @@
static const rb_data_type_t Descriptor_type = {
"Google::Protobuf::Descriptor",
{Descriptor_mark, RUBY_DEFAULT_FREE, NULL},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static Descriptor* ruby_to_Descriptor(VALUE val) {
@@ -280,7 +282,7 @@
"Descriptor objects may not be created from Ruby.");
}
- self->descriptor_pool = descriptor_pool;
+ RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
self->msgdef = (const upb_MessageDef*)NUM2ULL(ptr);
return Qnil;
@@ -390,7 +392,7 @@
static VALUE Descriptor_msgclass(VALUE _self) {
Descriptor* self = ruby_to_Descriptor(_self);
if (self->klass == Qnil) {
- self->klass = build_class_from_descriptor(_self);
+ RB_OBJ_WRITE(_self, &self->klass, build_class_from_descriptor(_self));
}
return self->klass;
}
@@ -417,6 +419,8 @@
typedef struct {
const upb_FileDef* filedef;
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
VALUE descriptor_pool; // Owns the upb_FileDef.
} FileDescriptor;
@@ -430,7 +434,7 @@
static const rb_data_type_t FileDescriptor_type = {
"Google::Protobuf::FileDescriptor",
{FileDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static FileDescriptor* ruby_to_FileDescriptor(VALUE val) {
@@ -463,7 +467,7 @@
"Descriptor objects may not be created from Ruby.");
}
- self->descriptor_pool = descriptor_pool;
+ RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
self->filedef = (const upb_FileDef*)NUM2ULL(ptr);
return Qnil;
@@ -519,6 +523,8 @@
typedef struct {
const upb_FieldDef* fielddef;
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
VALUE descriptor_pool; // Owns the upb_FieldDef.
} FieldDescriptor;
@@ -532,7 +538,7 @@
static const rb_data_type_t FieldDescriptor_type = {
"Google::Protobuf::FieldDescriptor",
{FieldDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static FieldDescriptor* ruby_to_FieldDescriptor(VALUE val) {
@@ -570,7 +576,7 @@
"Descriptor objects may not be created from Ruby.");
}
- self->descriptor_pool = descriptor_pool;
+ RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
self->fielddef = (const upb_FieldDef*)NUM2ULL(ptr);
return Qnil;
@@ -884,6 +890,8 @@
typedef struct {
const upb_OneofDef* oneofdef;
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
VALUE descriptor_pool; // Owns the upb_OneofDef.
} OneofDescriptor;
@@ -897,7 +905,7 @@
static const rb_data_type_t OneofDescriptor_type = {
"Google::Protobuf::OneofDescriptor",
{OneofDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static OneofDescriptor* ruby_to_OneofDescriptor(VALUE val) {
@@ -936,7 +944,7 @@
"Descriptor objects may not be created from Ruby.");
}
- self->descriptor_pool = descriptor_pool;
+ RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
self->oneofdef = (const upb_OneofDef*)NUM2ULL(ptr);
return Qnil;
@@ -988,6 +996,8 @@
typedef struct {
const upb_EnumDef* enumdef;
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
VALUE module; // begins as nil
VALUE descriptor_pool; // Owns the upb_EnumDef.
} EnumDescriptor;
@@ -1003,7 +1013,7 @@
static const rb_data_type_t EnumDescriptor_type = {
"Google::Protobuf::EnumDescriptor",
{EnumDescriptor_mark, RUBY_DEFAULT_FREE, NULL},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static EnumDescriptor* ruby_to_EnumDescriptor(VALUE val) {
@@ -1042,7 +1052,7 @@
"Descriptor objects may not be created from Ruby.");
}
- self->descriptor_pool = descriptor_pool;
+ RB_OBJ_WRITE(_self, &self->descriptor_pool, descriptor_pool);
self->enumdef = (const upb_EnumDef*)NUM2ULL(ptr);
return Qnil;
@@ -1138,7 +1148,7 @@
static VALUE EnumDescriptor_enummodule(VALUE _self) {
EnumDescriptor* self = ruby_to_EnumDescriptor(_self);
if (self->module == Qnil) {
- self->module = build_module_from_enumdesc(_self);
+ RB_OBJ_WRITE(_self, &self->module, build_module_from_enumdesc(_self));
}
return self->module;
}
diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c
index 99e2946..ab19d27 100644
--- a/ruby/ext/google/protobuf_c/message.c
+++ b/ruby/ext/google/protobuf_c/message.c
@@ -53,6 +53,8 @@
// -----------------------------------------------------------------------------
typedef struct {
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
VALUE arena;
const upb_Message* msg; // Can get as mutable when non-frozen.
const upb_MessageDef*
@@ -65,9 +67,9 @@
}
static rb_data_type_t Message_type = {
- "Message",
+ "Google::Protobuf::Message",
{Message_mark, RUBY_DEFAULT_FREE, NULL},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static Message* ruby_to_Message(VALUE msg_rb) {
@@ -105,7 +107,7 @@
void Message_InitPtr(VALUE self_, upb_Message* msg, VALUE arena) {
Message* self = ruby_to_Message(self_);
self->msg = msg;
- self->arena = arena;
+ RB_OBJ_WRITE(self_, &self->arena, arena);
ObjectCache_Add(msg, self_);
}
@@ -1162,6 +1164,12 @@
Qfalse))) {
options |= upb_JsonEncode_EmitDefaults;
}
+
+ if (RTEST(rb_hash_lookup2(hash_args,
+ ID2SYM(rb_intern("format_enums_as_integers")),
+ Qfalse))) {
+ options |= upb_JsonEncode_FormatEnumsAsIntegers;
+ }
}
upb_Status_Clear(&status);
diff --git a/ruby/ext/google/protobuf_c/protobuf.c b/ruby/ext/google/protobuf_c/protobuf.c
index 3c765c5..bee8ac2 100644
--- a/ruby/ext/google/protobuf_c/protobuf.c
+++ b/ruby/ext/google/protobuf_c/protobuf.c
@@ -171,6 +171,8 @@
typedef struct {
upb_Arena *arena;
+ // IMPORTANT: WB_PROTECTED objects must only use the RB_OBJ_WRITE()
+ // macro to update VALUE references, as to trigger write barriers.
VALUE pinned_objs;
} Arena;
@@ -190,7 +192,7 @@
const rb_data_type_t Arena_type = {
"Google::Protobuf::Internal::Arena",
{Arena_mark, Arena_free, NULL},
- .flags = RUBY_TYPED_FREE_IMMEDIATELY,
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};
static void* ruby_upb_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, size_t size) {
@@ -233,7 +235,7 @@
Arena *arena;
TypedData_Get_Struct(_arena, Arena, &Arena_type, arena);
if (arena->pinned_objs == Qnil) {
- arena->pinned_objs = rb_ary_new();
+ RB_OBJ_WRITE(_arena, &arena->pinned_objs, rb_ary_new());
}
rb_ary_push(arena->pinned_objs, obj);
}
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c
index bda70b2..6fbf78b 100644
--- a/ruby/ext/google/protobuf_c/ruby-upb.c
+++ b/ruby/ext/google/protobuf_c/ruby-upb.c
@@ -641,12 +641,14 @@
[kUpb_FieldType_Bytes] = _upb_mapsorter_cmpstr,
};
-static bool _upb_mapsorter_resize(_upb_mapsorter* s, _upb_sortedmap* sorted,
- int size) {
+bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
+ const upb_Map* map, _upb_sortedmap* sorted) {
+ int map_size = _upb_Map_Size(map);
sorted->start = s->size;
sorted->pos = sorted->start;
- sorted->end = sorted->start + size;
+ sorted->end = sorted->start + map_size;
+ // Grow s->entries if necessary.
if (sorted->end > s->cap) {
s->cap = upb_Log2CeilingSize(sorted->end);
s->entries = realloc(s->entries, s->cap * sizeof(*s->entries));
@@ -654,17 +656,9 @@
}
s->size = sorted->end;
- return true;
-}
-
-bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
- const upb_Map* map, _upb_sortedmap* sorted) {
- int map_size = _upb_Map_Size(map);
-
- if (!_upb_mapsorter_resize(s, sorted, map_size)) return false;
// Copy non-empty entries from the table to s->entries.
- const void** dst = &s->entries[sorted->start];
+ upb_tabent const** dst = &s->entries[sorted->start];
const upb_tabent* src = map->table.t.entries;
const upb_tabent* end = src + upb_table_size(&map->table.t);
for (; src < end; src++) {
@@ -680,29 +674,6 @@
compar[key_type]);
return true;
}
-
-static int _upb_mapsorter_cmpext(const void* _a, const void* _b) {
- const upb_Message_Extension* const* a = _a;
- const upb_Message_Extension* const* b = _b;
- uint32_t a_num = (*a)->ext->field.number;
- uint32_t b_num = (*b)->ext->field.number;
- assert(a_num != b_num);
- return a_num < b_num ? -1 : 1;
-}
-
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s,
- const upb_Message_Extension* exts, size_t count,
- _upb_sortedmap* sorted) {
- if (!_upb_mapsorter_resize(s, sorted, count)) return false;
-
- for (size_t i = 0; i < count; i++) {
- s->entries[sorted->start + i] = &exts[i];
- }
-
- qsort(&s->entries[sorted->start], count, sizeof(*s->entries),
- _upb_mapsorter_cmpext);
- return true;
-}
/* This file was generated by upbc (the upb compiler) from the input
* file:
*
@@ -1891,7 +1862,7 @@
n = len + 1;
p = upb_Arena_Malloc(a, n);
if (p) {
- if (len != 0) memcpy(p, s, len);
+ memcpy(p, s, len);
p[len] = 0;
}
return p;
@@ -7227,27 +7198,9 @@
_upb_DefBuilder_FailJmp(ctx);
}
-// Verify a relative identifier string. The loop is branchless for speed.
-static void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx,
- upb_StringView name) {
- bool good = name.size > 0;
-
- for (size_t i = 0; i < name.size; i++) {
- const char c = name.data[i];
- const char d = c | 0x20; // force lowercase
- const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_');
- const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0);
-
- good &= is_alpha | is_numer;
- }
-
- if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false);
-}
-
const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx,
const char* prefix,
upb_StringView name) {
- _upb_DefBuilder_CheckIdentNotFull(ctx, name);
if (prefix) {
// ret = prefix + '.' + name;
size_t n = strlen(prefix);
@@ -7363,7 +7316,7 @@
return true;
}
-static int TryGetHexDigit(const char** src, const char* end) {
+static char TryGetHexDigit(const char** src, const char* end) {
char ch;
if (!TryGetChar(src, end, &ch)) return -1;
if ('0' <= ch && ch <= '9') {
@@ -7380,10 +7333,10 @@
static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx,
const upb_FieldDef* f,
const char** src, const char* end) {
- int hex_digit = TryGetHexDigit(src, end);
+ char hex_digit = TryGetHexDigit(src, end);
if (hex_digit < 0) {
_upb_DefBuilder_Errf(
- ctx, "\\x must be followed by at least one hex digit (field='%s')",
+ ctx, "\\x cannot be followed by non-hex digit in field '%s' default",
upb_FieldDef_FullName(f));
return 0;
}
@@ -7559,7 +7512,7 @@
}
bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext,
- const upb_FieldDef* f) {
+ upb_FieldDef* f) {
return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f),
s->arena);
}
@@ -7791,6 +7744,12 @@
const upb_MiniTableFile* layout, upb_Status* status) {
const upb_StringView name = UPB_DESC(FileDescriptorProto_name)(file_proto);
+ if (name.size == 0) {
+ upb_Status_SetErrorFormat(status,
+ "missing name in google_protobuf_FileDescriptorProto");
+ return NULL;
+ }
+
// Determine whether we already know about this file.
{
upb_value v;
@@ -8182,6 +8141,7 @@
e->file = _upb_DefBuilder_File(ctx);
name = UPB_DESC(EnumDescriptorProto_name)(enum_proto);
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
_upb_DefBuilder_Add(ctx, e->full_name,
@@ -8991,14 +8951,7 @@
}
const upb_StringView name = UPB_DESC(FieldDescriptorProto_name)(field_proto);
-
- f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
- f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto);
- f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto);
- f->is_proto3_optional =
- UPB_DESC(FieldDescriptorProto_proto3_optional)(field_proto);
- f->msgdef = m;
- f->scope.oneof = NULL;
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
f->has_json_name = UPB_DESC(FieldDescriptorProto_has_json_name)(field_proto);
if (f->has_json_name) {
@@ -9010,6 +8963,14 @@
}
if (!f->json_name) _upb_DefBuilder_OomErr(ctx);
+ f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
+ f->label_ = (int)UPB_DESC(FieldDescriptorProto_label)(field_proto);
+ f->number_ = UPB_DESC(FieldDescriptorProto_number)(field_proto);
+ f->is_proto3_optional =
+ UPB_DESC(FieldDescriptorProto_proto3_optional)(field_proto);
+ f->msgdef = m;
+ f->scope.oneof = NULL;
+
const bool has_type = UPB_DESC(FieldDescriptorProto_has_type)(field_proto);
const bool has_type_name =
UPB_DESC(FieldDescriptorProto_has_type_name)(field_proto);
@@ -9139,24 +9100,19 @@
}
_upb_MessageDef_InsertField(ctx, m, f);
-}
-upb_FieldDef* _upb_Extensions_New(
- upb_DefBuilder* ctx, int n,
- const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix,
- upb_MessageDef* m) {
- _upb_DefType_CheckPadding(sizeof(upb_FieldDef));
- upb_FieldDef* defs =
- (upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n);
+ if (!ctx->layout) return;
- for (int i = 0; i < n; i++) {
- upb_FieldDef* f = &defs[i];
-
- _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f);
- f->index_ = i;
+ const upb_MiniTable* mt = upb_MessageDef_MiniTable(m);
+ const upb_MiniTableField* fields = mt->fields;
+ for (int i = 0; i < mt->field_count; i++) {
+ if (fields[i].number == f->number_) {
+ f->layout_index = i;
+ return;
+ }
}
- return defs;
+ UPB_ASSERT(false); // It should be impossible to reach this point.
}
upb_FieldDef* _upb_FieldDefs_New(
@@ -9167,23 +9123,28 @@
upb_FieldDef* defs =
(upb_FieldDef*)_upb_DefBuilder_Alloc(ctx, sizeof(upb_FieldDef) * n);
- uint32_t previous = 0;
- for (int i = 0; i < n; i++) {
- upb_FieldDef* f = &defs[i];
+ // If we are creating extensions then is_sorted will be NULL.
+ // If we are not creating extensions then is_sorted will be non-NULL.
+ if (is_sorted) {
+ uint32_t previous = 0;
+ for (int i = 0; i < n; i++) {
+ upb_FieldDef* f = &defs[i];
- _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f);
- f->index_ = i;
- if (!ctx->layout) {
- // Speculate that the def fields are sorted. We will always sort the
- // MiniTable fields, so if defs are sorted then indices will match.
- //
- // If this is incorrect, we will overwrite later.
- f->layout_index = i;
+ _upb_FieldDef_CreateNotExt(ctx, prefix, protos[i], m, f);
+ f->index_ = i;
+ if (!ctx->layout) f->layout_index = i;
+
+ const uint32_t current = f->number_;
+ if (previous > current) *is_sorted = false;
+ previous = current;
}
+ } else {
+ for (int i = 0; i < n; i++) {
+ upb_FieldDef* f = &defs[i];
- const uint32_t current = f->number_;
- if (previous > current) *is_sorted = false;
- previous = current;
+ _upb_FieldDef_CreateExt(ctx, prefix, protos[i], m, f);
+ f->index_ = i;
+ }
}
return defs;
@@ -9239,9 +9200,6 @@
return (v1 < v2) ? -1 : (v1 > v2);
}
-// _upb_FieldDefs_Sorted() is mostly a pure function of its inputs, but has one
-// critical side effect that we depend on: it sets layout_index appropriately
-// for non-sorted lists of fields.
const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n,
upb_Arena* a) {
// TODO(salo): Replace this arena alloc with a persistent scratch buffer.
@@ -9299,10 +9257,7 @@
"field number %u in extension %s has no extension range in message %s",
(unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m));
}
-}
-void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx,
- const upb_FieldDef* f) {
const upb_MiniTableExtension* ext = _upb_FieldDef_ExtensionMiniTable(f);
if (ctx->layout) {
@@ -9321,8 +9276,8 @@
sub.subenum = _upb_EnumDef_MiniTable(f->sub.enumdef);
}
bool ok2 = upb_MiniTableExtension_Build(desc.data, desc.size, mut_ext,
- upb_MessageDef_MiniTable(f->msgdef),
- sub, ctx->status);
+ upb_MessageDef_MiniTable(m), sub,
+ ctx->status);
if (!ok2) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table");
}
@@ -9379,7 +9334,6 @@
const UPB_DESC(FileOptions) * opts;
const char* name;
const char* package;
- const char* edition;
const upb_FileDef** deps;
const int32_t* public_deps;
@@ -9416,10 +9370,6 @@
return f->package ? f->package : "";
}
-const char* upb_FileDef_Edition(const upb_FileDef* f) {
- return f->edition ? f->edition : "";
-}
-
const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; }
upb_Syntax upb_FileDef_Syntax(const upb_FileDef* f) { return f->syntax; }
@@ -9567,14 +9517,13 @@
}
}
- upb_StringView name = UPB_DESC(FileDescriptorProto_name)(file_proto);
- file->name = strviewdup(ctx, name);
- if (strlen(file->name) != name.size) {
- _upb_DefBuilder_Errf(ctx, "File name contained embedded NULL");
+ if (!UPB_DESC(FileDescriptorProto_has_name)(file_proto)) {
+ _upb_DefBuilder_Errf(ctx, "File has no name");
}
- upb_StringView package = UPB_DESC(FileDescriptorProto_package)(file_proto);
+ file->name = strviewdup(ctx, UPB_DESC(FileDescriptorProto_name)(file_proto));
+ upb_StringView package = UPB_DESC(FileDescriptorProto_package)(file_proto);
if (package.size) {
_upb_DefBuilder_CheckIdentFull(ctx, package);
file->package = strviewdup(ctx, package);
@@ -9582,18 +9531,6 @@
file->package = NULL;
}
- upb_StringView edition = UPB_DESC(FileDescriptorProto_edition)(file_proto);
-
- if (edition.size == 0) {
- file->edition = NULL;
- } else {
- // TODO(b/267770604): How should we validate this?
- file->edition = strviewdup(ctx, edition);
- if (strlen(file->edition) != edition.size) {
- _upb_DefBuilder_Errf(ctx, "Edition name contained embedded NULL");
- }
- }
-
if (UPB_DESC(FileDescriptorProto_has_syntax)(file_proto)) {
upb_StringView syntax = UPB_DESC(FileDescriptorProto_syntax)(file_proto);
@@ -9662,7 +9599,8 @@
// Create extensions.
exts = UPB_DESC(FileDescriptorProto_extension)(file_proto, &n);
file->top_lvl_ext_count = n;
- file->top_lvl_exts = _upb_Extensions_New(ctx, n, exts, file->package, NULL);
+ file->top_lvl_exts =
+ _upb_FieldDefs_New(ctx, n, exts, file->package, NULL, NULL);
// Create messages.
msgs = UPB_DESC(FileDescriptorProto_message_type)(file_proto, &n);
@@ -9686,19 +9624,11 @@
_upb_FieldDef_Resolve(ctx, file->package, f);
}
- for (int i = 0; i < file->top_lvl_msg_count; i++) {
- upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
- _upb_MessageDef_CreateMiniTable(ctx, (upb_MessageDef*)m);
- }
-
- for (int i = 0; i < file->top_lvl_ext_count; i++) {
- upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i);
- _upb_FieldDef_BuildMiniTableExtension(ctx, f);
- }
-
- for (int i = 0; i < file->top_lvl_msg_count; i++) {
- upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
- _upb_MessageDef_LinkMiniTable(ctx, m);
+ if (!ctx->layout) {
+ for (int i = 0; i < file->top_lvl_msg_count; i++) {
+ upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i);
+ _upb_MessageDef_LinkMiniTable(ctx, m);
+ }
}
if (file->ext_count) {
@@ -10211,8 +10141,6 @@
static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m) {
upb_StringView desc;
- // Note: this will assign layout_index for fields, so upb_FieldDef_MiniTable()
- // is safe to call only after this call.
bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc);
if (!ok) _upb_DefBuilder_OomErr(ctx);
@@ -10232,6 +10160,23 @@
_upb_FieldDef_Resolve(ctx, m->full_name, f);
}
+ if (!ctx->layout) {
+ m->layout = _upb_MessageDef_MakeMiniTable(ctx, m);
+ if (!m->layout) _upb_DefBuilder_OomErr(ctx);
+ }
+
+#ifndef NDEBUG
+ for (int i = 0; i < m->field_count; i++) {
+ const upb_FieldDef* f = upb_MessageDef_Field(m, i);
+ const int layout_index = _upb_FieldDef_LayoutIndex(f);
+ UPB_ASSERT(layout_index < m->layout->field_count);
+ const upb_MiniTableField* mt_f = &m->layout->fields[layout_index];
+ UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f));
+ UPB_ASSERT(upb_FieldDef_HasPresence(f) ==
+ upb_MiniTableField_HasPresence(mt_f));
+ }
+#endif
+
m->in_message_set = false;
for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) {
upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i);
@@ -10294,39 +10239,8 @@
if (!ok) _upb_DefBuilder_OomErr(ctx);
}
-void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m) {
- if (ctx->layout == NULL) {
- m->layout = _upb_MessageDef_MakeMiniTable(ctx, m);
- } else {
- UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count);
- m->layout = ctx->layout->msgs[ctx->msg_count++];
- UPB_ASSERT(m->field_count == m->layout->field_count);
-
- // We don't need the result of this call, but it will assign layout_index
- // for all the fields in O(n lg n) time.
- _upb_FieldDefs_Sorted(m->fields, m->field_count, ctx->tmp_arena);
- }
-
- for (int i = 0; i < m->nested_msg_count; i++) {
- upb_MessageDef* nested =
- (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i);
- _upb_MessageDef_CreateMiniTable(ctx, nested);
- }
-}
-
void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m) {
- for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) {
- const upb_FieldDef* ext = upb_MessageDef_NestedExtension(m, i);
- _upb_FieldDef_BuildMiniTableExtension(ctx, ext);
- }
-
- for (int i = 0; i < m->nested_msg_count; i++) {
- _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i));
- }
-
- if (ctx->layout) return;
-
for (int i = 0; i < m->field_count; i++) {
const upb_FieldDef* f = upb_MessageDef_Field(m, i);
const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f);
@@ -10354,17 +10268,9 @@
}
}
-#ifndef NDEBUG
- for (int i = 0; i < m->field_count; i++) {
- const upb_FieldDef* f = upb_MessageDef_Field(m, i);
- const int layout_index = _upb_FieldDef_LayoutIndex(f);
- UPB_ASSERT(layout_index < m->layout->field_count);
- const upb_MiniTableField* mt_f = &m->layout->fields[layout_index];
- UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f));
- UPB_ASSERT(upb_FieldDef_HasPresence(f) ==
- upb_MiniTableField_HasPresence(mt_f));
+ for (int i = 0; i < m->nested_msg_count; i++) {
+ _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i));
}
-#endif
}
static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) {
@@ -10497,6 +10403,7 @@
m->is_sorted = true;
name = UPB_DESC(DescriptorProto_name)(msg_proto);
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name);
_upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG));
@@ -10515,6 +10422,17 @@
ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena);
if (!ok) _upb_DefBuilder_OomErr(ctx);
+ if (ctx->layout) {
+ /* create_fielddef() below depends on this being set. */
+ UPB_ASSERT(ctx->msg_count < ctx->layout->msg_count);
+ m->layout = ctx->layout->msgs[ctx->msg_count++];
+ UPB_ASSERT(n_field == m->layout->field_count);
+ } else {
+ /* Allocate now (to allow cross-linking), populate later. */
+ m->layout = _upb_DefBuilder_Alloc(
+ ctx, sizeof(*m->layout) + sizeof(_upb_FastTable_Entry));
+ }
+
UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto);
m->oneof_count = n_oneof;
@@ -10555,7 +10473,7 @@
const UPB_DESC(FieldDescriptorProto)* const* exts =
UPB_DESC(DescriptorProto_extension)(msg_proto, &n_ext);
m->nested_ext_count = n_ext;
- m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->full_name, m);
+ m->nested_exts = _upb_FieldDefs_New(ctx, n_ext, exts, m->full_name, m, NULL);
const UPB_DESC(DescriptorProto)* const* msgs =
UPB_DESC(DescriptorProto_nested_type)(msg_proto, &n_msg);
@@ -10962,6 +10880,7 @@
s->file = _upb_DefBuilder_File(ctx);
name = UPB_DESC(ServiceDescriptorProto_name)(svc_proto);
+ _upb_DefBuilder_CheckIdentNotFull(ctx, name);
const char* package = _upb_FileDef_RawPackage(s->file);
s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name);
_upb_DefBuilder_Add(ctx, s->full_name,
@@ -13729,15 +13648,6 @@
encode_tag(e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup);
}
-static void encode_ext(upb_encstate* e, const upb_Message_Extension* ext,
- bool is_message_set) {
- if (UPB_UNLIKELY(is_message_set)) {
- encode_msgset_item(e, ext);
- } else {
- encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field);
- }
-}
-
static void encode_message(upb_encstate* e, const upb_Message* msg,
const upb_MiniTable* m, size_t* size) {
size_t pre_len = e->limit - e->ptr;
@@ -13767,17 +13677,12 @@
size_t ext_count;
const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &ext_count);
if (ext_count) {
- if (e->options & kUpb_EncodeOption_Deterministic) {
- _upb_sortedmap sorted;
- _upb_mapsorter_pushexts(&e->sorter, ext, ext_count, &sorted);
- while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) {
- encode_ext(e, ext, m->ext == kUpb_ExtMode_IsMessageSet);
- }
- _upb_mapsorter_popmap(&e->sorter, &sorted);
- } else {
- const upb_Message_Extension* end = ext + ext_count;
- for (; ext != end; ext++) {
- encode_ext(e, ext, m->ext == kUpb_ExtMode_IsMessageSet);
+ const upb_Message_Extension* end = ext + ext_count;
+ for (; ext != end; ext++) {
+ if (UPB_UNLIKELY(m->ext == kUpb_ExtMode_IsMessageSet)) {
+ encode_msgset_item(e, ext);
+ } else {
+ encode_field(e, &ext->data, &ext->ext->sub, &ext->ext->field);
}
}
}
diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h
index 0af88d6..cd703c2 100755
--- a/ruby/ext/google/protobuf_c/ruby-upb.h
+++ b/ruby/ext/google/protobuf_c/ruby-upb.h
@@ -1424,6 +1424,179 @@
#include <stdlib.h>
+#ifndef UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
+#define UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
+
+
+// Must be last.
+
+struct upb_Decoder;
+typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr,
+ upb_Message* msg, intptr_t table,
+ uint64_t hasbits, uint64_t data);
+typedef struct {
+ uint64_t field_data;
+ _upb_FieldParser* field_parser;
+} _upb_FastTable_Entry;
+
+typedef enum {
+ kUpb_ExtMode_NonExtendable = 0, // Non-extendable message.
+ kUpb_ExtMode_Extendable = 1, // Normal extendable message.
+ kUpb_ExtMode_IsMessageSet = 2, // MessageSet message.
+ kUpb_ExtMode_IsMessageSet_ITEM =
+ 3, // MessageSet item (temporary only, see decode.c)
+
+ // During table building we steal a bit to indicate that the message is a map
+ // entry. *Only* used during table building!
+ kUpb_ExtMode_IsMapEntry = 4,
+} upb_ExtMode;
+
+// upb_MiniTable represents the memory layout of a given upb_MessageDef.
+// The members are public so generated code can initialize them,
+// but users MUST NOT directly read or write any of its members.
+struct upb_MiniTable {
+ const upb_MiniTableSub* subs;
+ const upb_MiniTableField* fields;
+
+ // Must be aligned to sizeof(void*). Doesn't include internal members like
+ // unknown fields, extension dict, pointer to msglayout, etc.
+ uint16_t size;
+
+ uint16_t field_count;
+ uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1
+ uint8_t dense_below;
+ uint8_t table_mask;
+ uint8_t required_count; // Required fields have the lowest hasbits.
+
+ // To statically initialize the tables of variable length, we need a flexible
+ // array member, and we need to compile in gnu99 mode (constant initialization
+ // of flexible array members is a GNU extension, not in C99 unfortunately.
+ _upb_FastTable_Entry fasttable[];
+};
+
+// Map entries aren't actually stored for map fields, they are only used during
+// parsing. For parsing, it helps a lot if all map entry messages have the same
+// layout. The layout code in mini_table/decode.c will ensure that all map
+// entries have this layout.
+//
+// Note that users can and do create map entries directly, which will also use
+// this layout.
+//
+// NOTE: sync with mini_table/decode.c.
+typedef struct {
+ // We only need 2 hasbits max, but due to alignment we'll use 8 bytes here,
+ // and the uint64_t helps make this clear.
+ uint64_t hasbits;
+ union {
+ upb_StringView str; // For str/bytes.
+ upb_value val; // For all other types.
+ } k;
+ union {
+ upb_StringView str; // For str/bytes.
+ upb_value val; // For all other types.
+ } v;
+} upb_MapEntryData;
+
+typedef struct {
+ void* internal_data;
+ upb_MapEntryData data;
+} upb_MapEntry;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Computes a bitmask in which the |l->required_count| lowest bits are set,
+// except that we skip the lowest bit (because upb never uses hasbit 0).
+//
+// Sample output:
+// requiredmask(1) => 0b10 (0x2)
+// requiredmask(5) => 0b111110 (0x3e)
+UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) {
+ int n = l->required_count;
+ assert(0 < n && n <= 63);
+ return ((1ULL << n) - 1) << 1;
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif /* UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ */
+
+// Must be last.
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// _upb_mapsorter sorts maps and provides ordered iteration over the entries.
+// Since maps can be recursive (map values can be messages which contain other
+// maps), _upb_mapsorter can contain a stack of maps.
+
+typedef struct {
+ upb_tabent const** entries;
+ int size;
+ int cap;
+} _upb_mapsorter;
+
+typedef struct {
+ int start;
+ int pos;
+ int end;
+} _upb_sortedmap;
+
+UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) {
+ s->entries = NULL;
+ s->size = 0;
+ s->cap = 0;
+}
+
+UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) {
+ if (s->entries) free(s->entries);
+}
+
+UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map,
+ _upb_sortedmap* sorted, upb_MapEntry* ent) {
+ if (sorted->pos == sorted->end) return false;
+ const upb_tabent* tabent = s->entries[sorted->pos++];
+ upb_StringView key = upb_tabstrview(tabent->key);
+ _upb_map_fromkey(key, &ent->data.k, map->key_size);
+ upb_value val = {tabent->val.val};
+ _upb_map_fromvalue(val, &ent->data.v, map->val_size);
+ return true;
+}
+
+UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s,
+ _upb_sortedmap* sorted) {
+ s->size = sorted->start;
+}
+
+bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
+ const upb_Map* map, _upb_sortedmap* sorted);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+
+#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ */
+
+/*
+** Our memory representation for parsing tables and messages themselves.
+** Functions in this file are used by generated code and possibly reflection.
+**
+** The definitions in this file are internal to upb.
+**/
+
+#ifndef UPB_MESSAGE_INTERNAL_H_
+#define UPB_MESSAGE_INTERNAL_H_
+
+#include <stdlib.h>
+#include <string.h>
+
+
#ifndef UPB_MESSAGE_EXTENSION_INTERNAL_H_
#define UPB_MESSAGE_EXTENSION_INTERNAL_H_
@@ -1696,191 +1869,6 @@
#endif /* UPB_MESSAGE_EXTENSION_INTERNAL_H_ */
-#ifndef UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
-#define UPB_MINI_TABLE_MESSAGE_INTERNAL_H_
-
-
-// Must be last.
-
-struct upb_Decoder;
-typedef const char* _upb_FieldParser(struct upb_Decoder* d, const char* ptr,
- upb_Message* msg, intptr_t table,
- uint64_t hasbits, uint64_t data);
-typedef struct {
- uint64_t field_data;
- _upb_FieldParser* field_parser;
-} _upb_FastTable_Entry;
-
-typedef enum {
- kUpb_ExtMode_NonExtendable = 0, // Non-extendable message.
- kUpb_ExtMode_Extendable = 1, // Normal extendable message.
- kUpb_ExtMode_IsMessageSet = 2, // MessageSet message.
- kUpb_ExtMode_IsMessageSet_ITEM =
- 3, // MessageSet item (temporary only, see decode.c)
-
- // During table building we steal a bit to indicate that the message is a map
- // entry. *Only* used during table building!
- kUpb_ExtMode_IsMapEntry = 4,
-} upb_ExtMode;
-
-// upb_MiniTable represents the memory layout of a given upb_MessageDef.
-// The members are public so generated code can initialize them,
-// but users MUST NOT directly read or write any of its members.
-struct upb_MiniTable {
- const upb_MiniTableSub* subs;
- const upb_MiniTableField* fields;
-
- // Must be aligned to sizeof(void*). Doesn't include internal members like
- // unknown fields, extension dict, pointer to msglayout, etc.
- uint16_t size;
-
- uint16_t field_count;
- uint8_t ext; // upb_ExtMode, declared as uint8_t so sizeof(ext) == 1
- uint8_t dense_below;
- uint8_t table_mask;
- uint8_t required_count; // Required fields have the lowest hasbits.
-
- // To statically initialize the tables of variable length, we need a flexible
- // array member, and we need to compile in gnu99 mode (constant initialization
- // of flexible array members is a GNU extension, not in C99 unfortunately.
- _upb_FastTable_Entry fasttable[];
-};
-
-// Map entries aren't actually stored for map fields, they are only used during
-// parsing. For parsing, it helps a lot if all map entry messages have the same
-// layout. The layout code in mini_table/decode.c will ensure that all map
-// entries have this layout.
-//
-// Note that users can and do create map entries directly, which will also use
-// this layout.
-//
-// NOTE: sync with mini_table/decode.c.
-typedef struct {
- // We only need 2 hasbits max, but due to alignment we'll use 8 bytes here,
- // and the uint64_t helps make this clear.
- uint64_t hasbits;
- union {
- upb_StringView str; // For str/bytes.
- upb_value val; // For all other types.
- } k;
- union {
- upb_StringView str; // For str/bytes.
- upb_value val; // For all other types.
- } v;
-} upb_MapEntryData;
-
-typedef struct {
- void* internal_data;
- upb_MapEntryData data;
-} upb_MapEntry;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// Computes a bitmask in which the |l->required_count| lowest bits are set,
-// except that we skip the lowest bit (because upb never uses hasbit 0).
-//
-// Sample output:
-// requiredmask(1) => 0b10 (0x2)
-// requiredmask(5) => 0b111110 (0x3e)
-UPB_INLINE uint64_t upb_MiniTable_requiredmask(const upb_MiniTable* l) {
- int n = l->required_count;
- assert(0 < n && n <= 63);
- return ((1ULL << n) - 1) << 1;
-}
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-
-#endif /* UPB_MINI_TABLE_MESSAGE_INTERNAL_H_ */
-
-// Must be last.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// _upb_mapsorter sorts maps and provides ordered iteration over the entries.
-// Since maps can be recursive (map values can be messages which contain other
-// maps), _upb_mapsorter can contain a stack of maps.
-
-typedef struct {
- void const** entries;
- int size;
- int cap;
-} _upb_mapsorter;
-
-typedef struct {
- int start;
- int pos;
- int end;
-} _upb_sortedmap;
-
-UPB_INLINE void _upb_mapsorter_init(_upb_mapsorter* s) {
- s->entries = NULL;
- s->size = 0;
- s->cap = 0;
-}
-
-UPB_INLINE void _upb_mapsorter_destroy(_upb_mapsorter* s) {
- if (s->entries) free(s->entries);
-}
-
-UPB_INLINE bool _upb_sortedmap_next(_upb_mapsorter* s, const upb_Map* map,
- _upb_sortedmap* sorted, upb_MapEntry* ent) {
- if (sorted->pos == sorted->end) return false;
- const upb_tabent* tabent = (const upb_tabent*)s->entries[sorted->pos++];
- upb_StringView key = upb_tabstrview(tabent->key);
- _upb_map_fromkey(key, &ent->data.k, map->key_size);
- upb_value val = {tabent->val.val};
- _upb_map_fromvalue(val, &ent->data.v, map->val_size);
- return true;
-}
-
-UPB_INLINE bool _upb_sortedmap_nextext(_upb_mapsorter* s,
- _upb_sortedmap* sorted,
- const upb_Message_Extension** ext) {
- if (sorted->pos == sorted->end) return false;
- *ext = (const upb_Message_Extension*)s->entries[sorted->pos++];
- return true;
-}
-
-UPB_INLINE void _upb_mapsorter_popmap(_upb_mapsorter* s,
- _upb_sortedmap* sorted) {
- s->size = sorted->start;
-}
-
-bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type,
- const upb_Map* map, _upb_sortedmap* sorted);
-
-bool _upb_mapsorter_pushexts(_upb_mapsorter* s,
- const upb_Message_Extension* exts, size_t count,
- _upb_sortedmap* sorted);
-
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
-
-
-#endif /* UPB_COLLECTIONS_MAP_SORTER_INTERNAL_H_ */
-
-/*
-** Our memory representation for parsing tables and messages themselves.
-** Functions in this file are used by generated code and possibly reflection.
-**
-** The definitions in this file are internal to upb.
-**/
-
-#ifndef UPB_MESSAGE_INTERNAL_H_
-#define UPB_MESSAGE_INTERNAL_H_
-
-#include <stdlib.h>
-#include <string.h>
-
-
#ifndef UPB_MINI_TABLE_EXTENSION_REGISTRY_H_
#define UPB_MINI_TABLE_EXTENSION_REGISTRY_H_
@@ -8813,7 +8801,6 @@
const char* upb_FileDef_Name(const upb_FileDef* f);
const UPB_DESC(FileOptions) * upb_FileDef_Options(const upb_FileDef* f);
const char* upb_FileDef_Package(const upb_FileDef* f);
-const char* upb_FileDef_Edition(const upb_FileDef* f);
const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f);
const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i);
@@ -9926,7 +9913,7 @@
upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s);
bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext,
- const upb_FieldDef* f);
+ upb_FieldDef* f);
bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v,
upb_Status* status);
bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size,
@@ -10052,6 +10039,23 @@
void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name,
bool full);
+// Verify a relative identifier string. The loop is branchless for speed.
+UPB_INLINE void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx,
+ upb_StringView name) {
+ bool good = name.size > 0;
+
+ for (size_t i = 0; i < name.size; i++) {
+ const char c = name.data[i];
+ const char d = c | 0x20; // force lowercase
+ const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_');
+ const bool is_numer = ('0' <= c) & (c <= '9') & (i != 0);
+
+ good &= is_alpha | is_numer;
+ }
+
+ if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false);
+}
+
// Verify a full identifier string. This is slightly more complicated than
// verifying a relative identifier string because we must track '.' chars.
UPB_INLINE void _upb_DefBuilder_CheckIdentFull(upb_DefBuilder* ctx,
@@ -10155,14 +10159,6 @@
uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f);
void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix,
upb_FieldDef* f);
-void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx,
- const upb_FieldDef* f);
-
-// Allocate and initialize an array of |n| extensions (field defs).
-upb_FieldDef* _upb_Extensions_New(
- upb_DefBuilder* ctx, int n,
- const UPB_DESC(FieldDescriptorProto) * const* protos, const char* prefix,
- upb_MessageDef* m);
// Allocate and initialize an array of |n| field defs.
upb_FieldDef* _upb_FieldDefs_New(
@@ -10227,7 +10223,6 @@
void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m,
const upb_FieldDef* f);
bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n);
-void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m);
void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx,
const upb_MessageDef* m);
void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m);
diff --git a/ruby/pom.xml b/ruby/pom.xml
index 503d3af..cd2d68e 100644
--- a/ruby/pom.xml
+++ b/ruby/pom.xml
@@ -76,7 +76,11 @@
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
+<<<<<<< HEAD
+ <version>3.21.12</version>
+=======
<version>3.22.1</version>
+>>>>>>> upstream/22.x
</dependency>
<dependency>
<groupId>org.jruby</groupId>
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
index 92a31d6..dc76e2d 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -669,6 +669,7 @@
* @param options [Hash] options for the decoder
* preserve_proto_fieldnames: set true to use original fieldnames (default is to camelCase)
* emit_defaults: set true to emit 0/false values (default is to omit them)
+ * format_enums_as_integers: set true to emit enum values as integer (default is string)
*/
@JRubyMethod(name = "encode_json", required = 1, optional = 1, meta = true)
public static IRubyObject encodeJson(
@@ -690,6 +691,8 @@
IRubyObject emitDefaults = options.fastARef(runtime.newSymbol("emit_defaults"));
IRubyObject preserveNames = options.fastARef(runtime.newSymbol("preserve_proto_fieldnames"));
+ IRubyObject printingEnumsAsInts =
+ options.fastARef(runtime.newSymbol("format_enums_as_integers"));
if (emitDefaults != null && emitDefaults.isTrue()) {
printer = printer.includingDefaultValueFields();
@@ -698,6 +701,10 @@
if (preserveNames != null && preserveNames.isTrue()) {
printer = printer.preservingProtoFieldNames();
}
+
+ if (printingEnumsAsInts != null && printingEnumsAsInts.isTrue()) {
+ printer = printer.printingEnumsAsInts();
+ }
}
printer =
printer.usingTypeRegistry(
diff --git a/ruby/tests/encode_decode_test.rb b/ruby/tests/encode_decode_test.rb
index df2cd36..710e754 100755
--- a/ruby/tests/encode_decode_test.rb
+++ b/ruby/tests/encode_decode_test.rb
@@ -84,6 +84,34 @@
)
assert_match 'optional_int32', json
+
+
+ # Test for enums printing as ints.
+ msg = A::B::C::TestMessage.new({ optional_enum: 1 })
+ json = A::B::C::TestMessage.encode_json(
+ msg,
+ { :format_enums_as_integers => true }
+ )
+
+ assert_match '"optionalEnum":1', json
+
+ # Test for default enum being printed as int.
+ msg = A::B::C::TestMessage.new({ optional_enum: 0 })
+ json = A::B::C::TestMessage.encode_json(
+ msg,
+ { :format_enums_as_integers => true, :emit_defaults => true }
+ )
+
+ assert_match '"optionalEnum":0', json
+
+ # Test for repeated enums printing as ints.
+ msg = A::B::C::TestMessage.new({ repeated_enum: [0,1,2,3] })
+ json = A::B::C::TestMessage.encode_json(
+ msg,
+ { :format_enums_as_integers => true }
+ )
+
+ assert_match '"repeatedEnum":[0,1,2,3]', json
end
def test_encode_wrong_msg
diff --git a/rust/BUILD b/rust/BUILD
new file mode 100644
index 0000000..ac72f07
--- /dev/null
+++ b/rust/BUILD
@@ -0,0 +1,20 @@
+# Protobuf Rust runtime packages.
+
+load("@rules_rust//rust:defs.bzl", "rust_library")
+load("@rules_proto//proto:defs.bzl", "proto_lang_toolchain")
+
+package(default_visibility = ["//src/google/protobuf:__subpackages__"])
+
+rust_library(
+ name = "protobuf",
+ srcs = ["lib.rs"],
+)
+
+# TODO(b/270125787): Move to the right location once rust_proto_library is no longer experimental.
+proto_lang_toolchain(
+ name = "proto_lang_toolchain",
+ command_line = "--rust_out=experimental-codegen=enabled:$(OUT)",
+ progress_message = "Generating Rust proto_library %{label}",
+ runtime = ":protobuf",
+ visibility = ["//visibility:public"],
+)
diff --git a/rust/BUILD.bazel b/rust/BUILD.bazel
deleted file mode 100644
index 5efdab5..0000000
--- a/rust/BUILD.bazel
+++ /dev/null
@@ -1,10 +0,0 @@
-# Protobuf Rust runtime packages.
-
-load("@rules_rust//rust:defs.bzl", "rust_library")
-
-package(default_visibility = ["//src/google/protobuf:__subpackages__"])
-
-rust_library(
- name = "protobuf",
- srcs = ["lib.rs"],
-)
diff --git a/rust/defs.bzl b/rust/defs.bzl
new file mode 100644
index 0000000..8e7d47e
--- /dev/null
+++ b/rust/defs.bzl
@@ -0,0 +1,243 @@
+"""This file implements an experimental, do-not-use-kind of rust_proto_library.
+
+Disclaimer: This project is experimental, under heavy development, and should not
+be used yet."""
+
+# buildifier: disable=bzl-visibility
+load("@rules_rust//rust/private:providers.bzl", "CrateInfo", "DepInfo", "DepVariantInfo")
+
+# buildifier: disable=bzl-visibility
+load("@rules_rust//rust/private:rustc.bzl", "rustc_compile_action")
+load("@rules_rust//rust:defs.bzl", "rust_common")
+
+proto_common = proto_common_do_not_use
+
+RustProtoInfo = provider(
+ doc = "Rust protobuf provider info",
+ fields = {
+ "dep_variant_info": "DepVariantInfo for the compiled Rust gencode (also covers its " +
+ "transitive dependencies)",
+ },
+)
+
+def _generate_rust_gencode(
+ ctx,
+ proto_info,
+ proto_lang_toolchain):
+ """Generates Rust gencode
+
+ This function uses proto_common APIs and a ProtoLangToolchain to register an action
+ that invokes protoc with the right flags.
+ Args:
+ ctx (RuleContext): current rule context
+ proto_info (ProtoInfo): ProtoInfo of the proto_library target for which we are generating
+ gencode
+ proto_lang_toolchain (ProtoLangToolchainInfo): proto lang toolchain for Rust
+ Returns:
+ rs_outputs ([File]): generated Rust source files
+ """
+ actions = ctx.actions
+ rs_outputs = proto_common.declare_generated_files(
+ actions = actions,
+ proto_info = proto_info,
+ extension = ".pb.rs",
+ )
+
+ proto_common.compile(
+ actions = ctx.actions,
+ proto_info = proto_info,
+ generated_files = rs_outputs,
+ proto_lang_toolchain_info = proto_lang_toolchain,
+ plugin_output = ctx.bin_dir.path,
+ )
+ return rs_outputs
+
+def _get_crate_info(providers):
+ for provider in providers:
+ if hasattr(provider, "name"):
+ return provider
+ fail("Couldn't find a CrateInfo in the list of providers")
+
+def _get_dep_info(providers):
+ for provider in providers:
+ if hasattr(provider, "direct_crates"):
+ return provider
+ fail("Couldn't find a DepInfo in the list of providers")
+
+def _get_cc_info(providers):
+ for provider in providers:
+ if hasattr(provider, "linking_context"):
+ return provider
+ fail("Couldn't find a CcInfo in the list of providers")
+
+def _compile_rust(ctx, attr, src, extra_srcs, deps):
+ """Compiles a Rust source file.
+
+ Eventually this function could be upstreamed into rules_rust and be made present in rust_common.
+
+ Args:
+ ctx (RuleContext): The rule context.
+ attr (Attrs): The current rule's attributes (`ctx.attr` for rules, `ctx.rule.attr` for aspects)
+ src (File): The crate root source file to be compiled.
+ extra_srcs ([File]): Additional source files to include in the crate.
+ deps (List[DepVariantInfo]): A list of dependencies needed.
+
+ Returns:
+ A DepVariantInfo provider.
+ """
+ toolchain = ctx.toolchains["@rules_rust//rust:toolchain"]
+ output_hash = repr(hash(src.path))
+
+ # TODO(b/270124215): Use the import! macro once available
+ crate_name = ctx.label.name.replace("-", "_")
+
+ lib_name = "{prefix}{name}-{lib_hash}{extension}".format(
+ prefix = "lib",
+ name = crate_name,
+ lib_hash = output_hash,
+ extension = ".rlib",
+ )
+
+ rmeta_name = "{prefix}{name}-{lib_hash}{extension}".format(
+ prefix = "lib",
+ name = crate_name,
+ lib_hash = output_hash,
+ extension = ".rmeta",
+ )
+
+ lib = ctx.actions.declare_file(lib_name)
+ rmeta = ctx.actions.declare_file(rmeta_name)
+
+ providers = rustc_compile_action(
+ ctx = ctx,
+ attr = attr,
+ toolchain = toolchain,
+ crate_info = rust_common.create_crate_info(
+ name = crate_name,
+ type = "rlib",
+ root = src,
+ srcs = depset([src] + extra_srcs),
+ deps = depset(deps),
+ proc_macro_deps = depset([]),
+ aliases = {},
+ output = lib,
+ metadata = rmeta,
+ edition = "2021",
+ is_test = False,
+ rustc_env = {},
+ compile_data = depset([]),
+ compile_data_targets = depset([]),
+ owner = ctx.label,
+ ),
+ output_hash = output_hash,
+ )
+
+ return DepVariantInfo(
+ crate_info = _get_crate_info(providers),
+ dep_info = _get_dep_info(providers),
+ cc_info = _get_cc_info(providers),
+ build_info = None,
+ )
+
+def _rust_proto_aspect_impl(target, ctx):
+ if ProtoInfo not in target:
+ return None
+
+ proto_lang_toolchain = ctx.attr._proto_lang_toolchain[proto_common.ProtoLangToolchainInfo]
+
+ gencode = _generate_rust_gencode(ctx, target[ProtoInfo], proto_lang_toolchain)
+
+ runtime = proto_lang_toolchain.runtime
+ dep_variant_info_for_runtime = DepVariantInfo(
+ crate_info = runtime[CrateInfo] if CrateInfo in runtime else None,
+ dep_info = runtime[DepInfo] if DepInfo in runtime else None,
+ cc_info = runtime[CcInfo] if CcInfo in runtime else None,
+ build_info = None,
+ )
+
+ proto_dep = getattr(ctx.rule.attr, "deps", [])
+ dep_variant_info = _compile_rust(
+ ctx = ctx,
+ attr = ctx.rule.attr,
+ src = gencode[0],
+ extra_srcs = gencode[1:],
+ deps = [dep_variant_info_for_runtime] + ([proto_dep[0][RustProtoInfo].dep_variant_info] if proto_dep else []),
+ )
+ return [RustProtoInfo(
+ dep_variant_info = dep_variant_info,
+ )]
+
+rust_proto_library_aspect = aspect(
+ implementation = _rust_proto_aspect_impl,
+ attr_aspects = ["deps"],
+ attrs = {
+ "_cc_toolchain": attr.label(
+ doc = (
+ "In order to use find_cc_toolchain, your rule has to depend " +
+ "on C++ toolchain. See `@rules_cc//cc:find_cc_toolchain.bzl` " +
+ "docs for details."
+ ),
+ default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
+ ),
+ "_collect_cc_coverage": attr.label(
+ default = Label("@rules_rust//util:collect_coverage"),
+ executable = True,
+ cfg = "exec",
+ ),
+ "_error_format": attr.label(
+ default = Label("@rules_rust//:error_format"),
+ ),
+ "_extra_exec_rustc_flag": attr.label(
+ default = Label("@rules_rust//:extra_exec_rustc_flag"),
+ ),
+ "_extra_exec_rustc_flags": attr.label(
+ default = Label("@rules_rust//:extra_exec_rustc_flags"),
+ ),
+ "_extra_rustc_flag": attr.label(
+ default = Label("@rules_rust//:extra_rustc_flag"),
+ ),
+ "_extra_rustc_flags": attr.label(
+ default = Label("@rules_rust//:extra_rustc_flags"),
+ ),
+ "_process_wrapper": attr.label(
+ doc = "A process wrapper for running rustc on all platforms.",
+ default = Label("@rules_rust//util/process_wrapper"),
+ executable = True,
+ allow_single_file = True,
+ cfg = "exec",
+ ),
+ "_proto_lang_toolchain": attr.label(
+ default = Label("//rust:proto_lang_toolchain"),
+ ),
+ },
+ fragments = ["cpp"],
+ host_fragments = ["cpp"],
+ toolchains = [
+ str(Label("@rules_rust//rust:toolchain")),
+ "@bazel_tools//tools/cpp:toolchain_type",
+ ],
+ incompatible_use_toolchain_transition = True,
+)
+
+def _rust_proto_library_impl(ctx):
+ deps = ctx.attr.deps
+ if not deps:
+ fail("Exactly 1 dependency in `deps` attribute expected, none were provided.")
+ if len(deps) > 1:
+ fail("Exactly 1 dependency in `deps` attribute expected, too many were provided.")
+
+ dep = deps[0]
+ rust_proto_info = dep[RustProtoInfo]
+ dep_variant_info = rust_proto_info.dep_variant_info
+ return [dep_variant_info.crate_info, dep_variant_info.dep_info, dep_variant_info.cc_info]
+
+rust_proto_library = rule(
+ implementation = _rust_proto_library_impl,
+ attrs = {
+ "deps": attr.label_list(
+ mandatory = True,
+ providers = [ProtoInfo],
+ aspects = [rust_proto_library_aspect],
+ ),
+ },
+)
diff --git a/rust/lib.rs b/rust/lib.rs
index 8974efa..d860245 100644
--- a/rust/lib.rs
+++ b/rust/lib.rs
@@ -31,3 +31,6 @@
//! Rust Protobuf Runtime
// Not yet implemented.
+
+// TODO(b/270138878): Remove once we have real logic in the runtime.
+pub fn do_nothing() {}
diff --git a/rust/test/BUILD b/rust/test/BUILD
new file mode 100644
index 0000000..6e61e15
--- /dev/null
+++ b/rust/test/BUILD
@@ -0,0 +1,49 @@
+load("//rust:defs.bzl", "rust_proto_library")
+load("@rules_rust//rust:defs.bzl", "rust_test")
+
+rust_proto_library(
+ name = "hello_world_rs_proto",
+ testonly = True,
+ deps = ["//third_party/protobuf:unittest_proto"],
+)
+
+rust_test(
+ name = "hello_world_test",
+ srcs = ["hello_world_test.rs"],
+ # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+ tags = ["not_build:arm"],
+ deps = [":hello_world_rs_proto"],
+)
+
+proto_library(
+ name = "parent_proto",
+ srcs = ["parent.proto"],
+)
+
+proto_library(
+ name = "child_proto",
+ srcs = ["child.proto"],
+ exports = [":parent_proto"],
+ deps = [":parent_proto"],
+)
+
+rust_proto_library(
+ name = "parent_rs_proto",
+ deps = [":parent_proto"],
+)
+
+rust_proto_library(
+ name = "child_rs_proto",
+ deps = [":child_proto"],
+)
+
+rust_test(
+ name = "child_parent_test",
+ srcs = ["child_parent_test.rs"],
+ # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+ tags = ["not_build:arm"],
+ deps = [
+ ":child_rs_proto",
+ ":parent_rs_proto",
+ ],
+)
diff --git a/rust/test/child.proto b/rust/test/child.proto
new file mode 100644
index 0000000..cb43465
--- /dev/null
+++ b/rust/test/child.proto
@@ -0,0 +1,40 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+syntax = "proto2";
+
+package third_party_protobuf_rust_test;
+
+// copybara:strip_begin(Replace import path for Bazel)
+import public "google/protobuf/rust/test/parent.proto";
+
+// copybara:strip_end_and_replace import public "rust/test/parent.proto";
+
+message Child {}
diff --git a/rust/test/child_parent_test.rs b/rust/test/child_parent_test.rs
new file mode 100644
index 0000000..0bfb332
--- /dev/null
+++ b/rust/test/child_parent_test.rs
@@ -0,0 +1,37 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+fn main() {
+ let _child = child_proto::Child {};
+ let _parent = parent_proto::Parent {};
+ // Parent from child_proto crate should be the same type as Parent from
+ // parent_proto crate.
+ let _parent_from_child: child_proto::Parent = parent_proto::Parent {};
+}
diff --git a/rust/test/hello_world_test.rs b/rust/test/hello_world_test.rs
new file mode 100644
index 0000000..24cad65
--- /dev/null
+++ b/rust/test/hello_world_test.rs
@@ -0,0 +1,35 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+fn main() {
+ // This is currently just a smoke test checking that we can generate gencode, compile it, and
+ // link the test binary.
+ let _test_all_types: unittest_proto::TestAllTypes;
+}
diff --git a/rust/test/parent.proto b/rust/test/parent.proto
new file mode 100644
index 0000000..fa3b204
--- /dev/null
+++ b/rust/test/parent.proto
@@ -0,0 +1,35 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+syntax = "proto2";
+
+package third_party_protobuf_rust_test;
+
+message Parent {}
diff --git a/rust/test/rust_proto_library_unit_test/BUILD b/rust/test/rust_proto_library_unit_test/BUILD
new file mode 100644
index 0000000..de7da61
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/BUILD
@@ -0,0 +1,3 @@
+load(":rust_proto_library_unit_test.bzl", "rust_proto_library_unit_test")
+
+rust_proto_library_unit_test(name = "rust_proto_library_unit_test")
diff --git a/rust/test/rust_proto_library_unit_test/child.proto b/rust/test/rust_proto_library_unit_test/child.proto
new file mode 100644
index 0000000..acb7dc4
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/child.proto
@@ -0,0 +1,33 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+syntax = "proto2";
+
+package third_party_protobuf_rust_test_rust_proto_library_unit_test;
diff --git a/rust/test/rust_proto_library_unit_test/defs.bzl b/rust/test/rust_proto_library_unit_test/defs.bzl
new file mode 100644
index 0000000..81741aa
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/defs.bzl
@@ -0,0 +1,19 @@
+"""Support for rust_proto_library_aspect unit-tests."""
+
+load("//rust:defs.bzl", "RustProtoInfo", "rust_proto_library_aspect")
+
+ActionsInfo = provider(
+ doc = ("A provider that exposes what actions were registered by rust_proto_library_aspect " +
+ "on proto_libraries."),
+ fields = {"actions": "List[Action]: actions registered on proto_libraries."},
+)
+
+def _attach_aspect_impl(ctx):
+ return [ctx.attr.dep[RustProtoInfo], ActionsInfo(actions = ctx.attr.dep.actions)]
+
+attach_aspect = rule(
+ implementation = _attach_aspect_impl,
+ attrs = {
+ "dep": attr.label(aspects = [rust_proto_library_aspect]),
+ },
+)
diff --git a/rust/test/rust_proto_library_unit_test/parent.proto b/rust/test/rust_proto_library_unit_test/parent.proto
new file mode 100644
index 0000000..acb7dc4
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/parent.proto
@@ -0,0 +1,33 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+syntax = "proto2";
+
+package third_party_protobuf_rust_test_rust_proto_library_unit_test;
diff --git a/rust/test/rust_proto_library_unit_test/rust_proto_library_unit_test.bzl b/rust/test/rust_proto_library_unit_test/rust_proto_library_unit_test.bzl
new file mode 100644
index 0000000..6749cf9
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/rust_proto_library_unit_test.bzl
@@ -0,0 +1,95 @@
+"""This module contains unit tests for rust_proto_library and its aspect."""
+
+load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
+load(":defs.bzl", "ActionsInfo", "attach_aspect")
+
+def _find_action_with_mnemonic(actions, mnemonic):
+ action = [a for a in actions if a.mnemonic == mnemonic]
+ if not action:
+ fail("Couldn't find action with mnemonic {} among {}".format(mnemonic, actions))
+ return action[0]
+
+def _find_rust_lib_input(inputs, target_name):
+ inputs = inputs.to_list()
+ input = [i for i in inputs if i.basename.startswith("lib" + target_name) and
+ (i.basename.endswith(".rlib") or i.basename.endswith(".rmeta"))]
+ if not input:
+ fail("Couldn't find lib{}-<hash>.rlib or lib{}-<hash>.rmeta among {}".format(
+ target_name,
+ target_name,
+ [i.basename for i in inputs],
+ ))
+ return input[0]
+
+####################################################################################################
+
+def _rust_compilation_action_has_runtime_as_input_test_impl(ctx):
+ env = analysistest.begin(ctx)
+ target_under_test = analysistest.target_under_test(env)
+ actions = target_under_test[ActionsInfo].actions
+ rustc_action = _find_action_with_mnemonic(actions, "Rustc")
+ _find_rust_lib_input(rustc_action.inputs, "protobuf")
+ asserts.true(env, rustc_action.outputs.to_list()[0].path.endswith(".rlib"))
+
+ return analysistest.end(env)
+
+rust_compilation_action_has_runtime_as_input_test = analysistest.make(
+ _rust_compilation_action_has_runtime_as_input_test_impl,
+)
+
+def _test_rust_compilation_action_has_runtime_as_input():
+ native.proto_library(name = "some_proto", srcs = ["some_proto.proto"])
+ attach_aspect(name = "some_proto_with_aspect", dep = ":some_proto")
+
+ rust_compilation_action_has_runtime_as_input_test(
+ name = "rust_compilation_action_has_runtime_as_input_test",
+ target_under_test = ":some_proto_with_aspect",
+ # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+ tags = ["not_build:arm"],
+ )
+
+####################################################################################################
+
+def _rust_compilation_action_has_deps_as_inputs_test_impl(ctx):
+ env = analysistest.begin(ctx)
+ target_under_test = analysistest.target_under_test(env)
+ actions = target_under_test[ActionsInfo].actions
+ rustc_action = _find_action_with_mnemonic(actions, "Rustc")
+ _find_rust_lib_input(rustc_action.inputs, "parent")
+
+ return analysistest.end(env)
+
+rust_compilation_action_has_deps_as_input_test = analysistest.make(
+ _rust_compilation_action_has_deps_as_inputs_test_impl,
+)
+
+def _test_rust_compilation_action_has_deps_as_input():
+ native.proto_library(name = "parent_proto", srcs = ["parent.proto"])
+ native.proto_library(name = "child_proto", srcs = ["child.proto"], deps = [":parent_proto"])
+
+ attach_aspect(name = "child_proto_with_aspect", dep = ":child_proto")
+
+ rust_compilation_action_has_deps_as_input_test(
+ name = "rust_compilation_action_has_deps_as_input_test",
+ target_under_test = ":child_proto_with_aspect",
+ # TODO(b/270274576): Enable testing on arm once we have a Rust Arm toolchain.
+ tags = ["not_build:arm"],
+ )
+
+####################################################################################################
+
+def rust_proto_library_unit_test(name):
+ """Sets up rust_proto_library_unit_test test suite.
+
+ Args:
+ name: name of the test suite"""
+ _test_rust_compilation_action_has_runtime_as_input()
+ _test_rust_compilation_action_has_deps_as_input()
+
+ native.test_suite(
+ name = name,
+ tests = [
+ ":rust_compilation_action_has_runtime_as_input_test",
+ ":rust_compilation_action_has_deps_as_input_test",
+ ],
+ )
diff --git a/rust/test/rust_proto_library_unit_test/some_proto.proto b/rust/test/rust_proto_library_unit_test/some_proto.proto
new file mode 100644
index 0000000..1cc4a52
--- /dev/null
+++ b/rust/test/rust_proto_library_unit_test/some_proto.proto
@@ -0,0 +1,39 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+// This file exists because of the design of the Starlark unit testing
+// framework. We call these tests unittests, but Blaze still sees them as full
+// builds. And while Blaze doesn't build the test-setup targets unless it really
+// needs to, it checks that all input files are present. Therefore, we need
+// these "empty" files to be present.
+
+syntax = "proto2";
+
+package third_party_protobuf_rust_test_rust_proto_library_unit_test;
diff --git a/src/file_lists.cmake b/src/file_lists.cmake
index d754247..3b49e91 100644
--- a/src/file_lists.cmake
+++ b/src/file_lists.cmake
@@ -68,6 +68,7 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/message.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/message_lite.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/parse_context.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_mode.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_ops.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_ptr_field.cc
@@ -165,6 +166,7 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/port_undef.inc
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection.h
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_internal.h
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_mode.h
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_ops.h
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_field.h
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_ptr_field.h
@@ -270,11 +272,13 @@
# @//pkg:protoc
set(libprotoc_srcs
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/allowlists/allowlists.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/enum.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/extension.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/field.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
@@ -361,12 +365,15 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/rust/generator.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.cc
)
# @//pkg:protoc
set(libprotoc_hdrs
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/allowlists/allowlist.h
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/allowlists/allowlists.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/enum.h
@@ -461,6 +468,7 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/python/pyi_generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/retention.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/ruby/ruby_generator.h
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/rust/generator.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/scc.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/subprocess.h
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/zip_writer.h
@@ -598,6 +606,7 @@
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_arena_lite_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_arena_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/proto3_lite_unittest.cc
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_mode_test.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/reflection_ops_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_field_reflection_unittest.cc
${protobuf_SOURCE_DIR}/src/google/protobuf/repeated_field_unittest.cc
@@ -613,6 +622,7 @@
set(protobuf_test_protos_files
${protobuf_SOURCE_DIR}/src/google/protobuf/any_test.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/map_proto2_unittest.proto
+ ${protobuf_SOURCE_DIR}/src/google/protobuf/map_proto3_unittest.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/map_unittest.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest.proto
${protobuf_SOURCE_DIR}/src/google/protobuf/unittest_arena.proto
diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel
index d986479..34ee53b 100644
--- a/src/google/protobuf/BUILD.bazel
+++ b/src/google/protobuf/BUILD.bazel
@@ -392,6 +392,7 @@
"generated_message_tctable_gen.cc",
"map_field.cc",
"message.cc",
+ "reflection_mode.cc",
"reflection_ops.cc",
"service.cc",
"text_format.cc",
@@ -415,6 +416,7 @@
"metadata.h",
"reflection.h",
"reflection_internal.h",
+ "reflection_mode.h",
"reflection_ops.h",
"service.h",
"text_format.h",
@@ -548,6 +550,7 @@
srcs = [
"any_test.proto",
"map_proto2_unittest.proto",
+ "map_proto3_unittest.proto",
"map_unittest.proto",
"unittest.proto",
"unittest_arena.proto",
@@ -604,6 +607,7 @@
name = "generic_test_protos",
srcs = [
"map_proto2_unittest.proto",
+ "map_proto3_unittest.proto",
"map_unittest.proto",
"unittest.proto",
"unittest_arena.proto",
@@ -1257,6 +1261,7 @@
"//src/google/protobuf/io",
"//src/google/protobuf/stubs",
"//src/google/protobuf/testing",
+ "@com_google_absl//absl/functional:bind_front",
"@com_google_absl//absl/synchronization",
"@com_google_googletest//:gtest",
"@com_google_googletest//:gtest_main",
@@ -1313,6 +1318,16 @@
],
)
+cc_test(
+ name = "reflection_mode_test",
+ srcs = ["reflection_mode_test.cc"],
+ deps = [
+ ":protobuf_nowkt",
+ "@com_google_googletest//:gtest",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
+
################################################################################
# Helper targets for Kotlin tests
################################################################################
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index 8a74236..0917057 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -96,6 +96,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index ed63bbb..649d48d 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -436,7 +436,7 @@
// .google.protobuf.Syntax syntax = 7;
case 7:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 56)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
_internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
} else {
@@ -865,7 +865,7 @@
// .google.protobuf.Syntax syntax = 7;
case 7:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 56)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
_internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
} else {
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index ac59bce..d334922 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -108,6 +108,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -379,6 +386,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -636,6 +650,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 071360f..5d25d65 100644
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -197,18 +197,21 @@
PROTOBUF_NOINLINE
void* SerialArena::AllocateFromStringBlockFallback() {
+ ABSL_DCHECK_EQ(string_block_unused_.load(std::memory_order_relaxed), 0U);
if (string_block_) {
- ABSL_DCHECK_EQ(string_block_unused_.load(std::memory_order_relaxed), 0U);
- space_used_.store(space_used_.load(std::memory_order_relaxed) +
- string_block_->effective_size(),
- std::memory_order_relaxed);
+ AddSpaceUsed(string_block_->effective_size());
}
- string_block_ = StringBlock::New(string_block_);
- space_allocated_.store(space_allocated_.load(std::memory_order_relaxed) +
- string_block_->allocated_size(),
- std::memory_order_relaxed);
-
+ void* ptr;
+ size_t size = StringBlock::NextSize(string_block_);
+ if (MaybeAllocateAligned(size, &ptr)) {
+ // Correct space_used_ to avoid double counting
+ AddSpaceUsed(-size);
+ string_block_ = StringBlock::Emplace(ptr, size, string_block_);
+ } else {
+ string_block_ = StringBlock::New(string_block_);
+ AddSpaceAllocated(string_block_->allocated_size());
+ }
size_t unused = string_block_->effective_size() - sizeof(std::string);
string_block_unused_.store(unused, std::memory_order_relaxed);
return string_block_->AtOffset(unused);
@@ -240,8 +243,7 @@
// Record how much used in this block.
used = static_cast<size_t>(ptr() - old_head->Pointer(kBlockHeaderSize));
wasted = old_head->size - used;
- space_used_.store(space_used_.load(std::memory_order_relaxed) + used,
- std::memory_order_relaxed);
+ AddSpaceUsed(used);
}
// TODO(sbenza): Evaluate if pushing unused space into the cached blocks is a
@@ -253,9 +255,7 @@
// We don't want to emit an expensive RMW instruction that requires
// exclusive access to a cacheline. Hence we write it in terms of a
// regular add.
- space_allocated_.store(
- space_allocated_.load(std::memory_order_relaxed) + mem.n,
- std::memory_order_relaxed);
+ AddSpaceAllocated(mem.n);
ThreadSafeArenaStats::RecordAllocateStats(parent_.arena_stats_.MutableStats(),
/*used=*/used,
/*allocated=*/mem.n, wasted);
@@ -278,19 +278,21 @@
// usage of the *current* block.
// TODO(mkruskal) Consider eliminating this race in exchange for a possible
// performance hit on ARM (see cl/455186837).
- uint64_t current_space_used =
- string_block_ ? string_block_->effective_size() -
- string_block_unused_.load(std::memory_order_relaxed)
- : 0;
+
+ uint64_t space_used = 0;
+ if (string_block_) {
+ size_t unused = string_block_unused_.load(std::memory_order_relaxed);
+ space_used += string_block_->effective_size() - unused;
+ }
const ArenaBlock* h = head_.load(std::memory_order_acquire);
- if (h->IsSentry()) return current_space_used;
+ if (h->IsSentry()) return space_used;
const uint64_t current_block_size = h->size;
- current_space_used += std::min(
+ space_used += std::min(
static_cast<uint64_t>(
ptr() - const_cast<ArenaBlock*>(h)->Pointer(kBlockHeaderSize)),
current_block_size);
- return current_space_used + space_used_.load(std::memory_order_relaxed);
+ return space_used + space_used_.load(std::memory_order_relaxed);
}
size_t SerialArena::FreeStringBlocks(StringBlock* string_block,
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index e9e7a15..7f088a1 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -389,7 +389,11 @@
// message, or nullptr otherwise. If possible, the call resolves at compile
// time. Note that we can often devirtualize calls to `value->GetArena()` so
// usually calling this method is unnecessary.
+ // TODO(b/271599886): remove this function.
template <typename T>
+ ABSL_DEPRECATED(
+ "This will be removed in a future release. Call value->GetArena() "
+ "instead.")
PROTOBUF_ALWAYS_INLINE static Arena* GetArena(T* value) {
return GetArenaInternal(value);
}
@@ -552,7 +556,7 @@
static_assert(
InternalHelper<T>::is_arena_constructable::value,
"CreateMessage can only construct types that are ArenaConstructable");
- if (arena == nullptr) {
+ if (PROTOBUF_PREDICT_FALSE(arena == nullptr)) {
// Generated arena constructor T(Arena*) is protected. Call via
// InternalHelper.
return InternalHelper<T>::New();
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index 4832cff..42984df 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -1472,44 +1472,21 @@
Arena arena;
ArenaMessage* message = Arena::CreateMessage<ArenaMessage>(&arena);
const ArenaMessage* const_pointer_to_message = message;
- EXPECT_EQ(&arena, Arena::GetArena(message));
- EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message));
+ EXPECT_EQ(&arena, message->GetArena());
+ EXPECT_EQ(&arena, const_pointer_to_message->GetArena());
// Test that the Message* / MessageLite* specialization SFINAE works.
const Message* const_pointer_to_message_type = message;
- EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message_type));
+ EXPECT_EQ(&arena, const_pointer_to_message_type->GetArena());
const MessageLite* const_pointer_to_message_lite_type = message;
- EXPECT_EQ(&arena, Arena::GetArena(const_pointer_to_message_lite_type));
+ EXPECT_EQ(&arena, const_pointer_to_message_lite_type->GetArena());
}
TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaAllocatedMessages) {
ArenaMessage message;
const ArenaMessage* const_pointer_to_message = &message;
- EXPECT_EQ(nullptr, Arena::GetArena(&message));
- EXPECT_EQ(nullptr, Arena::GetArena(const_pointer_to_message));
-}
-
-TEST(ArenaTest, GetArenaShouldReturnNullForNonArenaCompatibleTypes) {
- // Test that GetArena returns nullptr for types that have a GetArena method
- // that doesn't return Arena*.
- struct {
- int GetArena() const { return 0; }
- } has_get_arena_method_wrong_return_type;
- EXPECT_EQ(nullptr, Arena::GetArena(&has_get_arena_method_wrong_return_type));
-
- // Test that GetArena returns nullptr for types that have a GetArena alias.
- struct {
- using GetArena = Arena*;
- GetArena unused;
- } has_get_arena_alias;
- EXPECT_EQ(nullptr, Arena::GetArena(&has_get_arena_alias));
-
- // Test that GetArena returns nullptr for types that have a GetArena data
- // member.
- struct {
- Arena GetArena;
- } has_get_arena_data_member;
- EXPECT_EQ(nullptr, Arena::GetArena(&has_get_arena_data_member));
+ EXPECT_EQ(nullptr, message.GetArena());
+ EXPECT_EQ(nullptr, const_pointer_to_message->GetArena());
}
TEST(ArenaTest, AddCleanup) {
diff --git a/src/google/protobuf/compiler/BUILD.bazel b/src/google/protobuf/compiler/BUILD.bazel
index 1977211..c880205 100644
--- a/src/google/protobuf/compiler/BUILD.bazel
+++ b/src/google/protobuf/compiler/BUILD.bazel
@@ -89,7 +89,9 @@
deps = [
":code_generator",
":importer",
+ ":retention",
"//src/google/protobuf:protobuf_nowkt",
+ "//src/google/protobuf/compiler/allowlists",
"@com_google_absl//absl/container:btree",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
@@ -116,6 +118,7 @@
"//src/google/protobuf/compiler/php",
"//src/google/protobuf/compiler/python",
"//src/google/protobuf/compiler/ruby",
+ "//src/google/protobuf/compiler/rust",
"@com_google_absl//absl/log:initialize",
],
)
@@ -258,6 +261,7 @@
data = [
":test_plugin",
"//:test_proto_srcs",
+ "//src/google/protobuf:descriptor_proto_srcs",
"//src/google/protobuf:testdata",
],
deps = [
@@ -377,10 +381,13 @@
filegroup(
name = "test_srcs",
- srcs = glob([
- "*_test.cc",
- "*unittest.cc",
- ], allow_empty = True) + [
+ srcs = glob(
+ [
+ "*_test.cc",
+ "*unittest.cc",
+ ],
+ allow_empty = True,
+ ) + [
"//src/google/protobuf/compiler/cpp:test_srcs",
"//src/google/protobuf/compiler/csharp:test_srcs",
"//src/google/protobuf/compiler/java:test_srcs",
diff --git a/src/google/protobuf/compiler/allowlists/BUILD.bazel b/src/google/protobuf/compiler/allowlists/BUILD.bazel
new file mode 100644
index 0000000..c57091e
--- /dev/null
+++ b/src/google/protobuf/compiler/allowlists/BUILD.bazel
@@ -0,0 +1,42 @@
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
+load("//build_defs:cpp_opts.bzl", "COPTS")
+
+package(default_visibility = ["//visibility:private"])
+
+cc_library(
+ name = "allowlist",
+ hdrs = ["allowlist.h"],
+ copts = COPTS,
+ include_prefix = "google/protobuf/compiler/allowlists",
+ deps = [
+ "//src/google/protobuf/stubs",
+ "@com_google_absl//absl/algorithm:container",
+ "@com_google_absl//absl/base:core_headers",
+ "@com_google_absl//absl/strings",
+ "@com_google_absl//absl/types:span",
+ ],
+)
+
+cc_library(
+ name = "allowlists",
+ srcs = ["allowlists.cc"],
+ hdrs = ["allowlists.h"],
+ copts = COPTS,
+ include_prefix = "google/protobuf/compiler/allowlists",
+ visibility = ["//src/google/protobuf:__subpackages__"],
+ deps = [
+ ":allowlist",
+ "@com_google_absl//absl/strings",
+ ],
+)
+
+cc_test(
+ name = "allowlist_test",
+ srcs = ["allowlist_test.cc"],
+ copts = COPTS,
+ deps = [
+ ":allowlist",
+ "@com_google_googletest//:gtest",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/src/google/protobuf/compiler/allowlists/allowlist.h b/src/google/protobuf/compiler/allowlists/allowlist.h
new file mode 100644
index 0000000..191c138
--- /dev/null
+++ b/src/google/protobuf/compiler/allowlists/allowlist.h
@@ -0,0 +1,148 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_ALLOWLISTS_ALLOWLIST_H__
+#define GOOGLE_PROTOBUF_COMPILER_ALLOWLISTS_ALLOWLIST_H__
+
+#include <cstddef>
+#include <cstring>
+
+#include "absl/algorithm/container.h"
+#include "google/protobuf/stubs/common.h"
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "absl/types/span.h"
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace internal {
+enum AllowlistFlags : unsigned int {
+ kNone = 0,
+ kMatchPrefix = 1 << 1,
+ kAllowAllInOss = 1 << 2,
+};
+
+// An allowlist of things (messages, files, targets) that are allowed to violate
+// some constraint.
+//
+// This is fundamentally a simple API over a set of static strings. It should
+// only ever be used as a `static const` variable.
+//
+// These allowlists are usually only used internally within Google, and contain
+// the names of internal files and Protobufs. In open source, these lists become
+// no-ops (either they always or never allow everything).
+template <size_t n>
+class Allowlist final {
+ public:
+ template <size_t m = n, typename = std::enable_if_t<m != 0>>
+ constexpr Allowlist(const absl::string_view (&list)[n], AllowlistFlags flags)
+ : flags_(flags) {
+ for (size_t i = 0; i < n; ++i) {
+ list_[i] = list[i];
+ if (i != 0) {
+ ABSL_ASSERT(list_[i - 1] < list_[i] && "Allowlist must be sorted!");
+ }
+ }
+ }
+
+ template <size_t m = n, typename = std::enable_if_t<m == 0>>
+ explicit constexpr Allowlist(AllowlistFlags flags)
+ : list_(nullptr, 0), flags_(flags) {}
+
+ // Checks if the element is allowed by this allowlist.
+ bool Allows(absl::string_view name) const {
+ if (flags_ & AllowlistFlags::kAllowAllInOss) return true;
+
+ // Convert to a span to get access to standard algorithms without resorting
+ // to horrible things like std::end().
+ absl::Span<const absl::string_view> list = list_;
+
+ auto bound = absl::c_lower_bound(list, name);
+ if (bound == list.end()) {
+ // If this string has the last element as a prefix, it will appear as if
+ // the element is not present in the list; we can take care of this case
+ // by manually checking the last element.
+ //
+ // This will also spuriously fire if a string sorts before everything in
+ // the list, but in that case the check will still return false as
+ // expected.
+ if (flags_ & AllowlistFlags::kMatchPrefix && !list.empty()) {
+ return absl::StartsWith(name, list.back());
+ }
+
+ return false;
+ }
+
+ if (name == *bound) return true;
+
+ if (flags_ & AllowlistFlags::kMatchPrefix && bound != list.begin()) {
+ return absl::StartsWith(name, bound[-1]);
+ }
+
+ return false;
+ }
+
+ private:
+ constexpr absl::Span<const absl::string_view> list() const { return list_; }
+
+ // NOTE: std::array::operator[] is *not* constexpr before C++17.
+ //
+ // In order for a zero-element list to work, we replace the array with a
+ // null string view when the size is zero.
+ std::conditional_t<n != 0, absl::string_view[n],
+ absl::Span<absl::string_view>>
+ list_;
+ AllowlistFlags flags_;
+};
+
+struct EmptyAllowlistSentinel {};
+
+// This overload picks up MakeAllowlist({}), since zero-length arrays are not
+// a thing in C++.
+constexpr Allowlist<0> MakeAllowlist(
+ EmptyAllowlistSentinel, // This binds to `{}`.
+ AllowlistFlags flags = AllowlistFlags::kNone) {
+ return Allowlist<0>(flags);
+}
+
+template <size_t n>
+constexpr Allowlist<n> MakeAllowlist(
+ const absl::string_view (&list)[n],
+ AllowlistFlags flags = AllowlistFlags::kNone) {
+ return Allowlist<n>(list, flags);
+}
+
+} // namespace internal
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_ALLOWLISTS_ALLOWLIST_H__
diff --git a/src/google/protobuf/compiler/allowlists/allowlist_test.cc b/src/google/protobuf/compiler/allowlists/allowlist_test.cc
new file mode 100644
index 0000000..03dda91
--- /dev/null
+++ b/src/google/protobuf/compiler/allowlists/allowlist_test.cc
@@ -0,0 +1,120 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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 "google/protobuf/compiler/allowlists/allowlist.h"
+
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace internal {
+namespace {
+
+TEST(AllowlistTest, Smoke) {
+ static const auto kList = MakeAllowlist({
+ "bar",
+ "baz",
+ "foo",
+ });
+
+ EXPECT_TRUE(kList.Allows("bar"));
+ EXPECT_TRUE(kList.Allows("baz"));
+ EXPECT_TRUE(kList.Allows("foo"));
+ EXPECT_FALSE(kList.Allows("barf"));
+ EXPECT_FALSE(kList.Allows("baq"));
+ EXPECT_FALSE(kList.Allows("bak"));
+ EXPECT_FALSE(kList.Allows("foob"));
+}
+
+TEST(AllowlistTest, Empty) {
+ static const auto kList = MakeAllowlist({});
+
+ EXPECT_FALSE(kList.Allows("bar"));
+ EXPECT_FALSE(kList.Allows("baz"));
+ EXPECT_FALSE(kList.Allows("foo"));
+ EXPECT_FALSE(kList.Allows("barf"));
+ EXPECT_FALSE(kList.Allows("baq"));
+ EXPECT_FALSE(kList.Allows("bak"));
+ EXPECT_FALSE(kList.Allows("foob"));
+}
+
+TEST(AllowlistTest, Prefix) {
+ static const auto kList = MakeAllowlist(
+ {
+ "bar",
+ "baz",
+ "foo",
+ },
+ AllowlistFlags::kMatchPrefix);
+
+ EXPECT_TRUE(kList.Allows("bar"));
+ EXPECT_TRUE(kList.Allows("baz"));
+ EXPECT_TRUE(kList.Allows("foo"));
+ EXPECT_TRUE(kList.Allows("barf"));
+ EXPECT_TRUE(kList.Allows("foon"));
+ EXPECT_TRUE(kList.Allows("bazaar"));
+ EXPECT_FALSE(kList.Allows("baq"));
+ EXPECT_FALSE(kList.Allows("bbr"));
+ EXPECT_FALSE(kList.Allows("fbar"));
+ EXPECT_FALSE(kList.Allows("ba"));
+ EXPECT_FALSE(kList.Allows("fon"));
+ EXPECT_FALSE(kList.Allows("fop"));
+}
+
+TEST(AllowlistTest, Oss) {
+ static const auto kList = MakeAllowlist(
+ {
+ "bar",
+ "baz",
+ "foo",
+ },
+ AllowlistFlags::kAllowAllInOss);
+
+ EXPECT_TRUE(kList.Allows("bar"));
+ EXPECT_TRUE(kList.Allows("baz"));
+ EXPECT_TRUE(kList.Allows("foo"));
+ EXPECT_TRUE(kList.Allows("barf"));
+ EXPECT_TRUE(kList.Allows("baq"));
+ EXPECT_TRUE(kList.Allows("bak"));
+ EXPECT_TRUE(kList.Allows("foob"));
+}
+
+#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
+TEST(AllowlistTest, Unsorted) {
+ EXPECT_DEATH(MakeAllowlist({"foo", "bar"}), "Allowlist must be sorted!");
+}
+#endif
+
+} // namespace
+} // namespace internal
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/allowlists/allowlists.cc b/src/google/protobuf/compiler/allowlists/allowlists.cc
new file mode 100644
index 0000000..0e4d60f
--- /dev/null
+++ b/src/google/protobuf/compiler/allowlists/allowlists.cc
@@ -0,0 +1,53 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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 "google/protobuf/compiler/allowlists/allowlists.h"
+
+#include "absl/strings/string_view.h"
+#include "google/protobuf/compiler/allowlists/allowlist.h"
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+// NOTE: Allowlists in this file are not accepting new entries unless otherwise
+// specified.
+
+static constexpr auto kWeakImports = internal::MakeAllowlist({
+// Intentionally left blank.
+});
+
+bool IsWeakImportFile(absl::string_view filename) {
+ return kWeakImports.Allows(filename);
+}
+
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/allowlists/allowlists.h b/src/google/protobuf/compiler/allowlists/allowlists.h
new file mode 100644
index 0000000..b2dc174
--- /dev/null
+++ b/src/google/protobuf/compiler/allowlists/allowlists.h
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_ALLOWLISTS_ALLOWLISTS_H__
+#define GOOGLE_PROTOBUF_COMPILER_ALLOWLISTS_ALLOWLISTS_H__
+
+#include "absl/strings/string_view.h"
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+
+// Returns whether a file can use the `import weak` syntax.
+bool IsWeakImportFile(absl::string_view file);
+
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_ALLOWLISTS_COMPILER_ALLOWLISTS_H__
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 43a576d..86ae4b7 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -36,6 +36,7 @@
#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
+#include "google/protobuf/compiler/allowlists/allowlists.h"
#include "google/protobuf/stubs/platform_macros.h"
@@ -86,6 +87,7 @@
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/code_generator.h"
#include "google/protobuf/compiler/importer.h"
+#include "google/protobuf/compiler/retention.h"
#include "google/protobuf/compiler/zip_writer.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/dynamic_message.h"
@@ -2631,7 +2633,7 @@
// Add this file.
FileDescriptorProto* new_descriptor = output->Add();
- file->CopyTo(new_descriptor);
+ *new_descriptor = StripSourceRetentionOptions(*file);
if (include_json_name) {
file->CopyJsonNameTo(new_descriptor);
}
diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc
index c89f473..0b6d4aa 100644
--- a/src/google/protobuf/compiler/command_line_interface_unittest.cc
+++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc
@@ -1693,6 +1693,43 @@
EXPECT_TRUE(descriptor_set.file(1).has_source_code_info());
}
+TEST_F(CommandLineInterfaceTest, DescriptorSetOptionRetention) {
+ // clang-format off
+ CreateTempFile(
+ "foo.proto",
+ absl::Substitute(R"pb(
+ syntax = "proto2";
+ import "$0";
+ extend google.protobuf.FileOptions {
+ optional int32 runtime_retention_option = 50001
+ [retention = RETENTION_RUNTIME];
+ optional int32 source_retention_option = 50002
+ [retention = RETENTION_SOURCE];
+ }
+ option (runtime_retention_option) = 2;
+ option (source_retention_option) = 3;)pb",
+ DescriptorProto::descriptor()->file()->name()));
+ // clang-format on
+ std::string descriptor_proto_base_dir = "src";
+ Run(absl::Substitute(
+ "protocol_compiler --descriptor_set_out=$$tmpdir/descriptor_set "
+ "--proto_path=$$tmpdir --proto_path=$0 foo.proto",
+ descriptor_proto_base_dir));
+ ExpectNoErrors();
+
+ FileDescriptorSet descriptor_set;
+ ReadDescriptorSet("descriptor_set", &descriptor_set);
+ ASSERT_EQ(descriptor_set.file_size(), 1);
+ const UnknownFieldSet& unknown_fields =
+ descriptor_set.file(0).options().unknown_fields();
+
+ // We expect runtime_retention_option to be present while
+ // source_retention_option should have been stripped.
+ ASSERT_EQ(unknown_fields.field_count(), 1);
+ EXPECT_EQ(unknown_fields.field(0).number(), 50001);
+ EXPECT_EQ(unknown_fields.field(0).varint(), 2);
+}
+
#ifdef _WIN32
// TODO(teboring): Figure out how to write test on windows.
#else
diff --git a/src/google/protobuf/compiler/cpp/BUILD.bazel b/src/google/protobuf/compiler/cpp/BUILD.bazel
index bd69440..e2908b3 100644
--- a/src/google/protobuf/compiler/cpp/BUILD.bazel
+++ b/src/google/protobuf/compiler/cpp/BUILD.bazel
@@ -47,6 +47,7 @@
"enum.cc",
"extension.cc",
"field.cc",
+ "field_generators/cord_field.cc",
"field_generators/enum_field.cc",
"field_generators/map_field.cc",
"field_generators/message_field.cc",
diff --git a/src/google/protobuf/compiler/cpp/enum.cc b/src/google/protobuf/compiler/cpp/enum.cc
index fdfcd4a..552e874 100644
--- a/src/google/protobuf/compiler/cpp/enum.cc
+++ b/src/google/protobuf/compiler/cpp/enum.cc
@@ -143,7 +143,7 @@
.AnnotatedAs(value),
{"kNumber", Int32ToString(value->number())},
{"DEPRECATED", value->options().deprecated()
- ? "PROTOBUF_DEPRECATED_ENUM"
+ ? "PROTOBUF_DEPRECATED"
: ""},
},
R"cc(
@@ -302,7 +302,7 @@
{
Sub("VALUE", EnumValueName(enum_->value(j))).AnnotatedAs(value),
{"DEPRECATED",
- value->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM" : ""},
+ value->options().deprecated() ? "PROTOBUF_DEPRECATED" : ""},
},
R"cc(
$DEPRECATED $static constexpr $Enum_$ $VALUE$ = $Msg_Enum$_$VALUE$;
diff --git a/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc b/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc
new file mode 100644
index 0000000..c79c88c
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/field_generators/cord_field.cc
@@ -0,0 +1,419 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+// Author: kenton@google.com (Kenton Varda)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <memory>
+#include <string>
+#include <tuple>
+
+#include "absl/container/flat_hash_map.h"
+#include "absl/log/absl_check.h"
+#include "absl/strings/escaping.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/substitute.h"
+#include "google/protobuf/compiler/cpp/field.h"
+#include "google/protobuf/compiler/cpp/field_generators/generators.h"
+#include "google/protobuf/compiler/cpp/helpers.h"
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+namespace {
+void SetCordVariables(
+ const FieldDescriptor* descriptor,
+ absl::flat_hash_map<absl::string_view, std::string>* variables,
+ const Options& options) {
+ (*variables)["default"] = absl::StrCat(
+ "\"", absl::CEscape(descriptor->default_value_string()), "\"");
+ (*variables)["default_length"] =
+ absl::StrCat(descriptor->default_value_string().length());
+ (*variables)["full_name"] = descriptor->full_name();
+ // For one of Cords
+ (*variables)["default_variable_name"] = MakeDefaultName(descriptor);
+ (*variables)["default_variable_field"] = MakeDefaultFieldName(descriptor);
+ (*variables)["default_variable"] =
+ descriptor->default_value_string().empty()
+ ? ProtobufNamespace(options) +
+ "::internal::GetEmptyCordAlreadyInited()"
+ : absl::StrCat(
+ QualifiedClassName(descriptor->containing_type(), options),
+ "::", MakeDefaultFieldName(descriptor));
+}
+
+class CordFieldGenerator : public FieldGeneratorBase {
+ public:
+ CordFieldGenerator(const FieldDescriptor* descriptor, const Options& options);
+ ~CordFieldGenerator() override = default;
+
+ void GeneratePrivateMembers(io::Printer* printer) const override;
+ void GenerateAccessorDeclarations(io::Printer* printer) const override;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+ void GenerateClearingCode(io::Printer* printer) const override;
+ void GenerateMergingCode(io::Printer* printer) const override;
+ void GenerateSwappingCode(io::Printer* printer) const override;
+ void GenerateConstructorCode(io::Printer* printer) const override;
+ void GenerateDestructorCode(io::Printer* printer) const override;
+ void GenerateArenaDestructorCode(io::Printer* printer) const override;
+ void GenerateSerializeWithCachedSizesToArray(
+ io::Printer* printer) const override;
+ void GenerateByteSize(io::Printer* printer) const override;
+ void GenerateAggregateInitializer(io::Printer* printer) const override;
+ void GenerateConstexprAggregateInitializer(
+ io::Printer* printer) const override;
+ ArenaDtorNeeds NeedsArenaDestructor() const override {
+ return ArenaDtorNeeds::kRequired;
+ }
+};
+
+class CordOneofFieldGenerator : public CordFieldGenerator {
+ public:
+ CordOneofFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
+ ~CordOneofFieldGenerator() override = default;
+
+ void GeneratePrivateMembers(io::Printer* printer) const override;
+ void GenerateStaticMembers(io::Printer* printer) const override;
+ void GenerateInlineAccessorDefinitions(io::Printer* printer) const override;
+ void GenerateNonInlineAccessorDefinitions(
+ io::Printer* printer) const override;
+ void GenerateClearingCode(io::Printer* printer) const override;
+ void GenerateSwappingCode(io::Printer* printer) const override;
+ void GenerateConstructorCode(io::Printer* printer) const override {}
+ void GenerateArenaDestructorCode(io::Printer* printer) const override;
+ // Overrides CordFieldGenerator behavior.
+ ArenaDtorNeeds NeedsArenaDestructor() const override {
+ return ArenaDtorNeeds::kNone;
+ }
+};
+
+
+CordFieldGenerator::CordFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : FieldGeneratorBase(descriptor, options) {
+ SetCordVariables(descriptor, &variables_, options);
+}
+
+void CordFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format("::absl::Cord $name$_;\n");
+ if (!descriptor_->default_value_string().empty()) {
+ format(
+ "struct _default_$name$_func_ {\n"
+ " constexpr absl::string_view operator()() const {\n"
+ " return absl::string_view($default$, $default_length$);\n"
+ " }\n"
+ "};\n");
+ }
+}
+
+void CordFieldGenerator::GenerateAccessorDeclarations(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format("$deprecated_attr$const ::absl::Cord& ${1$$name$$}$() const;\n",
+ descriptor_);
+ format(
+ "$deprecated_attr$void ${1$set_$name$$}$(const ::absl::Cord& value);\n"
+ "$deprecated_attr$void ${1$set_$name$$}$(::absl::string_view value);\n",
+ std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::SET));
+ format("private:\n");
+ format(
+ "void ${1$_internal_set_$name$$}$(const ::absl::Cord& value);\n"
+ "::absl::Cord* ${1$_internal_mutable_$name$$}$();\n"
+ "public:\n",
+ descriptor_);
+}
+
+void CordFieldGenerator::GenerateInlineAccessorDefinitions(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format(
+ "inline const ::absl::Cord& $classname$::_internal_$name$() const {\n"
+ " return $field$;\n"
+ "}\n"
+ "inline const ::absl::Cord& $classname$::$name$() const {\n"
+ "$annotate_get$"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return _internal_$name$();\n"
+ "}\n"
+ "inline void $classname$::_internal_set_$name$(const ::absl::Cord& "
+ "value) {\n"
+ " $set_hasbit$\n"
+ " $field$ = value;\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const ::absl::Cord& value) {\n"
+ "$maybe_prepare_split_message$"
+ " _internal_set_$name$(value);\n"
+ "$annotate_set$"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::set_$name$(::absl::string_view value) {\n"
+ "$maybe_prepare_split_message$"
+ " $set_hasbit$\n"
+ " $field$ = value;\n"
+ "$annotate_set$"
+ " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
+ "}\n");
+}
+
+void CordFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ if (descriptor_->default_value_string().empty()) {
+ format("$field$.clear();\n");
+ } else {
+ format("$field$ = ::absl::string_view($default$, $default_length$);\n");
+ }
+}
+
+void CordFieldGenerator::GenerateMergingCode(io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format("_this->_internal_set_$name$(from._internal_$name$());\n");
+}
+
+void CordFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format("$field$.swap(other->$field$);\n");
+}
+
+void CordFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
+ ABSL_CHECK(!ShouldSplit(descriptor_, options_));
+ Formatter format(printer, variables_);
+ if (!descriptor_->default_value_string().empty()) {
+ format("$field$ = ::absl::string_view($default$, $default_length$);\n");
+ }
+}
+
+void CordFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ if (ShouldSplit(descriptor_, options_)) {
+ // A cord field in the `Split` struct is automatically destroyed when the
+ // split pointer is deleted and should not be explicitly destroyed here.
+ return;
+ }
+ format("$field$.~Cord();\n");
+}
+
+void CordFieldGenerator::GenerateArenaDestructorCode(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ // _this is the object being destructed (we are inside a static method here).
+ format("_this->$field$. ::absl::Cord::~Cord ();\n");
+}
+
+void CordFieldGenerator::GenerateSerializeWithCachedSizesToArray(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ if (descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+ GenerateUtf8CheckCodeForCord(
+ descriptor_, options_, false,
+ absl::Substitute("this->_internal_$0(), ", printer->LookupVar("name")),
+ format);
+ }
+ format(
+ "target = stream->Write$declared_type$($number$, "
+ "this->_internal_$name$(), "
+ "target);\n");
+}
+
+void CordFieldGenerator::GenerateByteSize(io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format(
+ "total_size += $tag_size$ +\n"
+ " ::$proto_ns$::internal::WireFormatLite::$declared_type$Size(\n"
+ " this->_internal_$name$());\n");
+}
+
+void CordFieldGenerator::GenerateConstexprAggregateInitializer(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ if (descriptor_->default_value_string().empty()) {
+ format("/*decltype($field$)*/{}");
+ } else {
+ format(
+ "/*decltype($field$)*/{::absl::strings_internal::MakeStringConstant(\n"
+ " $classname$::Impl_::$1$_default_$name$_func_{})}",
+ ShouldSplit(descriptor_, options_) ? "Split::" : "");
+ }
+}
+
+void CordFieldGenerator::GenerateAggregateInitializer(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ if (ShouldSplit(descriptor_, options_)) {
+ format("decltype(Impl_::Split::$name$_){}");
+ return;
+ }
+ format("decltype($field$){}");
+}
+
+// ===================================================================
+
+CordOneofFieldGenerator::CordOneofFieldGenerator(
+ const FieldDescriptor* descriptor, const Options& options)
+ : CordFieldGenerator(descriptor, options) {
+}
+
+void CordOneofFieldGenerator::GeneratePrivateMembers(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format("::absl::Cord *$name$_;\n");
+}
+
+void CordOneofFieldGenerator::GenerateStaticMembers(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ if (!descriptor_->default_value_string().empty()) {
+ format(
+ "struct _default_$name$_func_ {\n"
+ " constexpr absl::string_view operator()() const {\n"
+ " return absl::string_view($default$, $default_length$);\n"
+ " }\n"
+ "};"
+ "static const ::absl::Cord $default_variable_name$;\n");
+ }
+}
+
+void CordOneofFieldGenerator::GenerateInlineAccessorDefinitions(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format(
+ "inline const ::absl::Cord& $classname$::_internal_$name$() const {\n"
+ " if ($has_field$) {\n"
+ " return *$field$;\n"
+ " }\n"
+ " return $default_variable$;\n"
+ "}\n"
+ "inline const ::absl::Cord& $classname$::$name$() const {\n"
+ "$annotate_get$"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return _internal_$name$();\n"
+ "}\n"
+ "inline void $classname$::_internal_set_$name$(const ::absl::Cord& "
+ "value) {\n"
+ " if ($not_has_field$) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $field$ = new ::absl::Cord;\n"
+ " if (GetArenaForAllocation() != nullptr) {\n"
+ " GetArenaForAllocation()->Own($field$);\n"
+ " }\n"
+ " }\n"
+ " *$field$ = value;\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const ::absl::Cord& value) {\n"
+ " _internal_set_$name$(value);\n"
+ "$annotate_set$"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::set_$name$(::absl::string_view value) {\n"
+ " if ($not_has_field$) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $field$ = new ::absl::Cord;\n"
+ " if (GetArenaForAllocation() != nullptr) {\n"
+ " GetArenaForAllocation()->Own($field$);\n"
+ " }\n"
+ " }\n"
+ " *$field$ = value;\n"
+ "$annotate_set$"
+ " // @@protoc_insertion_point(field_set_string_piece:$full_name$)\n"
+ "}\n"
+ "inline ::absl::Cord* $classname$::_internal_mutable_$name$() {\n"
+ " if ($not_has_field$) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $field$ = new ::absl::Cord;\n"
+ " if (GetArenaForAllocation() != nullptr) {\n"
+ " GetArenaForAllocation()->Own($field$);\n"
+ " }\n"
+ " }\n"
+ " return $field$;\n"
+ "}\n"
+ "inline ::absl::Cord* $classname$::mutable_$name$() {\n"
+ " ::absl::Cord* _cord = _internal_mutable_$name$();\n"
+ "$annotate_mutable$"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return _cord;\n"
+ "}\n");
+}
+
+void CordOneofFieldGenerator::GenerateNonInlineAccessorDefinitions(
+ io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ if (!descriptor_->default_value_string().empty()) {
+ format(
+ "PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
+ "const ::absl::Cord $classname$::$default_variable_field$(\n"
+ " ::absl::strings_internal::MakeStringConstant(\n"
+ " _default_$name$_func_{}));\n");
+ }
+}
+
+void CordOneofFieldGenerator::GenerateClearingCode(io::Printer* printer) const {
+ Formatter format(printer, variables_);
+ format(
+ "if (GetArenaForAllocation() == nullptr) {\n"
+ " delete $field$;\n"
+ "}\n");
+}
+
+void CordOneofFieldGenerator::GenerateSwappingCode(io::Printer* printer) const {
+ // Don't print any swapping code. Swapping the union will swap this field.
+}
+
+void CordOneofFieldGenerator::GenerateArenaDestructorCode(
+ io::Printer* printer) const {
+ // We inherit from CordFieldGenerator, so we need to re-override to the
+ // default behavior here.
+}
+
+// ===================================================================
+} // namespace
+
+std::unique_ptr<FieldGeneratorBase> MakeSingularCordGenerator(
+ const FieldDescriptor* desc, const Options& options,
+ MessageSCCAnalyzer* scc) {
+ return absl::make_unique<CordFieldGenerator>(desc, options);
+}
+
+
+std::unique_ptr<FieldGeneratorBase> MakeOneofCordGenerator(
+ const FieldDescriptor* desc, const Options& options,
+ MessageSCCAnalyzer* scc) {
+ return absl::make_unique<CordOneofFieldGenerator>(desc, options);
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
index 9744204..19bd6b5 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc
@@ -51,6 +51,7 @@
namespace compiler {
namespace cpp {
namespace {
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
using Sub = ::google::protobuf::io::Printer::Sub;
std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts) {
@@ -172,7 +173,8 @@
void SingularEnum::GenerateAccessorDeclarations(io::Printer* p) const {
auto v = p->WithVars(
- AnnotatedAccessors(field_, {"", "set_", "_internal_", "_internal_set_"}));
+ AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+ auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
p->Emit(R"cc(
$DEPRECATED$ $Enum$ $name$() const;
$DEPRECATED$ void $set_name$($Enum$ value);
@@ -331,9 +333,12 @@
};
void RepeatedEnum::GenerateAccessorDeclarations(io::Printer* p) const {
- auto v = p->WithVars(
- AnnotatedAccessors(field_, {"", "set_", "add_", "mutable_", "_internal_",
- "_internal_add_", "_internal_mutable_"}));
+ auto v = p->WithVars(AnnotatedAccessors(
+ field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+ auto vs =
+ p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+ auto vm =
+ p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
p->Emit(R"cc(
public:
diff --git a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
index 79f1015..a91a394 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/map_field.cc
@@ -30,6 +30,7 @@
#include <memory>
#include <string>
+#include <tuple>
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
@@ -141,10 +142,12 @@
" ${1$_internal_mutable_$name$$}$();\n"
"public:\n"
"$deprecated_attr$const ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >&\n"
- " ${1$$name$$}$() const;\n"
+ " ${1$$name$$}$() const;\n",
+ descriptor_);
+ format(
"$deprecated_attr$::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
" ${1$mutable_$name$$}$();\n",
- descriptor_);
+ std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::ALIAS));
}
void MapFieldGenerator::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
index 6eaadef..b4bf2a9 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/message_field.cc
@@ -809,9 +809,11 @@
"$type$* ${1$_internal_add_$name$$}$();\n"
"public:\n",
descriptor_);
+ format("$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n",
+ descriptor_);
+ format("$deprecated_attr$$type$* ${1$add_$name$$}$();\n",
+ std::make_tuple(descriptor_, GeneratedCodeInfo::Annotation::SET));
format(
- "$deprecated_attr$const $type$& ${1$$name$$}$(int index) const;\n"
- "$deprecated_attr$$type$* ${1$add_$name$$}$();\n"
"$deprecated_attr$const ::$proto_ns$::RepeatedPtrField< $type$ >&\n"
" ${1$$name$$}$() const;\n",
descriptor_);
diff --git a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
index 5bbf298..b15801e 100644
--- a/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/field_generators/primitive_field.cc
@@ -56,7 +56,7 @@
using ::google::protobuf::internal::WireFormat;
using ::google::protobuf::internal::WireFormatLite;
using Sub = ::google::protobuf::io::Printer::Sub;
-using Annotation = ::google::protobuf::GeneratedCodeInfo::Annotation;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
// For encodings with fixed sizes, returns that size in bytes.
absl::optional<size_t> FixedSize(FieldDescriptor::Type type) {
@@ -193,18 +193,10 @@
};
void SingularPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
+ auto v = p->WithVars(
+ AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
+ auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
p->Emit(
- {
- Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
- Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_name",
- absl::StrCat("_internal_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_set_name",
- absl::StrCat("_internal_set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- },
R"cc(
$DEPRECATED$ $Type$ $name$() const;
$DEPRECATED$ void $set_name$($Type$ value);
@@ -397,41 +389,27 @@
}
void RepeatedPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
- p->Emit(
- {
- Sub("name", p->LookupVar("name")).AnnotatedAs(field_),
- Sub("set_name", absl::StrCat("set_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("add_name", absl::StrCat("add_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("mutable_name", absl::StrCat("mutable_", p->LookupVar("name")))
- .AnnotatedAs(field_),
+ auto v = p->WithVars(AnnotatedAccessors(
+ field_, {"", "_internal_", "_internal_add_", "_internal_mutable_"}));
+ auto vs =
+ p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
+ auto va =
+ p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
+ p->Emit(R"cc(
+ $DEPRECATED$ $Type$ $name$(int index) const;
+ $DEPRECATED$ void $set_name$(int index, $Type$ value);
+ $DEPRECATED$ void $add_name$($Type$ value);
+ $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
+ $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
- Sub("_internal_name",
- absl::StrCat("_internal_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_add_name",
- absl::StrCat("_internal_add_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- Sub("_internal_mutable_name",
- absl::StrCat("_internal_mutable_", p->LookupVar("name")))
- .AnnotatedAs(field_),
- },
- R"cc(
- $DEPRECATED$ $Type$ $name$(int index) const;
- $DEPRECATED$ void $set_name$(int index, $Type$ value);
- $DEPRECATED$ void $add_name$($Type$ value);
- $DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
- $DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
+ private:
+ $Type$ $_internal_name$(int index) const;
+ void $_internal_add_name$($Type$ value);
+ const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
+ $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
- private:
- $Type$ $_internal_name$(int index) const;
- void $_internal_add_name$($Type$ value);
- const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
- $pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
-
- public:
- )cc");
+ public:
+ )cc");
}
void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
diff --git a/src/google/protobuf/compiler/cpp/generator.cc b/src/google/protobuf/compiler/cpp/generator.cc
index c485cdb..ab26320 100644
--- a/src/google/protobuf/compiler/cpp/generator.cc
+++ b/src/google/protobuf/compiler/cpp/generator.cc
@@ -52,6 +52,7 @@
namespace compiler {
namespace cpp {
namespace {
+
std::string NumberedCcFileName(absl::string_view basename, int number) {
return absl::StrCat(basename, ".out/", number, ".cc");
}
@@ -161,6 +162,14 @@
} else if (key == "proto_static_reflection_h") {
} else if (key == "annotate_accessor") {
file_options.annotate_accessor = true;
+ } else if (key == "protos_for_field_listener_events") {
+ for (absl::string_view proto : absl::StrSplit(value, ':')) {
+ if (proto == file->name()) {
+ file_options.field_listener_options.inject_field_listener_events =
+ true;
+ break;
+ }
+ }
} else if (key == "inject_field_listener_events") {
file_options.field_listener_options.inject_field_listener_events = true;
} else if (key == "forbidden_field_listener_events") {
diff --git a/src/google/protobuf/compiler/cpp/helpers.cc b/src/google/protobuf/compiler/cpp/helpers.cc
index e815e8b..cd4919c 100644
--- a/src/google/protobuf/compiler/cpp/helpers.cc
+++ b/src/google/protobuf/compiler/cpp/helpers.cc
@@ -211,9 +211,9 @@
// Returns true if "field" is a message field that is backed by LazyField per
// profile (go/pdlazy).
-inline bool IsEagerlyVerifiedLazyByProfile(const FieldDescriptor* field,
- const Options& options,
- MessageSCCAnalyzer* scc_analyzer) {
+inline bool IsLazyByProfile(const FieldDescriptor* field,
+ const Options& options,
+ MessageSCCAnalyzer* scc_analyzer) {
return false;
}
@@ -1092,10 +1092,6 @@
return false;
}
-bool IsUtf8String(const FieldDescriptor* field) {
- return IsProto3(field->file()) &&
- field->type() == FieldDescriptor::TYPE_STRING;
-}
VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor) {
(void)descriptor;
diff --git a/src/google/protobuf/compiler/cpp/helpers.h b/src/google/protobuf/compiler/cpp/helpers.h
index df9fba5..fd2ea7b 100644
--- a/src/google/protobuf/compiler/cpp/helpers.h
+++ b/src/google/protobuf/compiler/cpp/helpers.h
@@ -82,7 +82,7 @@
inline std::string DeprecatedAttribute(const Options& /* options */,
const EnumValueDescriptor* d) {
- return d->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM " : "";
+ return d->options().deprecated() ? "PROTOBUF_DEPRECATED " : "";
}
// Commonly-used separator comments. Thick is a line of '=', thin is a line
@@ -323,11 +323,6 @@
const FieldDescriptor* field,
absl::string_view prefix);
-// Returns true if generated messages have public unknown fields accessors
-inline bool PublicUnknownFieldsAccessors(const Descriptor* message) {
- return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
-}
-
// Returns the optimize mode for <file>, respecting <options.enforce_lite>.
FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file,
const Options& options);
@@ -470,10 +465,6 @@
std::string UnderscoresToCamelCase(absl::string_view input,
bool cap_next_letter);
-inline bool IsProto3(const FileDescriptor* file) {
- return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
-}
-
inline bool IsCrossFileMessage(const FieldDescriptor* field) {
return field->type() == FieldDescriptor::TYPE_MESSAGE &&
field->message_type()->file() != field->file();
@@ -1050,8 +1041,6 @@
// Returns VerifySimpleType if messages can be verified by predefined methods.
VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor);
-bool IsUtf8String(const FieldDescriptor* field);
-
bool HasMessageFieldOrExtension(const Descriptor* desc);
// Generates a vector of substitutions for use with Printer::WithVars that
diff --git a/src/google/protobuf/compiler/cpp/message.cc b/src/google/protobuf/compiler/cpp/message.cc
index 88bb015..e34f19b 100644
--- a/src/google/protobuf/compiler/cpp/message.cc
+++ b/src/google/protobuf/compiler/cpp/message.cc
@@ -85,6 +85,7 @@
using ::google::protobuf::internal::WireFormatLite;
using ::google::protobuf::internal::cpp::HasHasbit;
using ::google::protobuf::internal::cpp::Utf8CheckMode;
+using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
using Sub = ::google::protobuf::io::Printer::Sub;
static constexpr int kNoHasbit = -1;
@@ -251,18 +252,6 @@
return false;
}
-// Does the given field have a has_$name$() method?
-bool HasHasMethod(const FieldDescriptor* field) {
- if (!IsProto3(field->file())) {
- // In proto1/proto2, every field has a has_$name$() method.
- return true;
- }
- // For message types without true field presence, only fields with a message
- // type or inside an one-of have a has_$name$() method.
- return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
- field->has_optional_keyword() || field->real_containing_oneof();
-}
-
bool HasInternalHasMethod(const FieldDescriptor* field) {
return !HasHasbit(field) &&
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE;
@@ -730,7 +719,10 @@
{"clearer",
[&] {
p->Emit({Sub("clear_name", absl::StrCat("clear_", name))
- .AnnotatedAs(field)},
+ .AnnotatedAs({
+ field,
+ Semantic::kSet,
+ })},
R"cc(
$deprecated_attr $void $clear_name$() $impl$;
)cc");
@@ -1036,7 +1028,7 @@
// N.B.: Without field presence, we do not use has-bits or generate
// has_$name$() methods, but oneofs still have set_has_$name$().
// Oneofs also have private _internal_has_$name$() a helper method.
- if (HasHasMethod(field)) {
+ if (field->has_presence()) {
format(
"inline bool $classname$::has_$name$() const {\n"
"$annotate_has$"
@@ -1284,16 +1276,14 @@
"}\n"
"\n");
- if (PublicUnknownFieldsAccessors(descriptor_)) {
- format(
- "inline const $unknown_fields_type$& unknown_fields() const {\n"
- " return $unknown_fields$;\n"
- "}\n"
- "inline $unknown_fields_type$* mutable_unknown_fields() {\n"
- " return $mutable_unknown_fields$;\n"
- "}\n"
- "\n");
- }
+ format(
+ "inline const $unknown_fields_type$& unknown_fields() const {\n"
+ " return $unknown_fields$;\n"
+ "}\n"
+ "inline $unknown_fields_type$* mutable_unknown_fields() {\n"
+ " return $mutable_unknown_fields$;\n"
+ "}\n"
+ "\n");
// Only generate this member if it's not disabled.
if (HasDescriptorMethods(descriptor_->file(), options_) &&
@@ -3649,7 +3639,6 @@
LazySerializerEmitter(MessageGenerator* mg, io::Printer* p)
: mg_(mg),
p_(p),
- eager_(IsProto3(mg->descriptor_->file())),
cached_has_bit_index_(kNoHasbit) {}
~LazySerializerEmitter() { Flush(); }
@@ -3658,13 +3647,14 @@
// oneof, and handle them at the next Flush().
void Emit(const FieldDescriptor* field) {
Formatter format(p_);
- if (eager_ || MustFlush(field)) {
+
+ if (!field->has_presence() || MustFlush(field)) {
Flush();
}
if (!field->real_containing_oneof()) {
// TODO(ckennelly): Defer non-oneof fields similarly to oneof fields.
- if (!field->options().weak() && !field->is_repeated() && !eager_) {
+ if (HasHasbit(field) && field->has_presence()) {
// We speculatively load the entire _has_bits_[index] contents, even
// if it is for only one field. Deferring non-oneof emitting would
// allow us to determine whether this is going to be useful.
@@ -3708,7 +3698,6 @@
MessageGenerator* mg_;
io::Printer* p_;
- bool eager_;
std::vector<const FieldDescriptor*> v_;
// cached_has_bit_index_ maintains that:
diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc
index feb5a7f..e95ee56 100644
--- a/src/google/protobuf/compiler/cpp/metadata_test.cc
+++ b/src/google/protobuf/compiler/cpp/metadata_test.cc
@@ -177,6 +177,270 @@
EXPECT_FALSE(atu::GetAnnotationSubstring(test, annotation).has_value());
}
+constexpr absl::string_view kEnumFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ enum Enum { VALUE = 0; }
+ message Message {
+ optional Enum efield = 1;
+ repeated Enum refield = 2;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesEnumSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kEnumFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "efield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_efield" || *substring == "clear_efield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_refield" || *substring == "clear_refield" ||
+ *substring == "add_refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_refield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kMapFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ map<string, int32> mfield = 1;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesMapSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kMapFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kPrimFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional int32 ifield = 1;
+ repeated int32 rifield = 2;
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesPrimSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kPrimFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "ifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_ifield" || *substring == "clear_ifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rifield" || *substring == "clear_rifield" ||
+ *substring == "add_rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rifield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kCordFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional string sfield = 1 [ctype = CORD];
+ repeated string rsfield = 2 [ctype = CORD];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesCordSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kCordFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+ *substring == "add_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
+constexpr absl::string_view kStringPieceFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message Message {
+ optional string sfield = 1 [ctype = STRING_PIECE];
+ repeated string rsfield = 2 [ctype = STRING_PIECE];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesStringPieceSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kStringPieceFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(0).name());
+ std::vector<int> field_path{FileDescriptorProto::kMessageTypeFieldNumber, 0,
+ DescriptorProto::kFieldFieldNumber, 0};
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_sfield" || *substring == "set_alias_sfield" ||
+ *substring == "clear_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_sfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+ field_path.back() = 1;
+ annotations.clear();
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "set_rsfield" ||
+ *substring == "set_alias_rsfield" ||
+ *substring == "clear_rsfield" ||
+ *substring == "add_alias_rsfield" ||
+ *substring == "add_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rsfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ }
+ }
+}
+
constexpr absl::string_view kStringFieldTestFile = R"(
syntax = "proto2";
package foo;
@@ -205,7 +469,7 @@
if (*substring == "sfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (*substring == "set_sfield") {
+ } else if (*substring == "set_sfield" || *substring == "clear_sfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
annotation->semantic());
} else if (*substring == "mutable_sfield") {
@@ -223,7 +487,8 @@
if (*substring == "rsfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (*substring == "set_rsfield") {
+ } else if (*substring == "set_rsfield" || *substring == "clear_rsfield" ||
+ *substring == "add_rsfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
annotation->semantic());
} else if (*substring == "mutable_rsfield") {
@@ -265,6 +530,9 @@
if (*substring == "mfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
+ } else if (*substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
} else if (*substring == "mutable_mfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
annotation->semantic());
@@ -277,15 +545,60 @@
for (const auto* annotation : annotations) {
auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
ASSERT_TRUE(substring.has_value());
- if (substring == "rmfield") {
+ if (*substring == "rmfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
annotation->semantic());
- } else if (substring == "mutable_rmfield") {
+ } else if (*substring == "add_rmfield" || *substring == "clear_rmfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ } else if (*substring == "mutable_rmfield") {
EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
annotation->semantic());
}
}
}
+
+constexpr absl::string_view kLazyMessageFieldTestFile = R"(
+ syntax = "proto2";
+ package foo;
+ message SMessage { }
+ message Message {
+ optional SMessage mfield = 1 [lazy=true];
+ }
+)";
+
+TEST_F(CppMetadataTest, AnnotatesLazyMessageSemantics) {
+ FileDescriptorProto file;
+ GeneratedCodeInfo info;
+ std::string pb_h;
+ atu::AddFile("test.proto", kLazyMessageFieldTestFile);
+ EXPECT_TRUE(CaptureMetadata("test.proto", &file, &pb_h, &info, nullptr,
+ nullptr, nullptr));
+ EXPECT_EQ("Message", file.message_type(1).name());
+ std::vector<int> field_path;
+ field_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber);
+ field_path.push_back(1);
+ field_path.push_back(DescriptorProto::kFieldFieldNumber);
+ field_path.push_back(0);
+ std::vector<const GeneratedCodeInfo::Annotation*> annotations;
+ atu::FindAnnotationsOnPath(info, "test.proto", field_path, &annotations);
+ EXPECT_TRUE(!annotations.empty());
+ for (const auto* annotation : annotations) {
+ auto substring = atu::GetAnnotationSubstring(pb_h, *annotation);
+ ASSERT_TRUE(substring.has_value());
+ if (*substring == "mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_NONE,
+ annotation->semantic());
+ } else if (*substring == "mutable_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_ALIAS,
+ annotation->semantic());
+ } else if (*substring == "set_encoded_mfield" ||
+ *substring == "clear_mfield") {
+ EXPECT_EQ(GeneratedCodeInfo_Annotation_Semantic_SET,
+ annotation->semantic());
+ }
+ }
+}
} // namespace
} // namespace cpp
} // namespace compiler
diff --git a/src/google/protobuf/compiler/cpp/parse_function_generator.cc b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
index 7e93fcd..864ea45 100644
--- a/src/google/protobuf/compiler/cpp/parse_function_generator.cc
+++ b/src/google/protobuf/compiler/cpp/parse_function_generator.cc
@@ -96,7 +96,8 @@
UseDirectTcParserTable(field, gen_->options_),
GetOptimizeFor(field->file(), gen_->options_) ==
FileOptions::LITE_RUNTIME,
- ShouldSplit(field, gen_->options_)};
+ ShouldSplit(field, gen_->options_),
+ true};
}
private:
@@ -216,17 +217,6 @@
"}\n\n");
}
-static bool NeedsUnknownEnumSupport(const Descriptor* descriptor) {
- for (int i = 0; i < descriptor->field_count(); ++i) {
- auto* field = descriptor->field(i);
- if (field->is_repeated() && field->cpp_type() == field->CPPTYPE_ENUM &&
- !internal::cpp::HasPreservingUnknownEnumSemantics(field)) {
- return true;
- }
- }
- return false;
-}
-
void ParseFunctionGenerator::GenerateTailcallFallbackFunction(
Formatter& format) {
ABSL_CHECK(should_generate_tctable());
@@ -236,21 +226,18 @@
format.Indent();
format("auto* typed_msg = static_cast<$classname$*>(msg);\n");
- // If we need a side channel, generate the check to jump to the generic
- // handler to deal with the side channel data.
- if (NeedsUnknownEnumSupport(descriptor_)) {
- format(
- "if (PROTOBUF_PREDICT_FALSE(\n"
- " _pbi::TcParser::MustFallbackToGeneric(PROTOBUF_TC_PARAM_PASS))) "
- "{\n"
- " PROTOBUF_MUSTTAIL return "
- "::_pbi::TcParser::GenericFallback$1$(PROTOBUF_TC_PARAM_PASS);\n"
- "}\n",
- GetOptimizeFor(descriptor_->file(), options_) ==
- FileOptions::LITE_RUNTIME
- ? "Lite"
- : "");
- }
+ // Generate the check to jump to the generic handler to deal with the side
+ // channel data.
+ format(
+ "if (PROTOBUF_PREDICT_FALSE(\n"
+ " _pbi::TcParser::MustFallbackToGeneric(PROTOBUF_TC_PARAM_PASS))) "
+ "{\n"
+ " PROTOBUF_MUSTTAIL return "
+ "::_pbi::TcParser::GenericFallback$1$(PROTOBUF_TC_PARAM_PASS);\n"
+ "}\n",
+ GetOptimizeFor(descriptor_->file(), options_) == FileOptions::LITE_RUNTIME
+ ? "Lite"
+ : "");
if (num_hasbits_ > 0) {
// Sync hasbits
@@ -494,14 +481,10 @@
} else {
format("0, // no _has_bits_\n");
}
- if (descriptor_->extension_range_count() == 1) {
- format(
- "PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n"
- "$1$, $2$, // extension_range_{low,high}\n",
- descriptor_->extension_range(0)->start,
- descriptor_->extension_range(0)->end);
+ if (descriptor_->extension_range_count() != 0) {
+ format("PROTOBUF_FIELD_OFFSET($classname$, $extensions$),\n");
} else {
- format("0, 0, 0, // no _extensions_\n");
+ format("0, // no _extensions_\n");
}
format("$1$, $2$, // max_field_number, fast_idx_mask\n",
(ordered_fields_.empty() ? 0 : ordered_fields_.back()->number()),
@@ -634,6 +617,29 @@
case TailCallTableInfo::kNumericOffset:
format("{_fl::Offset{$1$}},\n", aux_entry.offset);
break;
+ case TailCallTableInfo::kMapAuxInfo: {
+ auto utf8_check = internal::cpp::GetUtf8CheckMode(
+ aux_entry.field,
+ GetOptimizeFor(aux_entry.field->file(), options_) ==
+ FileOptions::LITE_RUNTIME);
+ auto* map_value = aux_entry.field->message_type()->map_value();
+ const bool validated_enum =
+ map_value->type() == FieldDescriptor::TYPE_ENUM &&
+ !internal::cpp::HasPreservingUnknownEnumSemantics(
+ map_value);
+ format(
+ "{::_pbi::TcParser::GetMapAuxInfo<decltype($classname$("
+ ").$1$)>($2$, $3$, $4$)},\n",
+ FieldMemberName(aux_entry.field, /*split=*/false),
+ utf8_check == internal::cpp::Utf8CheckMode::kStrict,
+ utf8_check == internal::cpp::Utf8CheckMode::kVerify,
+ validated_enum);
+ break;
+ }
+ case TailCallTableInfo::kCreateInArena:
+ format("{::_pbi::TcParser::CreateInArenaStorageCb<$1$>},\n",
+ QualifiedClassName(aux_entry.desc, options_));
+ break;
}
}
}
@@ -1151,7 +1157,7 @@
format.Set("enum_type",
QualifiedClassName(field->enum_type(), options_));
format(
- "$uint32$ val = ::$proto_ns$::internal::ReadVarint32(&ptr);\n"
+ "$int32$ val = ::$proto_ns$::internal::ReadVarint32(&ptr);\n"
"CHK_(ptr);\n");
if (!internal::cpp::HasPreservingUnknownEnumSemantics(field)) {
format(
diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h
index 5960aa1..f3b165a 100644
--- a/src/google/protobuf/compiler/csharp/csharp_helpers.h
+++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h
@@ -140,28 +140,16 @@
descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
}
-inline bool IsProto2(const FileDescriptor* descriptor) {
- return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2;
-}
-
inline bool SupportsPresenceApi(const FieldDescriptor* descriptor) {
// Unlike most languages, we don't generate Has/Clear members for message
// types, because they can always be set to null in C#. They're not really
// needed for oneof fields in proto2 either, as everything can be done via
- // oneof case, but we follow the convention from other languages. Proto3
- // oneof fields never have Has/Clear members - but will also never have
- // the explicit optional keyword either.
- //
- // None of the built-in helpers (descriptor->has_presence() etc) describe
- // quite the behavior we want, so the rules are explicit below.
-
- if (descriptor->is_repeated() ||
- descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
+ // oneof case, but we follow the convention from other languages.
+ if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE) {
return false;
}
- // has_optional_keyword() has more complex rules for proto2, but that
- // doesn't matter given the first part of this condition.
- return IsProto2(descriptor->file()) || descriptor->has_optional_keyword();
+
+ return descriptor->has_presence();
}
inline bool RequiresPresenceBit(const FieldDescriptor* descriptor) {
diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
index a0bd2e4..457dd97 100644
--- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
+++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
@@ -67,18 +67,16 @@
}
void PrimitiveFieldGenerator::GenerateMembers(io::Printer* printer) {
-
// Note: in multiple places, this code assumes that all fields
// that support presence are either nullable, or use a presence field bit.
// Fields which are oneof members are not generated here; they're generated in PrimitiveOneofFieldGenerator below.
// Extensions are not generated here either.
-
- // Proto2 allows different default values to be specified. These are retained
- // via static fields. They don't particularly need to be, but we don't need
- // to change that. In Proto3 the default value we don't generate these
- // fields, just using the literal instead.
- if (IsProto2(descriptor_->file())) {
+ // Explicit presence allows different default values to be specified. These
+ // are retained via static fields. They don't particularly need to be, but we
+ // don't need to change that. Under implicit presence we don't use static
+ // fields for default values and just use the literals instead.
+ if (descriptor_->has_presence()) {
// Note: "private readonly static" isn't as idiomatic as
// "private static readonly", but changing this now would create a lot of
// churn in generated code with near-to-zero benefit.
diff --git a/src/google/protobuf/compiler/java/enum.cc b/src/google/protobuf/compiler/java/enum.cc
index 84c99e6..f64d89e 100644
--- a/src/google/protobuf/compiler/java/enum.cc
+++ b/src/google/protobuf/compiler/java/enum.cc
@@ -119,7 +119,7 @@
printer->Annotate("name", canonical_values_[i]);
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (!descriptor_->is_closed()) {
if (ordinal_is_index) {
printer->Print("${$UNRECOGNIZED$}$(-1),\n", "{", "", "}", "");
} else {
@@ -167,7 +167,7 @@
printer->Print(
"\n"
"public final int getNumber() {\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (!descriptor_->is_closed()) {
if (ordinal_is_index) {
printer->Print(
" if (this == UNRECOGNIZED) {\n"
@@ -251,7 +251,7 @@
printer->Print(
"public final com.google.protobuf.Descriptors.EnumValueDescriptor\n"
" getValueDescriptor() {\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (!descriptor_->is_closed()) {
if (ordinal_is_index) {
printer->Print(
" if (this == UNRECOGNIZED) {\n"
@@ -346,7 +346,7 @@
" \"EnumValueDescriptor is not for this type.\");\n"
" }\n",
"classname", descriptor_->name());
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (!descriptor_->is_closed()) {
printer->Print(
" if (desc.getIndex() == -1) {\n"
" return UNRECOGNIZED;\n"
diff --git a/src/google/protobuf/compiler/java/enum_field.cc b/src/google/protobuf/compiler/java/enum_field.cc
index 59d56d4..935350c 100644
--- a/src/google/protobuf/compiler/java/enum_field.cc
+++ b/src/google/protobuf/compiler/java/enum_field.cc
@@ -120,7 +120,7 @@
(*variables)["get_has_field_bit_from_local"] =
GenerateGetBitFromLocal(builderBitIndex);
- if (SupportUnknownEnumValue(descriptor->file())) {
+ if (SupportUnknownEnumValue(descriptor)) {
variables->insert(
{"unknown", absl::StrCat((*variables)["type"], ".UNRECOGNIZED")});
} else {
@@ -162,12 +162,12 @@
void ImmutableEnumFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$boolean has$capitalized_name$();\n");
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(variables_,
"$deprecation$int get$capitalized_name$Value();\n");
@@ -179,7 +179,7 @@
void ImmutableEnumFieldGenerator::GenerateMembers(io::Printer* printer) const {
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
PrintExtraFieldInfo(variables_, printer);
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override $deprecation$public boolean "
@@ -188,7 +188,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(variables_,
"@java.lang.Override $deprecation$public int "
@@ -210,7 +210,7 @@
void ImmutableEnumFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
printer->Print(variables_, "private int $name$_ = $default_number$;\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override $deprecation$public boolean "
@@ -219,7 +219,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(variables_,
"@java.lang.Override $deprecation$public int "
@@ -286,7 +286,7 @@
" $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
" }\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(
variables_,
"$kt_deprecation$public var $kt_name$Value: kotlin.Int\n"
@@ -305,7 +305,7 @@
" $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
"}\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
/* builder */ false, /* kdoc */ true);
printer->Print(
@@ -333,12 +333,12 @@
void ImmutableEnumFieldGenerator::GenerateMergingCode(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
printer->Print(variables_,
"if (other.has$capitalized_name$()) {\n"
" set$capitalized_name$(other.get$capitalized_name$());\n"
"}\n");
- } else if (SupportUnknownEnumValue(descriptor_->file())) {
+ } else if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(
variables_,
"if (other.$name$_ != $default_number$) {\n"
@@ -362,7 +362,7 @@
void ImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
io::Printer* printer) const {
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(variables_,
"$name$_ = input.readEnum();\n"
"$set_has_field_bit_builder$\n");
@@ -429,7 +429,7 @@
void ImmutableEnumOneofFieldGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
@@ -437,7 +437,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(
variables_,
@@ -464,7 +464,7 @@
void ImmutableEnumOneofFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -473,7 +473,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(
variables_,
@@ -552,7 +552,7 @@
void ImmutableEnumOneofFieldGenerator::GenerateMergingCode(
io::Printer* printer) const {
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(
variables_,
"set$capitalized_name$Value(other.get$capitalized_name$Value());\n");
@@ -564,7 +564,7 @@
void ImmutableEnumOneofFieldGenerator::GenerateBuilderParsingCode(
io::Printer* printer) const {
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
"$set_oneof_case_message$;\n"
@@ -604,7 +604,7 @@
void ImmutableEnumOneofFieldGenerator::GenerateEqualsCode(
io::Printer* printer) const {
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(
variables_,
"if (get$capitalized_name$Value()\n"
@@ -619,7 +619,7 @@
void ImmutableEnumOneofFieldGenerator::GenerateHashCode(
io::Printer* printer) const {
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(variables_,
"hash = (37 * hash) + $constant_name$;\n"
"hash = (53 * hash) + get$capitalized_name$Value();\n");
@@ -661,7 +661,7 @@
WriteFieldAccessorDocComment(printer, descriptor_, LIST_INDEXED_GETTER);
printer->Print(variables_,
"$deprecation$$type$ get$capitalized_name$(int index);\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
printer->Print(variables_,
"$deprecation$java.util.List<java.lang.Integer>\n"
@@ -716,7 +716,7 @@
" return $name$_converter_.convert($name$_.get(index));\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -844,7 +844,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
printer->Print(variables_,
"$deprecation$public java.util.List<java.lang.Integer>\n"
@@ -954,7 +954,7 @@
void RepeatedImmutableEnumFieldGenerator::GenerateBuilderParsingCode(
io::Printer* printer) const {
// Read and store the enum
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(variables_,
"int tmpRaw = input.readEnum();\n"
"ensure$capitalized_name$IsMutable();\n"
diff --git a/src/google/protobuf/compiler/java/enum_field_lite.cc b/src/google/protobuf/compiler/java/enum_field_lite.cc
index fc3cb1f..162311c 100644
--- a/src/google/protobuf/compiler/java/enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/enum_field_lite.cc
@@ -123,12 +123,7 @@
(*variables)["default"], ".getNumber()")});
}
- (*variables)["get_has_field_bit_from_local"] =
- GenerateGetBitFromLocal(builderBitIndex);
- (*variables)["set_has_field_bit_to_local"] =
- GenerateSetBitToLocal(messageBitIndex);
-
- if (SupportUnknownEnumValue(descriptor->file())) {
+ if (SupportUnknownEnumValue(descriptor)) {
variables->insert(
{"unknown", absl::StrCat((*variables)["type"], ".UNRECOGNIZED")});
} else {
@@ -166,13 +161,13 @@
void ImmutableEnumFieldLiteGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$boolean ${$has$capitalized_name$$}$();\n");
printer->Annotate("{", "}", descriptor_);
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(variables_,
"$deprecation$int ${$get$capitalized_name$Value$}$();\n");
@@ -193,7 +188,7 @@
" fieldNumber=$number$,\n"
" type=com.google.protobuf.FieldType.$annotation_field_type$,\n"
" isRequired=$required$)\n");
- if (HasHazzer(descriptor_)) {
+ if (HasHasbit(descriptor_)) {
printer->Print(variables_,
"@com.google.protobuf.ProtoPresenceCheckedField(\n"
" presenceBitsId=$bit_field_id$,\n"
@@ -202,7 +197,7 @@
}
printer->Print(variables_, "private int $name$_;\n");
PrintExtraFieldInfo(variables_, printer);
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -212,7 +207,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(
variables_,
@@ -232,7 +227,7 @@
printer->Annotate("{", "}", descriptor_);
// Generate private setters for the builder to proxy into.
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER);
printer->Print(variables_,
"private void set$capitalized_name$Value(int value) {\n"
@@ -256,7 +251,7 @@
void ImmutableEnumFieldLiteGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -266,7 +261,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(
variables_,
@@ -327,7 +322,7 @@
" $kt_dsl_builder$.${$set$capitalized_name$$}$(value)\n"
" }\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
printer->Print(
variables_,
"$kt_deprecation$public var $kt_name$Value: kotlin.Int\n"
@@ -346,7 +341,7 @@
" $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
"}\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
/* builder */ false, /* kdoc */ true);
printer->Print(
@@ -400,7 +395,7 @@
void ImmutableEnumOneofFieldLiteGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -409,7 +404,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(
variables_,
@@ -436,7 +431,7 @@
printer->Annotate("{", "}", descriptor_);
// Generate private setters for the builder to proxy into.
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER);
printer->Print(variables_,
"private void set$capitalized_name$Value(int value) {\n"
@@ -476,7 +471,7 @@
void ImmutableEnumOneofFieldLiteGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -485,7 +480,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, GETTER);
printer->Print(
variables_,
@@ -571,7 +566,7 @@
variables_,
"$deprecation$$type$ ${$get$capitalized_name$$}$(int index);\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
printer->Print(variables_,
"$deprecation$java.util.List<java.lang.Integer>\n"
@@ -641,7 +636,7 @@
" return result == null ? $unknown$ : result;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -707,7 +702,7 @@
" $name$_ = emptyIntList();\n"
"}\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, SETTER);
printer->Print(variables_,
"private void set$capitalized_name$Value(\n"
@@ -740,7 +735,7 @@
WriteIntToUtf16CharSequence(GetExperimentalJavaFieldType(descriptor_),
output);
printer->Print(variables_, "\"$name$_\",\n");
- if (!SupportUnknownEnumValue(descriptor_->file())) {
+ if (!SupportUnknownEnumValue(descriptor_)) {
PrintEnumVerifierLogic(printer, descriptor_, variables_,
/*var_name=*/"$type$",
/*terminating_string=*/",\n",
@@ -815,7 +810,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(descriptor_)) {
WriteFieldEnumValueAccessorDocComment(printer, descriptor_, LIST_GETTER);
printer->Print(variables_,
"@java.lang.Override\n"
diff --git a/src/google/protobuf/compiler/java/enum_lite.cc b/src/google/protobuf/compiler/java/enum_lite.cc
index 5d10a68..abadc78 100644
--- a/src/google/protobuf/compiler/java/enum_lite.cc
+++ b/src/google/protobuf/compiler/java/enum_lite.cc
@@ -97,7 +97,7 @@
printer->Annotate("name", canonical_values_[i]);
}
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (!descriptor_->is_closed()) {
printer->Print("${$UNRECOGNIZED$}$(-1),\n", "{", "", "}", "");
printer->Annotate("{", "}", descriptor_);
}
@@ -142,7 +142,7 @@
"\n"
"@java.lang.Override\n"
"public final int getNumber() {\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (!descriptor_->is_closed()) {
printer->Print(
" if (this == UNRECOGNIZED) {\n"
" throw new java.lang.IllegalArgumentException(\n"
@@ -235,7 +235,7 @@
" result.append(getClass().getName()).append('@')\n"
" .append(java.lang.Integer.toHexString(\n"
" java.lang.System.identityHashCode(this)));\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (!descriptor_->is_closed()) {
printer->Print(
" if (this != UNRECOGNIZED) {\n"
" result.append(\" number=\").append(getNumber());\n"
diff --git a/src/google/protobuf/compiler/java/file.cc b/src/google/protobuf/compiler/java/file.cc
index e90bbfe..adaf2a6 100644
--- a/src/google/protobuf/compiler/java/file.cc
+++ b/src/google/protobuf/compiler/java/file.cc
@@ -51,6 +51,7 @@
#include "google/protobuf/compiler/java/name_resolver.h"
#include "google/protobuf/compiler/java/service.h"
#include "google/protobuf/compiler/java/shared_code_generator.h"
+#include "google/protobuf/compiler/retention.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/io/printer.h"
@@ -452,8 +453,7 @@
// To find those extensions, we need to parse the data into a dynamic message
// of the FileDescriptor based on the builder-pool, then we can use
// reflections to find all extension fields
- FileDescriptorProto file_proto;
- file_->CopyTo(&file_proto);
+ FileDescriptorProto file_proto = StripSourceRetentionOptions(*file_);
std::string file_data;
file_proto.SerializeToString(&file_data);
FieldDescriptorSet extensions;
@@ -521,8 +521,7 @@
// Check if custom options exist. If any, try to load immutable classes since
// custom options are only represented with immutable messages.
- FileDescriptorProto file_proto;
- file_->CopyTo(&file_proto);
+ FileDescriptorProto file_proto = StripSourceRetentionOptions(*file_);
std::string file_data;
file_proto.SerializeToString(&file_data);
FieldDescriptorSet extensions;
diff --git a/src/google/protobuf/compiler/java/helpers.cc b/src/google/protobuf/compiler/java/helpers.cc
index 8c3784d..eef40ee 100644
--- a/src/google/protobuf/compiler/java/helpers.cc
+++ b/src/google/protobuf/compiler/java/helpers.cc
@@ -932,7 +932,7 @@
}
if (field->is_map()) {
- if (!SupportUnknownEnumValue(field)) {
+ if (!SupportUnknownEnumValue(MapValueField(field))) {
const FieldDescriptor* value = field->message_type()->map_value();
if (GetJavaType(value) == JAVATYPE_ENUM) {
extra_bits |= kMapWithProto2EnumValue;
@@ -977,6 +977,20 @@
}
}
+const FieldDescriptor* MapKeyField(const FieldDescriptor* descriptor) {
+ ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ ABSL_CHECK(message->options().map_entry());
+ return message->map_key();
+}
+
+const FieldDescriptor* MapValueField(const FieldDescriptor* descriptor) {
+ ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
+ const Descriptor* message = descriptor->message_type();
+ ABSL_CHECK(message->options().map_entry());
+ return message->map_value();
+}
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/helpers.h b/src/google/protobuf/compiler/java/helpers.h
index 0ebb3b9..7cd37e0 100644
--- a/src/google/protobuf/compiler/java/helpers.h
+++ b/src/google/protobuf/compiler/java/helpers.h
@@ -354,28 +354,13 @@
// them has a required field. Return true if a required field is found.
bool HasRequiredFields(const Descriptor* descriptor);
-inline bool IsProto2(const FileDescriptor* descriptor) {
- return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO2;
-}
-
inline bool IsRealOneof(const FieldDescriptor* descriptor) {
return descriptor->containing_oneof() &&
!descriptor->containing_oneof()->is_synthetic();
}
-inline bool HasHazzer(const FieldDescriptor* descriptor) {
- return !descriptor->is_repeated() &&
- (descriptor->message_type() || descriptor->has_optional_keyword() ||
- IsProto2(descriptor->file()) || IsRealOneof(descriptor));
-}
-
inline bool HasHasbit(const FieldDescriptor* descriptor) {
- // Note that currently message fields inside oneofs have hasbits. This is
- // surprising, as the oneof case should avoid any need for a hasbit. But if
- // you change this method to remove hasbits for oneofs, a few tests fail.
- // TODO(b/124347790): remove hasbits for oneofs
- return !descriptor->is_repeated() &&
- (descriptor->has_optional_keyword() || IsProto2(descriptor->file()));
+ return internal::cpp::HasHasbit(descriptor);
}
// Whether generate classes expose public PARSER instances.
@@ -387,12 +372,8 @@
// Whether unknown enum values are kept (i.e., not stored in UnknownFieldSet
// but in the message and can be queried using additional getters that return
// ints.
-inline bool SupportUnknownEnumValue(const FileDescriptor* descriptor) {
- return descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
-}
-
inline bool SupportUnknownEnumValue(const FieldDescriptor* field) {
- return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
+ return !field->legacy_enum_field_treated_as_closed();
}
// Check whether a message has repeated fields.
@@ -415,7 +396,7 @@
}
inline bool CheckUtf8(const FieldDescriptor* descriptor) {
- return descriptor->file()->syntax() == FileDescriptor::SYNTAX_PROTO3 ||
+ return descriptor->requires_utf8_validation() ||
descriptor->file()->options().java_string_check_utf8();
}
@@ -448,6 +429,11 @@
// and the first field number that are not in the table part
std::pair<int, int> GetTableDrivenNumberOfEntriesAndLookUpStartFieldNumber(
const FieldDescriptor** fields, int count);
+
+const FieldDescriptor* MapKeyField(const FieldDescriptor* descriptor);
+
+const FieldDescriptor* MapValueField(const FieldDescriptor* descriptor);
+
} // namespace java
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/map_field.cc b/src/google/protobuf/compiler/java/map_field.cc
index 13354c4..041690b 100644
--- a/src/google/protobuf/compiler/java/map_field.cc
+++ b/src/google/protobuf/compiler/java/map_field.cc
@@ -47,20 +47,6 @@
namespace {
-const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
- ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
- const Descriptor* message = descriptor->message_type();
- ABSL_CHECK(message->options().map_entry());
- return message->map_key();
-}
-
-const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
- ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
- const Descriptor* message = descriptor->message_type();
- ABSL_CHECK(message->options().map_entry());
- return message->map_value();
-}
-
std::string TypeName(const FieldDescriptor* field,
ClassNameResolver* name_resolver, bool boxed) {
if (GetJavaType(field) == JAVATYPE_MESSAGE) {
@@ -98,8 +84,8 @@
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
- const FieldDescriptor* key = KeyField(descriptor);
- const FieldDescriptor* value = ValueField(descriptor);
+ const FieldDescriptor* key = MapKeyField(descriptor);
+ const FieldDescriptor* value = MapValueField(descriptor);
const JavaType keyJavaType = GetJavaType(key);
const JavaType valueJavaType = GetJavaType(value);
@@ -147,7 +133,7 @@
{"value_enum_type_pass_through_nullness",
absl::StrCat(pass_through_nullness, (*variables)["value_enum_type"])});
- if (SupportUnknownEnumValue(descriptor->file())) {
+ if (SupportUnknownEnumValue(value)) {
// Map unknown values to a special UNRECOGNIZED value if supported.
variables->insert(
{"unrecognized_value",
@@ -244,7 +230,9 @@
"$deprecation$boolean ${$contains$capitalized_name$$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
if (context_->options().opensource_runtime) {
printer->Print(variables_,
"/**\n"
@@ -275,7 +263,7 @@
"$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(value)) {
printer->Print(
variables_,
"/**\n"
@@ -362,7 +350,7 @@
" }\n"
" return $name$_;\n"
"}\n");
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ if (GetJavaType(MapValueField(descriptor_)) == JAVATYPE_ENUM) {
printer->Print(
variables_,
"private static final\n"
@@ -434,7 +422,8 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
if (context_->options().opensource_runtime) {
printer->Print(
variables_,
@@ -478,7 +467,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(value)) {
if (context_->options().opensource_runtime) {
printer->Print(
variables_,
@@ -585,7 +574,8 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
if (context_->options().opensource_runtime) {
printer->Print(
variables_,
@@ -645,7 +635,7 @@
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(value)) {
printer->Print(
variables_,
"/**\n"
@@ -870,8 +860,8 @@
void ImmutableMapFieldGenerator::GenerateBuilderParsingCode(
io::Printer* printer) const {
- if (!SupportUnknownEnumValue(descriptor_->file()) &&
- GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (!SupportUnknownEnumValue(value) && GetJavaType(value) == JAVATYPE_ENUM) {
printer->Print(
variables_,
"com.google.protobuf.ByteString bytes = input.readBytes();\n"
diff --git a/src/google/protobuf/compiler/java/map_field_lite.cc b/src/google/protobuf/compiler/java/map_field_lite.cc
index ca4091a..8e61a5b 100644
--- a/src/google/protobuf/compiler/java/map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/map_field_lite.cc
@@ -49,20 +49,6 @@
namespace {
-const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
- ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
- const Descriptor* message = descriptor->message_type();
- ABSL_CHECK(message->options().map_entry());
- return message->map_key();
-}
-
-const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
- ABSL_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
- const Descriptor* message = descriptor->message_type();
- ABSL_CHECK(message->options().map_entry());
- return message->map_value();
-}
-
std::string TypeName(const FieldDescriptor* field,
ClassNameResolver* name_resolver, bool boxed) {
if (GetJavaType(field) == JAVATYPE_MESSAGE) {
@@ -100,8 +86,8 @@
ClassNameResolver* name_resolver = context->GetNameResolver();
(*variables)["type"] =
name_resolver->GetImmutableClassName(descriptor->message_type());
- const FieldDescriptor* key = KeyField(descriptor);
- const FieldDescriptor* value = ValueField(descriptor);
+ const FieldDescriptor* key = MapKeyField(descriptor);
+ const FieldDescriptor* value = MapValueField(descriptor);
const JavaType keyJavaType = GetJavaType(key);
const JavaType valueJavaType = GetJavaType(value);
@@ -144,7 +130,7 @@
{"value_enum_type_pass_through_nullness",
absl::StrCat(pass_through_nullness, (*variables)["value_enum_type"])});
- if (SupportUnknownEnumValue(descriptor->file())) {
+ if (SupportUnknownEnumValue(value)) {
// Map unknown values to a special UNRECOGNIZED value if supported.
variables->insert(
{"unrecognized_value",
@@ -217,7 +203,8 @@
"$deprecation$boolean ${$contains$capitalized_name$$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
if (context_->options().opensource_runtime) {
printer->Print(variables_,
"/**\n"
@@ -248,7 +235,7 @@
"$deprecation$$value_enum_type$ ${$get$capitalized_name$OrThrow$}$(\n"
" $key_type$ key);\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(value)) {
printer->Print(
variables_,
"/**\n"
@@ -363,7 +350,9 @@
" return internalGet$capitalized_name$().containsKey(key);\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
printer->Print(
variables_,
"private static final\n"
@@ -432,7 +421,7 @@
" return $name$ValueConverter.doForward(map.get(key));\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(value)) {
printer->Print(
variables_,
"/**\n"
@@ -545,7 +534,7 @@
}
// Generate private setters for the builder to proxy into.
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
@@ -556,7 +545,7 @@
" internalGetMutable$capitalized_name$(),\n"
" $name$ValueConverter);\n"
"}\n");
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(value)) {
WriteFieldDocComment(printer, descriptor_);
printer->Print(
variables_,
@@ -583,9 +572,9 @@
printer->Print(variables_,
"\"$name$_\",\n"
"$default_entry$,\n");
- if (!SupportUnknownEnumValue(descriptor_) &&
- GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
- PrintEnumVerifierLogic(printer, ValueField(descriptor_), variables_,
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (!SupportUnknownEnumValue(value) && GetJavaType(value) == JAVATYPE_ENUM) {
+ PrintEnumVerifierLogic(printer, MapValueField(descriptor_), variables_,
/*var_name=*/"$value_enum_type$",
/*terminating_string=*/",\n",
/*enforce_lite=*/context_->EnforceLite());
@@ -631,7 +620,8 @@
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+ const FieldDescriptor* value = MapValueField(descriptor_);
+ if (GetJavaType(value) == JAVATYPE_ENUM) {
if (context_->options().opensource_runtime) {
printer->Print(
variables_,
@@ -711,7 +701,7 @@
" return this;\n"
"}\n");
printer->Annotate("{", "}", descriptor_);
- if (SupportUnknownEnumValue(descriptor_->file())) {
+ if (SupportUnknownEnumValue(value)) {
printer->Print(
variables_,
"/**\n"
diff --git a/src/google/protobuf/compiler/java/message.cc b/src/google/protobuf/compiler/java/message.cc
index 5d6a446..ff97d5b 100644
--- a/src/google/protobuf/compiler/java/message.cc
+++ b/src/google/protobuf/compiler/java/message.cc
@@ -971,18 +971,6 @@
// ===================================================================
-namespace {
-bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) {
- if (field->is_repeated()) {
- return false;
- }
- if (HasHasbit(field)) {
- return true;
- }
- return GetJavaType(field) == JAVATYPE_MESSAGE && !IsRealOneof(field);
-}
-} // namespace
-
void ImmutableMessageGenerator::GenerateEqualsAndHashCode(
io::Printer* printer) {
printer->Print(
@@ -1011,8 +999,7 @@
const FieldDescriptor* field = descriptor_->field(i);
if (!IsRealOneof(field)) {
const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
- bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
- if (check_has_bits) {
+ if (field->has_presence()) {
printer->Print(
"if (has$name$() != other.has$name$()) return false;\n"
"if (has$name$()) {\n",
@@ -1020,7 +1007,7 @@
printer->Indent();
}
field_generators_.get(field).GenerateEqualsCode(printer);
- if (check_has_bits) {
+ if (field->has_presence()) {
printer->Outdent();
printer->Print("}\n");
}
@@ -1095,13 +1082,12 @@
const FieldDescriptor* field = descriptor_->field(i);
if (!IsRealOneof(field)) {
const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field);
- bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field);
- if (check_has_bits) {
+ if (field->has_presence()) {
printer->Print("if (has$name$()) {\n", "name", info->capitalized_name);
printer->Indent();
}
field_generators_.get(field).GenerateHashCode(printer);
- if (check_has_bits) {
+ if (field->has_presence()) {
printer->Outdent();
printer->Print("}\n");
}
diff --git a/src/google/protobuf/compiler/java/message_lite.cc b/src/google/protobuf/compiler/java/message_lite.cc
index 721a463..b23f0e0 100644
--- a/src/google/protobuf/compiler/java/message_lite.cc
+++ b/src/google/protobuf/compiler/java/message_lite.cc
@@ -507,7 +507,7 @@
std::vector<uint16_t> chars;
int flags = 0;
- if (IsProto2(descriptor_->file())) {
+ if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO2) {
flags |= 0x1;
}
if (descriptor_->options().message_set_wire_format()) {
diff --git a/src/google/protobuf/compiler/java/primitive_field.cc b/src/google/protobuf/compiler/java/primitive_field.cc
index 15a1edb..352499e 100644
--- a/src/google/protobuf/compiler/java/primitive_field.cc
+++ b/src/google/protobuf/compiler/java/primitive_field.cc
@@ -221,7 +221,7 @@
void ImmutablePrimitiveFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$boolean has$capitalized_name$();\n");
@@ -234,7 +234,7 @@
io::Printer* printer) const {
printer->Print(variables_, "private $field_type$ $name$_ = $default$;\n");
PrintExtraFieldInfo(variables_, printer);
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -258,7 +258,7 @@
io::Printer* printer) const {
printer->Print(variables_, "private $field_type$ $name$_ $default_init$;\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -332,7 +332,7 @@
" $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
"}\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
/* builder */ false, /* kdoc */ true);
printer->Print(
@@ -363,7 +363,7 @@
void ImmutablePrimitiveFieldGenerator::GenerateMergingCode(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
printer->Print(variables_,
"if (other.has$capitalized_name$()) {\n"
" set$capitalized_name$(other.get$capitalized_name$());\n"
@@ -527,7 +527,7 @@
void ImmutablePrimitiveOneofFieldGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -550,7 +550,7 @@
void ImmutablePrimitiveOneofFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
diff --git a/src/google/protobuf/compiler/java/primitive_field_lite.cc b/src/google/protobuf/compiler/java/primitive_field_lite.cc
index b7197b8..b494130 100644
--- a/src/google/protobuf/compiler/java/primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/primitive_field_lite.cc
@@ -187,10 +187,6 @@
}
}
- (*variables)["get_has_field_bit_from_local"] =
- GenerateGetBitFromLocal(builderBitIndex);
- (*variables)["set_has_field_bit_to_local"] =
- GenerateSetBitToLocal(messageBitIndex);
// Annotations often use { and } variables to denote ranges.
(*variables)["{"] = "";
(*variables)["}"] = "";
@@ -219,7 +215,7 @@
void ImmutablePrimitiveFieldLiteGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$boolean has$capitalized_name$();\n");
@@ -246,7 +242,7 @@
" fieldNumber=$number$,\n"
" type=com.google.protobuf.FieldType.$annotation_field_type$,\n"
" isRequired=$required$)\n");
- if (HasHazzer(descriptor_)) {
+ if (HasHasbit(descriptor_)) {
printer->Print(variables_,
"@com.google.protobuf.ProtoPresenceCheckedField(\n"
" presenceBitsId=$bit_field_id$,\n"
@@ -255,7 +251,7 @@
}
printer->Print(variables_, "private $field_type$ $name$_;\n");
PrintExtraFieldInfo(variables_, printer);
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -301,7 +297,7 @@
void ImmutablePrimitiveFieldLiteGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -362,7 +358,7 @@
" $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
"}\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
/* builder */ false, /* kdoc */ true);
printer->Print(
@@ -416,7 +412,7 @@
void ImmutablePrimitiveOneofFieldLiteGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -464,7 +460,7 @@
void ImmutablePrimitiveOneofFieldLiteGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
diff --git a/src/google/protobuf/compiler/java/string_field.cc b/src/google/protobuf/compiler/java/string_field.cc
index 0913e0a..77336e0 100644
--- a/src/google/protobuf/compiler/java/string_field.cc
+++ b/src/google/protobuf/compiler/java/string_field.cc
@@ -197,7 +197,7 @@
// repeated fields, the logic is done in LazyStringArrayList.
void ImmutableStringFieldGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$boolean has$capitalized_name$();\n");
@@ -218,7 +218,7 @@
"private volatile java.lang.Object $name$_ = $default$;\n");
PrintExtraFieldInfo(variables_, printer);
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -277,7 +277,7 @@
io::Printer* printer) const {
printer->Print(variables_,
"private java.lang.Object $name$_ $default_init$;\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -395,7 +395,7 @@
" $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
"}\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
/* builder */ false, /* kdoc */ true);
printer->Print(
@@ -423,7 +423,7 @@
void ImmutableStringFieldGenerator::GenerateMergingCode(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
// Allow a slight breach of abstraction here in order to avoid forcing
// all string fields to Strings when copying fields from a Message.
printer->Print(variables_,
@@ -517,7 +517,7 @@
void ImmutableStringOneofFieldGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$public boolean ${$has$capitalized_name$$}$() {\n"
@@ -581,7 +581,7 @@
void ImmutableStringOneofFieldGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
diff --git a/src/google/protobuf/compiler/java/string_field_lite.cc b/src/google/protobuf/compiler/java/string_field_lite.cc
index 274df53..3aecb44 100644
--- a/src/google/protobuf/compiler/java/string_field_lite.cc
+++ b/src/google/protobuf/compiler/java/string_field_lite.cc
@@ -122,10 +122,6 @@
absl::StrCat("!", (*variables)["name"], "_.isEmpty()")});
}
- (*variables)["get_has_field_bit_from_local"] =
- GenerateGetBitFromLocal(builderBitIndex);
- (*variables)["set_has_field_bit_to_local"] =
- GenerateSetBitToLocal(messageBitIndex);
// Annotations often use { and } variables to denote text ranges.
(*variables)["{"] = "";
(*variables)["}"] = "";
@@ -179,7 +175,7 @@
// shouldn't be necessary or used on devices.
void ImmutableStringFieldLiteGenerator::GenerateInterfaceMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"$deprecation$boolean ${$has$capitalized_name$$}$();\n");
@@ -207,7 +203,7 @@
" type=com.google.protobuf.FieldType.$annotation_field_type$,\n"
" isRequired=$required$,\n"
" isEnforceUtf8=$enforce_utf8$)\n");
- if (HasHazzer(descriptor_)) {
+ if (HasHasbit(descriptor_)) {
printer->Print(variables_,
"@com.google.protobuf.ProtoPresenceCheckedField(\n"
" presenceBitsId=$bit_field_id$,\n"
@@ -217,7 +213,7 @@
printer->Print(variables_, "private java.lang.String $name$_;\n");
PrintExtraFieldInfo(variables_, printer);
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -279,7 +275,7 @@
void ImmutableStringFieldLiteGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(
variables_,
@@ -361,7 +357,7 @@
" $kt_dsl_builder$.${$clear$capitalized_name$$}$()\n"
"}\n");
- if (HasHazzer(descriptor_)) {
+ if (descriptor_->has_presence()) {
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER,
/* builder */ false, /* kdoc */ true);
printer->Print(
@@ -408,7 +404,7 @@
void ImmutableStringOneofFieldLiteGenerator::GenerateMembers(
io::Printer* printer) const {
PrintExtraFieldInfo(variables_, printer);
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
@@ -486,7 +482,7 @@
void ImmutableStringOneofFieldLiteGenerator::GenerateBuilderMembers(
io::Printer* printer) const {
- ABSL_DCHECK(HasHazzer(descriptor_));
+ ABSL_DCHECK(descriptor_->has_presence());
WriteFieldAccessorDocComment(printer, descriptor_, HAZZER);
printer->Print(variables_,
"@java.lang.Override\n"
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index ea9adfb..f5a064b 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -39,6 +39,7 @@
#include "google/protobuf/compiler/python/generator.h"
#include "google/protobuf/compiler/python/pyi_generator.h"
#include "google/protobuf/compiler/ruby/ruby_generator.h"
+#include "google/protobuf/compiler/rust/generator.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
@@ -112,6 +113,10 @@
cli.RegisterGenerator("--objc_out", "--objc_opt", &objc_generator,
"Generate Objective-C header and source.");
+ // Rust
+ rust::RustGenerator rust_generator;
+ cli.RegisterGenerator("--rust_out", &rust_generator,
+ "Generate Rust sources.");
return cli.Run(argc, argv);
}
diff --git a/src/google/protobuf/compiler/objectivec/import_writer.cc b/src/google/protobuf/compiler/objectivec/import_writer.cc
index d7ef3b9..ca0718b 100644
--- a/src/google/protobuf/compiler/objectivec/import_writer.cc
+++ b/src/google/protobuf/compiler/objectivec/import_writer.cc
@@ -140,15 +140,11 @@
return;
}
- // Lazy parse any mappings.
- if (need_to_parse_mapping_file_) {
- ParseFrameworkMappings();
- }
+ auto module_name = ModuleForFile(file);
- auto proto_lookup = proto_file_to_framework_name_.find(file->name());
- if (proto_lookup != proto_file_to_framework_name_.end()) {
+ if (!module_name.empty()) {
other_framework_imports_.emplace_back(absl::StrCat(
- proto_lookup->second, "/", FilePathBasename(file), header_extension));
+ module_name, "/", FilePathBasename(file), header_extension));
return;
}
@@ -166,6 +162,23 @@
protobuf_imports_.push_back(header_name);
}
+std::string ImportWriter::ModuleForFile(const FileDescriptor* file) {
+ ABSL_DCHECK(!IsProtobufLibraryBundledProtoFile(file));
+
+ // Lazy parse any mappings.
+ if (need_to_parse_mapping_file_) {
+ ParseFrameworkMappings();
+ }
+
+ auto proto_lookup = proto_file_to_framework_name_.find(file->name());
+
+ if (proto_lookup != proto_file_to_framework_name_.end()) {
+ return proto_lookup->second;
+ }
+
+ return "";
+}
+
void ImportWriter::PrintFileImports(io::Printer* p) const {
if (!other_framework_imports_.empty()) {
for (const auto& header : other_framework_imports_) {
diff --git a/src/google/protobuf/compiler/objectivec/import_writer.h b/src/google/protobuf/compiler/objectivec/import_writer.h
index 9f5e0a0..1c168b1 100644
--- a/src/google/protobuf/compiler/objectivec/import_writer.h
+++ b/src/google/protobuf/compiler/objectivec/import_writer.h
@@ -55,6 +55,9 @@
void AddFile(const FileDescriptor* file, const std::string& header_extension);
void AddRuntimeImport(const std::string& header_name);
+ // This can return an empty string if there is no module for the file. It also
+ // does not handle bundled proto files.
+ std::string ModuleForFile(const FileDescriptor* file);
void PrintFileImports(io::Printer* p) const;
void PrintRuntimeImports(io::Printer* p, bool default_cpp_symbol) const;
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index bc6d390..5e3404e 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
diff --git a/src/google/protobuf/compiler/python/BUILD.bazel b/src/google/protobuf/compiler/python/BUILD.bazel
index de1e06c..90d5d21 100644
--- a/src/google/protobuf/compiler/python/BUILD.bazel
+++ b/src/google/protobuf/compiler/python/BUILD.bazel
@@ -28,6 +28,7 @@
deps = [
"//src/google/protobuf:protobuf_nowkt",
"//src/google/protobuf/compiler:code_generator",
+ "//src/google/protobuf/compiler:retention",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/synchronization",
],
@@ -61,9 +62,12 @@
filegroup(
name = "test_srcs",
- srcs = glob([
- "*_test.cc",
- "*unittest.cc",
- ], allow_empty = True),
+ srcs = glob(
+ [
+ "*_test.cc",
+ "*unittest.cc",
+ ],
+ allow_empty = True,
+ ),
visibility = ["//src/google/protobuf/compiler:__pkg__"],
)
diff --git a/src/google/protobuf/compiler/python/generator.cc b/src/google/protobuf/compiler/python/generator.cc
index 58ffe07..651aaa9 100644
--- a/src/google/protobuf/compiler/python/generator.cc
+++ b/src/google/protobuf/compiler/python/generator.cc
@@ -64,6 +64,7 @@
#include "absl/strings/substitute.h"
#include "google/protobuf/compiler/python/helpers.h"
#include "google/protobuf/compiler/python/pyi_generator.h"
+#include "google/protobuf/compiler/retention.h"
#include "google/protobuf/descriptor.h"
#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/io/printer.h"
@@ -249,8 +250,7 @@
std::string filename = GetFileName(file, ".py");
- FileDescriptorProto fdp;
- file_->CopyTo(&fdp);
+ FileDescriptorProto fdp = StripSourceRetentionOptions(*file_);
fdp.SerializeToString(&file_descriptor_serialized_);
if (!opensource_runtime_ && GeneratingDescriptorProto()) {
@@ -262,9 +262,9 @@
std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
io::Printer printer(output.get(), '$');
printer.Print(
- "from $internal_package$ import descriptor_pb2\n"
- "\n",
- "internal_package", InternalPackage());
+ "from google3.net.google.protobuf.python.internal import "
+ "descriptor_pb2\n"
+ "\n");
// For static checkers, we need to explicitly assign to the symbols we
// publicly export.
@@ -342,7 +342,7 @@
FixAllDescriptorOptions();
// Set serialized_start and serialized_end.
- SetSerializedPbInterval();
+ SetSerializedPbInterval(fdp);
printer_->Outdent();
if (HasGenericServices(file)) {
@@ -373,11 +373,10 @@
printer_->Print("import google3\n");
}
printer_->Print(
- "from $internal_package$ import builder as _builder\n"
- "from $public_package$ import descriptor as _descriptor\n"
- "from $public_package$ import descriptor_pool as _descriptor_pool\n"
- "from $public_package$ import symbol_database as _symbol_database\n",
- "internal_package", InternalPackage(), "public_package", PublicPackage());
+ "from google.protobuf import descriptor as _descriptor\n"
+ "from google.protobuf import descriptor_pool as _descriptor_pool\n"
+ "from google.protobuf import symbol_database as _symbol_database\n"
+ "from google.protobuf.internal import builder as _builder\n");
printer_->Print("# @@protoc_insertion_point(imports)\n\n");
printer_->Print("_sym_db = _symbol_database.Default()\n");
@@ -442,7 +441,8 @@
m["name"] = file_->name();
m["package"] = file_->package();
m["syntax"] = StringifySyntax(file_->syntax());
- m["options"] = OptionsValue(file_->options().SerializeAsString());
+ m["options"] = OptionsValue(
+ StripLocalSourceRetentionOptions(*file_).SerializeAsString());
m["serialized_descriptor"] = absl::CHexEscape(file_descriptor_serialized_);
if (GeneratingDescriptorProto()) {
printer_->Print("if _descriptor._USE_C_DESCRIPTORS == False:\n");
@@ -528,7 +528,8 @@
" create_key=_descriptor._internal_create_key,\n"
" values=[\n";
std::string options_string;
- enum_descriptor.options().SerializeToString(&options_string);
+ StripLocalSourceRetentionOptions(enum_descriptor)
+ .SerializeToString(&options_string);
printer_->Print(m, enum_descriptor_template);
printer_->Indent();
printer_->Indent();
@@ -681,7 +682,8 @@
printer_->Outdent();
printer_->Print("],\n");
std::string options_string;
- message_descriptor.options().SerializeToString(&options_string);
+ StripLocalSourceRetentionOptions(message_descriptor)
+ .SerializeToString(&options_string);
printer_->Print(
"serialized_options=$options_value$,\n"
"is_extendable=$extendable$,\n"
@@ -708,7 +710,8 @@
m["name"] = desc->name();
m["full_name"] = desc->full_name();
m["index"] = absl::StrCat(desc->index());
- options_string = OptionsValue(desc->options().SerializeAsString());
+ options_string = OptionsValue(
+ StripLocalSourceRetentionOptions(*desc).SerializeAsString());
if (options_string == "None") {
m["serialized_options"] = "";
} else {
@@ -1050,7 +1053,8 @@
// TODO(robinson): Fix up EnumValueDescriptor "type" fields.
// More circular references. ::sigh::
std::string options_string;
- descriptor.options().SerializeToString(&options_string);
+ StripLocalSourceRetentionOptions(descriptor)
+ .SerializeToString(&options_string);
absl::flat_hash_map<absl::string_view, std::string> m;
m["name"] = descriptor.name();
m["index"] = absl::StrCat(descriptor.index());
@@ -1078,7 +1082,7 @@
void Generator::PrintFieldDescriptor(const FieldDescriptor& field,
bool is_extension) const {
std::string options_string;
- field.options().SerializeToString(&options_string);
+ StripLocalSourceRetentionOptions(field).SerializeToString(&options_string);
absl::flat_hash_map<absl::string_view, std::string> m;
m["name"] = field.name();
m["full_name"] = field.full_name();
@@ -1206,31 +1210,17 @@
return name;
}
-std::string Generator::PublicPackage() const {
- return opensource_runtime_ ? "google.protobuf"
- : "google3.net.google.protobuf.python.public";
-}
-
-std::string Generator::InternalPackage() const {
- return opensource_runtime_ ? "google.protobuf.internal"
- : "google3.net.google.protobuf.python.internal";
-}
-
-// Prints standard constructor arguments serialized_start and serialized_end.
+// Prints descriptor offsets _serialized_start and _serialized_end.
// Args:
-// descriptor: The cpp descriptor to have a serialized reference.
-// proto: A proto
+// descriptor_proto: The descriptor proto to have a serialized reference.
// Example printer output:
-// serialized_start=41,
-// serialized_end=43,
-//
-template <typename DescriptorT, typename DescriptorProtoT>
-void Generator::PrintSerializedPbInterval(const DescriptorT& descriptor,
- DescriptorProtoT& proto,
- absl::string_view name) const {
- descriptor.CopyTo(&proto);
+// _globals['_MYMESSAGE']._serialized_start=47
+// _globals['_MYMESSAGE']._serialized_end=76
+template <typename DescriptorProtoT>
+void Generator::PrintSerializedPbInterval(
+ const DescriptorProtoT& descriptor_proto, absl::string_view name) const {
std::string sp;
- proto.SerializeToString(&sp);
+ descriptor_proto.SerializeToString(&sp);
int offset = file_descriptor_serialized_.find(sp);
ABSL_CHECK_GE(offset, 0);
@@ -1254,43 +1244,47 @@
}
} // namespace
-void Generator::SetSerializedPbInterval() const {
+// Generates the start and end offsets for each entity in the serialized file
+// descriptor. The file argument must exactly match what was serialized into
+// file_descriptor_serialized_, and should already have had any
+// source-retention options stripped out. This is important because we need an
+// exact byte-for-byte match so that we can successfully find the correct
+// offsets in the serialized descriptors.
+void Generator::SetSerializedPbInterval(const FileDescriptorProto& file) const {
// Top level enums.
for (int i = 0; i < file_->enum_type_count(); ++i) {
- EnumDescriptorProto proto;
const EnumDescriptor& descriptor = *file_->enum_type(i);
- PrintSerializedPbInterval(descriptor, proto,
+ PrintSerializedPbInterval(file.enum_type(i),
ModuleLevelDescriptorName(descriptor));
}
// Messages.
for (int i = 0; i < file_->message_type_count(); ++i) {
- SetMessagePbInterval(*file_->message_type(i));
+ SetMessagePbInterval(file.message_type(i), *file_->message_type(i));
}
// Services.
for (int i = 0; i < file_->service_count(); ++i) {
- ServiceDescriptorProto proto;
const ServiceDescriptor& service = *file_->service(i);
- PrintSerializedPbInterval(service, proto,
+ PrintSerializedPbInterval(file.service(i),
ModuleLevelServiceDescriptorName(service));
}
}
-void Generator::SetMessagePbInterval(const Descriptor& descriptor) const {
- DescriptorProto message_proto;
- PrintSerializedPbInterval(descriptor, message_proto,
+void Generator::SetMessagePbInterval(const DescriptorProto& message_proto,
+ const Descriptor& descriptor) const {
+ PrintSerializedPbInterval(message_proto,
ModuleLevelDescriptorName(descriptor));
// Nested messages.
for (int i = 0; i < descriptor.nested_type_count(); ++i) {
- SetMessagePbInterval(*descriptor.nested_type(i));
+ SetMessagePbInterval(message_proto.nested_type(i),
+ *descriptor.nested_type(i));
}
for (int i = 0; i < descriptor.enum_type_count(); ++i) {
- EnumDescriptorProto proto;
const EnumDescriptor& enum_des = *descriptor.enum_type(i);
- PrintSerializedPbInterval(enum_des, proto,
+ PrintSerializedPbInterval(message_proto.enum_type(i),
ModuleLevelDescriptorName(enum_des));
}
}
@@ -1298,7 +1292,8 @@
// Prints expressions that set the options field of all descriptors.
void Generator::FixAllDescriptorOptions() const {
// Prints an expression that sets the file descriptor's options.
- std::string file_options = OptionsValue(file_->options().SerializeAsString());
+ std::string file_options = OptionsValue(
+ StripLocalSourceRetentionOptions(*file_).SerializeAsString());
if (file_options != "None") {
PrintDescriptorOptionsFixingCode(kDescriptorKey, file_options, printer_);
} else {
@@ -1326,7 +1321,8 @@
}
void Generator::FixOptionsForOneof(const OneofDescriptor& oneof) const {
- std::string oneof_options = OptionsValue(oneof.options().SerializeAsString());
+ std::string oneof_options =
+ OptionsValue(StripLocalSourceRetentionOptions(oneof).SerializeAsString());
if (oneof_options != "None") {
std::string oneof_name = absl::Substitute(
"$0.$1['$2']", ModuleLevelDescriptorName(*oneof.containing_type()),
@@ -1339,15 +1335,15 @@
// value descriptors.
void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const {
std::string descriptor_name = ModuleLevelDescriptorName(enum_descriptor);
- std::string enum_options =
- OptionsValue(enum_descriptor.options().SerializeAsString());
+ std::string enum_options = OptionsValue(
+ StripLocalSourceRetentionOptions(enum_descriptor).SerializeAsString());
if (enum_options != "None") {
PrintDescriptorOptionsFixingCode(descriptor_name, enum_options, printer_);
}
for (int i = 0; i < enum_descriptor.value_count(); ++i) {
const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(i);
- std::string value_options =
- OptionsValue(value_descriptor.options().SerializeAsString());
+ std::string value_options = OptionsValue(
+ StripLocalSourceRetentionOptions(value_descriptor).SerializeAsString());
if (value_options != "None") {
PrintDescriptorOptionsFixingCode(
absl::StrFormat("%s.values_by_name[\"%s\"]", descriptor_name.c_str(),
@@ -1363,8 +1359,8 @@
const ServiceDescriptor& service_descriptor) const {
std::string descriptor_name =
ModuleLevelServiceDescriptorName(service_descriptor);
- std::string service_options =
- OptionsValue(service_descriptor.options().SerializeAsString());
+ std::string service_options = OptionsValue(
+ StripLocalSourceRetentionOptions(service_descriptor).SerializeAsString());
if (service_options != "None") {
PrintDescriptorOptionsFixingCode(descriptor_name, service_options,
printer_);
@@ -1372,8 +1368,8 @@
for (int i = 0; i < service_descriptor.method_count(); ++i) {
const MethodDescriptor* method = service_descriptor.method(i);
- std::string method_options =
- OptionsValue(method->options().SerializeAsString());
+ std::string method_options = OptionsValue(
+ StripLocalSourceRetentionOptions(*method).SerializeAsString());
if (method_options != "None") {
std::string method_name = absl::StrCat(
descriptor_name, ".methods_by_name['", method->name(), "']");
@@ -1385,7 +1381,8 @@
// Prints expressions that set the options for field descriptors (including
// extensions).
void Generator::FixOptionsForField(const FieldDescriptor& field) const {
- std::string field_options = OptionsValue(field.options().SerializeAsString());
+ std::string field_options =
+ OptionsValue(StripLocalSourceRetentionOptions(field).SerializeAsString());
if (field_options != "None") {
std::string field_name;
if (field.is_extension()) {
@@ -1430,8 +1427,8 @@
FixOptionsForField(field);
}
// Message option for this message.
- std::string message_options =
- OptionsValue(descriptor.options().SerializeAsString());
+ std::string message_options = OptionsValue(
+ StripLocalSourceRetentionOptions(descriptor).SerializeAsString());
if (message_options != "None") {
std::string descriptor_name = ModuleLevelDescriptorName(descriptor);
PrintDescriptorOptionsFixingCode(descriptor_name, message_options,
diff --git a/src/google/protobuf/compiler/python/generator.h b/src/google/protobuf/compiler/python/generator.h
index c5182c4..65c16f5 100644
--- a/src/google/protobuf/compiler/python/generator.h
+++ b/src/google/protobuf/compiler/python/generator.h
@@ -41,6 +41,7 @@
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "google/protobuf/compiler/code_generator.h"
+#include "google/protobuf/descriptor.pb.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
@@ -163,12 +164,9 @@
std::string ModuleLevelMessageName(const Descriptor& descriptor) const;
std::string ModuleLevelServiceDescriptorName(
const ServiceDescriptor& descriptor) const;
- std::string PublicPackage() const;
- std::string InternalPackage() const;
- template <typename DescriptorT, typename DescriptorProtoT>
- void PrintSerializedPbInterval(const DescriptorT& descriptor,
- DescriptorProtoT& proto,
+ template <typename DescriptorProtoT>
+ void PrintSerializedPbInterval(const DescriptorProtoT& descriptor_proto,
absl::string_view name) const;
void FixAllDescriptorOptions() const;
@@ -178,8 +176,9 @@
void FixOptionsForService(const ServiceDescriptor& descriptor) const;
void FixOptionsForMessage(const Descriptor& descriptor) const;
- void SetSerializedPbInterval() const;
- void SetMessagePbInterval(const Descriptor& descriptor) const;
+ void SetSerializedPbInterval(const FileDescriptorProto& file) const;
+ void SetMessagePbInterval(const DescriptorProto& message_proto,
+ const Descriptor& descriptor) const;
void CopyPublicDependenciesAliases(absl::string_view copy_from,
const FileDescriptor* file) const;
diff --git a/src/google/protobuf/compiler/retention.cc b/src/google/protobuf/compiler/retention.cc
index 087af72..04937a4 100644
--- a/src/google/protobuf/compiler/retention.cc
+++ b/src/google/protobuf/compiler/retention.cc
@@ -42,6 +42,7 @@
namespace compiler {
namespace {
+
// Recursively strips any options with source retention from the message.
void StripMessage(Message& m) {
const Reflection* reflection = m.GetReflection();
@@ -62,43 +63,107 @@
}
}
}
+
+// Converts the descriptor to a dynamic message if necessary, and then strips
+// out all source-retention options.
+//
+// The options message may have custom options set on it, and these would
+// ordinarily appear as unknown fields since they are not linked into protoc.
+// Using a dynamic message allows us to see these custom options. To convert
+// back and forth between the generated type and the dynamic message, we have
+// to serialize one and parse that into the other.
+void ConvertToDynamicMessageAndStripOptions(Message& m,
+ const DescriptorPool& pool) {
+ // We need to look up the descriptor in the pool so that we can get a
+ // descriptor which knows about any custom options that were used in the
+ // .proto file.
+ const Descriptor* descriptor = pool.FindMessageTypeByName(m.GetTypeName());
+
+ if (descriptor == nullptr) {
+ // If the pool does not contain the descriptor, then this proto file does
+ // not transitively depend on descriptor.proto, in which case we know there
+ // are no custom options to worry about.
+ StripMessage(m);
+ } else {
+ DynamicMessageFactory factory;
+ std::unique_ptr<Message> dynamic_message(
+ factory.GetPrototype(descriptor)->New());
+ std::string serialized;
+ ABSL_CHECK(m.SerializeToString(&serialized));
+ ABSL_CHECK(dynamic_message->ParseFromString(serialized));
+ StripMessage(*dynamic_message);
+ ABSL_CHECK(dynamic_message->SerializeToString(&serialized));
+ ABSL_CHECK(m.ParseFromString(serialized));
+ }
+}
+
+// Returns a const reference to the descriptor pool associated with the given
+// descriptor.
+template <typename DescriptorType>
+const google::protobuf::DescriptorPool& GetPool(const DescriptorType& descriptor) {
+ return *descriptor.file()->pool();
+}
+
+// Specialization for FileDescriptor.
+const google::protobuf::DescriptorPool& GetPool(const FileDescriptor& descriptor) {
+ return *descriptor.pool();
+}
+
+// Returns the options associated with the given descriptor, with all
+// source-retention options stripped out.
+template <typename DescriptorType>
+auto StripLocalOptions(const DescriptorType& descriptor) {
+ auto options = descriptor.options();
+ ConvertToDynamicMessageAndStripOptions(options, GetPool(descriptor));
+ return options;
+}
+
} // namespace
FileDescriptorProto StripSourceRetentionOptions(const FileDescriptor& file) {
FileDescriptorProto file_proto;
file.CopyTo(&file_proto);
-
- // We need to look up the descriptor in file.pool() so that we can get a
- // descriptor which knows about any custom options that were used in the
- // .proto file.
- const Descriptor* descriptor =
- file.pool()->FindMessageTypeByName(FileDescriptorProto().GetTypeName());
-
- if (descriptor == nullptr) {
- // If the pool does not contain the descriptor for FileDescriptorProto,
- // then this proto file does not transitively depend on descriptor.proto,
- // in which case we know there are no custom options to worry about.
- StripMessage(file_proto);
- } else {
- // The options message may have custom options set on it, and these would
- // ordinarily appear as unknown fields since they are not linked into
- // protoc. Using a dynamic message allows us to see these custom options.
- // To convert back and forth between the generated type and the dynamic
- // message, we have to serialize one and parse that into the other.
- DynamicMessageFactory factory;
- std::unique_ptr<Message> dynamic_message(
- factory.GetPrototype(descriptor)->New());
- std::string serialized;
- ABSL_CHECK(file_proto.SerializeToString(&serialized));
- ABSL_CHECK(dynamic_message->ParseFromString(serialized));
- StripMessage(*dynamic_message);
- ABSL_CHECK(dynamic_message->SerializeToString(&serialized));
- ABSL_CHECK(file_proto.ParseFromString(serialized));
- }
-
+ ConvertToDynamicMessageAndStripOptions(file_proto, *file.pool());
return file_proto;
}
+EnumOptions StripLocalSourceRetentionOptions(const EnumDescriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
+EnumValueOptions StripLocalSourceRetentionOptions(
+ const EnumValueDescriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
+FieldOptions StripLocalSourceRetentionOptions(
+ const FieldDescriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
+FileOptions StripLocalSourceRetentionOptions(const FileDescriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
+MessageOptions StripLocalSourceRetentionOptions(const Descriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
+MethodOptions StripLocalSourceRetentionOptions(
+ const MethodDescriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
+OneofOptions StripLocalSourceRetentionOptions(
+ const OneofDescriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
+ServiceOptions StripLocalSourceRetentionOptions(
+ const ServiceDescriptor& descriptor) {
+ return StripLocalOptions(descriptor);
+}
+
} // namespace compiler
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/compiler/retention.h b/src/google/protobuf/compiler/retention.h
index b97ab1e..0579b06 100644
--- a/src/google/protobuf/compiler/retention.h
+++ b/src/google/protobuf/compiler/retention.h
@@ -46,6 +46,28 @@
PROTOC_EXPORT FileDescriptorProto
StripSourceRetentionOptions(const FileDescriptor& file);
+// The following functions take a descriptor and strip all source-retention
+// options from just the local entity (e.g. message, enum, field). Most code
+// generators should not need these functions, but they are sometimes useful if
+// you need to strip the options on a single entity rather than handling the
+// entire file at once.
+PROTOC_EXPORT EnumOptions
+StripLocalSourceRetentionOptions(const EnumDescriptor& descriptor);
+PROTOC_EXPORT EnumValueOptions
+StripLocalSourceRetentionOptions(const EnumValueDescriptor& descriptor);
+PROTOC_EXPORT FieldOptions
+StripLocalSourceRetentionOptions(const FieldDescriptor& descriptor);
+PROTOC_EXPORT FileOptions
+StripLocalSourceRetentionOptions(const FileDescriptor& descriptor);
+PROTOC_EXPORT MessageOptions
+StripLocalSourceRetentionOptions(const Descriptor& descriptor);
+PROTOC_EXPORT MethodOptions
+StripLocalSourceRetentionOptions(const MethodDescriptor& descriptor);
+PROTOC_EXPORT OneofOptions
+StripLocalSourceRetentionOptions(const OneofDescriptor& descriptor);
+PROTOC_EXPORT ServiceOptions
+StripLocalSourceRetentionOptions(const ServiceDescriptor& descriptor);
+
} // namespace compiler
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc
index fbeb2ef..5013fbd 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc
@@ -79,8 +79,7 @@
}
std::string LabelForField(const FieldDescriptor* field) {
- if (field->has_optional_keyword() &&
- field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) {
+ if (field->has_optional_keyword() && field->containing_oneof() != nullptr) {
return "proto3_optional";
}
switch (field->label()) {
@@ -520,11 +519,9 @@
printer->Print("\n");
}
- // TODO: Remove this when ruby supports extensions for proto2 syntax.
- if (file->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
- file->extension_count() > 0) {
- ABSL_LOG(WARNING)
- << "Extensions are not yet supported for proto2 .proto files.";
+ // TODO: Remove this when ruby supports extensions.
+ if (file->extension_count() > 0) {
+ ABSL_LOG(WARNING) << "Extensions are not yet supported in Ruby.";
}
bool use_raw_descriptor = file->name() == "google/protobuf/descriptor.proto";
@@ -560,9 +557,7 @@
const std::string& parameter,
GeneratorContext* generator_context,
std::string* error) const {
-
- if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 &&
- file->syntax() != FileDescriptor::SYNTAX_PROTO2) {
+ if (file->syntax() == FileDescriptor::SYNTAX_UNKNOWN) {
*error = "Invalid or unsupported proto syntax";
return false;
}
diff --git a/src/google/protobuf/compiler/rust/BUILD.bazel b/src/google/protobuf/compiler/rust/BUILD.bazel
index 2a26dd5..faddffc 100644
--- a/src/google/protobuf/compiler/rust/BUILD.bazel
+++ b/src/google/protobuf/compiler/rust/BUILD.bazel
@@ -7,6 +7,7 @@
cc_library(
name = "rust",
+ srcs = ["generator.cc"],
hdrs = ["generator.h"],
copts = COPTS,
include_prefix = "google/protobuf/compiler/rust",
diff --git a/src/google/protobuf/compiler/rust/generator.cc b/src/google/protobuf/compiler/rust/generator.cc
new file mode 100644
index 0000000..08a14eb
--- /dev/null
+++ b/src/google/protobuf/compiler/rust/generator.cc
@@ -0,0 +1,123 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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 "google/protobuf/compiler/rust/generator.h"
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/algorithm/container.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_replace.h"
+#include "absl/strings/string_view.h"
+#include "google/protobuf/descriptor.h"
+#include "google/protobuf/io/printer.h"
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace rust {
+
+bool ExperimentalRustGeneratorEnabled(
+ const std::vector<std::pair<std::string, std::string>>& options) {
+ static constexpr std::pair<absl::string_view, absl::string_view> kMagicValue =
+ {"experimental-codegen", "enabled"};
+
+ return absl::c_any_of(
+ options, [](std::pair<absl::string_view, absl::string_view> pair) {
+ return pair == kMagicValue;
+ });
+}
+
+std::string get_crate_name(const FileDescriptor* dependency) {
+ absl::string_view path = dependency->name();
+ auto basename = path.substr(path.rfind('/') + 1);
+ return absl::StrReplaceAll(basename, {
+ {".", "_"},
+ {"-", "_"},
+ });
+}
+
+bool RustGenerator::Generate(const FileDescriptor* file,
+ const std::string& parameter,
+ GeneratorContext* generator_context,
+ std::string* error) const {
+ std::vector<std::pair<std::string, std::string>> options;
+ ParseGeneratorParameter(parameter, &options);
+
+ if (!ExperimentalRustGeneratorEnabled(options)) {
+ *error =
+ "The Rust codegen is highly experimental. Future versions will break "
+ "existing code. Use at your own risk. You can opt-in by passing "
+ "'experimental-codegen=enabled' to '--rust_out'.";
+ return false;
+ }
+
+ auto basename = StripProto(file->name());
+ auto outfile = absl::WrapUnique(
+ generator_context->Open(absl::StrCat(basename, ".pb.rs")));
+
+ google::protobuf::io::Printer p(outfile.get());
+ // TODO(b/270138878): Remove `do_nothing` import once we have real logic. This
+ // is there only to smoke test rustc actions in rust_proto_library.
+ p.Emit(R"rs(
+#[allow(unused_imports)]
+ use protobuf::do_nothing;
+ )rs");
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ // TODO(b/270138878): Implement real logic
+ p.Emit({{"Msg", file->message_type(i)->name()}}, R"rs(
+ pub struct $Msg$ {}
+ )rs");
+ }
+ // TODO(b/270124215): Delete the following "placeholder impl" of `import
+ // public`. Also make sure to figure out how to map FileDescriptor#name to
+ // Rust crate names (currently Bazel labels).
+ for (int i = 0; i < file->public_dependency_count(); ++i) {
+ const FileDescriptor* dep = file->public_dependency(i);
+ std::string crate_name = get_crate_name(dep);
+ for (int j = 0; j < dep->message_type_count(); ++j) {
+ // TODO(b/270138878): Implement real logic
+ p.Emit(
+ {{"crate", crate_name}, {"type_name", dep->message_type(j)->name()}},
+ R"rs(
+ pub use $crate$::$type_name$;
+ )rs");
+ }
+ }
+
+ return true;
+}
+
+} // namespace rust
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/rust/generator.h b/src/google/protobuf/compiler/rust/generator.h
index a01c6ae..5b3d0c4 100644
--- a/src/google/protobuf/compiler/rust/generator.h
+++ b/src/google/protobuf/compiler/rust/generator.h
@@ -33,7 +33,6 @@
#include <string>
-#include "absl/log/absl_check.h"
#include "google/protobuf/compiler/code_generator.h"
// Must be included last.
@@ -44,7 +43,8 @@
namespace compiler {
namespace rust {
-class RustGenerator final : public google::protobuf::compiler::CodeGenerator {
+class PROTOC_EXPORT RustGenerator final
+ : public google::protobuf::compiler::CodeGenerator {
public:
RustGenerator() = default;
RustGenerator(const RustGenerator&) = delete;
@@ -53,10 +53,7 @@
bool Generate(const FileDescriptor* file, const std::string& parameter,
GeneratorContext* generator_context,
- std::string* error) const override {
- ABSL_CHECK(false) << "not yet implemented";
- return false;
- }
+ std::string* error) const override;
uint64_t GetSupportedFeatures() const override {
return FEATURE_PROTO3_OPTIONAL;
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 9e3a49d..efcd86e 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -5375,6 +5375,7 @@
} // namespace
+
void DescriptorBuilder::BuildMessage(const DescriptorProto& proto,
const Descriptor* parent,
Descriptor* result,
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index f6359e8..f1d2032 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -65,6 +65,7 @@
#include "google/protobuf/port.h"
#include "absl/base/attributes.h"
#include "absl/base/call_once.h"
+#include "absl/container/btree_map.h"
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
@@ -84,6 +85,7 @@
namespace google {
namespace protobuf {
+
// Defined in this file.
class Descriptor;
class FieldDescriptor;
@@ -117,7 +119,6 @@
class FileOptions;
class UninterpretedOption;
class SourceCodeInfo;
-class ExtensionMetadata;
// Defined in message.h
class Message;
@@ -768,6 +769,25 @@
// parse.
bool requires_utf8_validation() const;
+ // Determines if the given enum field is treated as closed based on legacy
+ // non-conformant behavior.
+ //
+ // Conformant behavior determines closedness based on the enum and
+ // can be queried using EnumDescriptor::is_closed().
+ //
+ // Some runtimes currently have a quirk where non-closed enums are
+ // treated as closed when used as the type of fields defined in a
+ // `syntax = proto2;` file. This quirk is not present in all runtimes; as of
+ // writing, we know that:
+ //
+ // - C++, Java, and C++-based Python share this quirk.
+ // - UPB and UPB-based Python do not.
+ // - PHP and Ruby treat all enums as open regardless of declaration.
+ //
+ // Care should be taken when using this function to respect the target
+ // runtime's enum handling quirks.
+ bool legacy_enum_field_treated_as_closed() const;
+
// Index of this field within the message's field array, or the file or
// extension scope's extensions array.
int index() const;
@@ -1902,7 +1922,7 @@
// in a .proto file.
enum ErrorLocation {
NAME, // the symbol name, or the package name for files
- NUMBER, // field or extension range number
+ NUMBER, // field, extension range or extension decl number
TYPE, // field type
EXTENDEE, // field extendee
DEFAULT_VALUE, // field default value
@@ -2442,6 +2462,11 @@
file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
+inline bool FieldDescriptor::legacy_enum_field_treated_as_closed() const {
+ return type() == TYPE_ENUM &&
+ file()->syntax() == FileDescriptor::SYNTAX_PROTO2;
+}
+
// To save space, index() is computed by looking at the descriptor's position
// in the parent's array of children.
inline int FieldDescriptor::index() const {
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index ce8901e..88e9833 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -4252,7 +4252,7 @@
// optional .google.protobuf.FieldDescriptorProto.Label label = 4;
case 4:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 32)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label_IsValid(static_cast<int>(val)))) {
_internal_set_label(static_cast<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Label>(val));
@@ -4266,7 +4266,7 @@
// optional .google.protobuf.FieldDescriptorProto.Type type = 5;
case 5:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 40)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type_IsValid(static_cast<int>(val)))) {
_internal_set_type(static_cast<::PROTOBUF_NAMESPACE_ID::FieldDescriptorProto_Type>(val));
@@ -7026,7 +7026,7 @@
// optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED];
case 9:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 72)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode_IsValid(static_cast<int>(val)))) {
_internal_set_optimize_for(static_cast<::PROTOBUF_NAMESPACE_ID::FileOptions_OptimizeMode>(val));
@@ -8297,7 +8297,7 @@
// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
case 1:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 8)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_CType_IsValid(static_cast<int>(val)))) {
_internal_set_ctype(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_CType>(val));
@@ -8341,7 +8341,7 @@
// optional .google.protobuf.FieldOptions.JSType jstype = 6 [default = JS_NORMAL];
case 6:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 48)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType_IsValid(static_cast<int>(val)))) {
_internal_set_jstype(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_JSType>(val));
@@ -8385,7 +8385,7 @@
// optional .google.protobuf.FieldOptions.OptionRetention retention = 17;
case 17:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 136)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_OptionRetention_IsValid(static_cast<int>(val)))) {
_internal_set_retention(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_OptionRetention>(val));
@@ -8399,7 +8399,7 @@
// optional .google.protobuf.FieldOptions.OptionTargetType target = 18;
case 18:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 144)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::FieldOptions_OptionTargetType_IsValid(static_cast<int>(val)))) {
_internal_set_target(static_cast<::PROTOBUF_NAMESPACE_ID::FieldOptions_OptionTargetType>(val));
@@ -9877,7 +9877,7 @@
// optional .google.protobuf.MethodOptions.IdempotencyLevel idempotency_level = 34 [default = IDEMPOTENCY_UNKNOWN];
case 34:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 16)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel_IsValid(static_cast<int>(val)))) {
_internal_set_idempotency_level(static_cast<::PROTOBUF_NAMESPACE_ID::MethodOptions_IdempotencyLevel>(val));
@@ -11581,7 +11581,7 @@
// optional .google.protobuf.GeneratedCodeInfo.Annotation.Semantic semantic = 5;
case 5:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 40)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
if (PROTOBUF_PREDICT_TRUE(::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic_IsValid(static_cast<int>(val)))) {
_internal_set_semantic(static_cast<::PROTOBUF_NAMESPACE_ID::GeneratedCodeInfo_Annotation_Semantic>(val));
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index ff15dcb..455021a 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index 80eebfe..c4c7e93 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -1120,6 +1120,66 @@
EXPECT_FALSE(bar3->requires_utf8_validation());
}
+TEST_F(DescriptorTest, EnumFieldTreatedAsClosed) {
+ // Make an open enum definition.
+ FileDescriptorProto open_enum_file;
+ open_enum_file.set_name("open_enum.proto");
+ open_enum_file.set_syntax("proto3");
+ AddEnumValue(AddEnum(&open_enum_file, "TestEnumOpen"), "TestEnumOpen_VALUE0",
+ 0);
+
+ const EnumDescriptor* open_enum =
+ pool_.BuildFile(open_enum_file)->enum_type(0);
+ EXPECT_FALSE(open_enum->is_closed());
+
+ // Create a message that treats enum fields as closed.
+ FileDescriptorProto closed_file;
+ closed_file.set_name("closed_enum_field.proto");
+ closed_file.add_dependency("open_enum.proto");
+ closed_file.add_dependency("foo.proto");
+
+ DescriptorProto* message = AddMessage(&closed_file, "TestClosedEnumField");
+ AddField(message, "int_field", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(message, "open_enum", 2, FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_ENUM)
+ ->set_type_name("TestEnumOpen");
+ AddField(message, "closed_enum", 3, FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_ENUM)
+ ->set_type_name("TestEnum");
+ const Descriptor* closed_message =
+ pool_.BuildFile(closed_file)->message_type(0);
+
+ EXPECT_FALSE(closed_message->FindFieldByName("int_field")
+ ->legacy_enum_field_treated_as_closed());
+ EXPECT_TRUE(closed_message->FindFieldByName("closed_enum")
+ ->legacy_enum_field_treated_as_closed());
+ EXPECT_TRUE(closed_message->FindFieldByName("open_enum")
+ ->legacy_enum_field_treated_as_closed());
+}
+
+TEST_F(DescriptorTest, EnumFieldTreatedAsOpen) {
+ FileDescriptorProto open_enum_file;
+ open_enum_file.set_name("open_enum.proto");
+ open_enum_file.set_syntax("proto3");
+ AddEnumValue(AddEnum(&open_enum_file, "TestEnumOpen"), "TestEnumOpen_VALUE0",
+ 0);
+ DescriptorProto* message = AddMessage(&open_enum_file, "TestOpenEnumField");
+ AddField(message, "int_field", 1, FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(message, "open_enum", 2, FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_ENUM)
+ ->set_type_name("TestEnumOpen");
+ const FileDescriptor* open_enum_file_desc = pool_.BuildFile(open_enum_file);
+ const Descriptor* open_message = open_enum_file_desc->message_type(0);
+ const EnumDescriptor* open_enum = open_enum_file_desc->enum_type(0);
+ EXPECT_FALSE(open_enum->is_closed());
+ EXPECT_FALSE(open_message->FindFieldByName("int_field")
+ ->legacy_enum_field_treated_as_closed());
+ EXPECT_FALSE(open_message->FindFieldByName("open_enum")
+ ->legacy_enum_field_treated_as_closed());
+}
+
TEST_F(DescriptorTest, IsMap) {
EXPECT_TRUE(map_->is_map());
EXPECT_FALSE(baz_->is_map());
@@ -3979,6 +4039,16 @@
BuildFileInTestPool(DescriptorProto::descriptor()->file());
}
+ void BuildDescriptorMessagesInTestPoolWithErrors(
+ absl::string_view expected_errors) {
+ FileDescriptorProto file_proto;
+ DescriptorProto::descriptor()->file()->CopyTo(&file_proto);
+ MockErrorCollector error_collector;
+ EXPECT_TRUE(pool_.BuildFileCollectingErrors(file_proto, &error_collector) ==
+ nullptr);
+ EXPECT_EQ(error_collector.text_, expected_errors);
+ }
+
DescriptorPool pool_;
};
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 6609a9e..7121b53 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -96,6 +96,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 16bacbf..c17b5ea 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -96,6 +96,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index d5ef61a..2178b1e 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -62,6 +62,7 @@
#error "You cannot SWIG proto headers"
#endif
+
namespace google {
namespace protobuf {
class Arena;
@@ -75,6 +76,7 @@
class UnknownFieldSet; // unknown_field_set.h
namespace internal {
class FieldSkipper; // wire_format_lite.h
+class WireFormat;
enum class LazyVerifyOption;
} // namespace internal
} // namespace protobuf
@@ -514,6 +516,7 @@
friend class RepeatedEnumTypeTraits;
friend class google::protobuf::Reflection;
+ friend class google::protobuf::internal::WireFormat;
const int32_t& GetRefInt32(int number, const int32_t& default_value) const;
const int64_t& GetRefInt64(int number, const int64_t& default_value) const;
@@ -560,6 +563,8 @@
virtual bool IsInitialized(const MessageLite* prototype,
Arena* arena) const = 0;
+ virtual bool IsEagerSerializeSafe(const MessageLite* prototype,
+ Arena* arena) const = 0;
PROTOBUF_DEPRECATED_MSG("Please use ByteSizeLong() instead")
virtual int ByteSize() const { return internal::ToIntSize(ByteSizeLong()); }
@@ -571,9 +576,9 @@
virtual void MergeFromMessage(const MessageLite& msg, Arena* arena) = 0;
virtual void Clear() = 0;
- virtual const char* _InternalParse(const Message& prototype, Arena* arena,
- LazyVerifyOption option, const char* ptr,
- ParseContext* ctx) = 0;
+ virtual const char* _InternalParse(const MessageLite& prototype,
+ Arena* arena, LazyVerifyOption option,
+ const char* ptr, ParseContext* ctx) = 0;
virtual uint8_t* WriteMessageToArray(
const MessageLite* prototype, int number, uint8_t* target,
io::EpsCopyOutputStream* stream) const = 0;
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index cdc4cc3..27b5dd6 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -285,7 +285,7 @@
} else {
output->type = extension->type();
output->is_repeated = extension->is_repeated();
- output->is_packed = extension->options().packed();
+ output->is_packed = extension->is_packed();
output->descriptor = extension;
if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
output->message_info.prototype =
diff --git a/src/google/protobuf/extension_set_inl.h b/src/google/protobuf/extension_set_inl.h
index bd01e95..4554d95 100644
--- a/src/google/protobuf/extension_set_inl.h
+++ b/src/google/protobuf/extension_set_inl.h
@@ -141,14 +141,14 @@
#undef HANDLE_FIXED_TYPE
case WireFormatLite::TYPE_ENUM: {
- uint64_t val;
- ptr = VarintParse(ptr, &val);
+ uint64_t tmp;
+ ptr = VarintParse(ptr, &tmp);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
- int value = val;
+ int value = tmp;
if (!extension.enum_validity_check.func(
extension.enum_validity_check.arg, value)) {
- WriteVarint(number, val, metadata->mutable_unknown_fields<T>());
+ WriteVarint(number, value, metadata->mutable_unknown_fields<T>());
} else if (extension.is_repeated) {
AddEnum(number, WireFormatLite::TYPE_ENUM, extension.is_packed, value,
extension.descriptor);
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index ccd1c9b..7f6799f 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -57,7 +57,6 @@
// Must be included last.
#include "google/protobuf/port_def.inc"
-
namespace google {
namespace protobuf {
namespace internal {
@@ -1359,6 +1358,54 @@
}
}
+TEST(ExtensionSetTest, Proto3PackedDynamicExtensions) {
+ // Regression test for b/271121265. This test case verifies that
+ // packed-by-default repeated custom options in proto3 are correctly
+ // serialized in packed form when dynamic extensions are used.
+
+ // Create a custom option in proto3 and load this into an overlay
+ // DescriptorPool with a DynamicMessageFactory.
+ google::protobuf::FileDescriptorProto file_descriptor_proto;
+ file_descriptor_proto.set_syntax("proto3");
+ file_descriptor_proto.set_name(
+ "third_party/protobuf/unittest_proto3_packed_extension.proto");
+ file_descriptor_proto.set_package("proto3_unittest");
+ file_descriptor_proto.add_dependency(
+ DescriptorProto::descriptor()->file()->name());
+ FieldDescriptorProto* extension = file_descriptor_proto.add_extension();
+ extension->set_name("repeated_int32_option");
+ extension->set_extendee(MessageOptions().GetTypeName());
+ extension->set_number(50009);
+ extension->set_label(FieldDescriptorProto::LABEL_REPEATED);
+ extension->set_type(FieldDescriptorProto::TYPE_INT32);
+ extension->set_json_name("repeatedInt32Option");
+ google::protobuf::DescriptorPool pool(DescriptorPool::generated_pool());
+ ASSERT_NE(pool.BuildFile(file_descriptor_proto), nullptr);
+ DynamicMessageFactory factory;
+ factory.SetDelegateToGeneratedFactory(true);
+
+ // Create a serialized MessageOptions proto equivalent to:
+ // [proto3_unittest.repeated_int32_option]: 1
+ UnknownFieldSet unknown_fields;
+ unknown_fields.AddVarint(50009, 1);
+ std::string serialized_options;
+ ASSERT_TRUE(unknown_fields.SerializeToString(&serialized_options));
+
+ // Parse the MessageOptions using our custom extension registry.
+ io::ArrayInputStream input_stream(serialized_options.data(),
+ serialized_options.size());
+ io::CodedInputStream coded_stream(&input_stream);
+ coded_stream.SetExtensionRegistry(&pool, &factory);
+ MessageOptions message_options;
+ ASSERT_TRUE(message_options.ParseFromCodedStream(&coded_stream));
+
+ // Finally, serialize the proto again and verify that the repeated option has
+ // been correctly serialized in packed form.
+ std::string reserialized_options;
+ ASSERT_TRUE(message_options.SerializeToString(&reserialized_options));
+ EXPECT_EQ(reserialized_options, "\xca\xb5\x18\x01\x01");
+}
+
TEST(ExtensionSetTest, BoolExtension) {
unittest::TestAllExtensions msg;
uint8_t wire_bytes[2] = {13 * 8, 42 /* out of bounds payload for bool */};
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index 7b7833e..ddb95f5 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -96,6 +96,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 80a3eb5..6fab214 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -1540,10 +1540,6 @@
static_cast<uint32_t>(1)) != 0;
}
-bool CreateUnknownEnumValues(const FileDescriptor* file) {
- return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
-}
-
void CheckInOrder(const FieldDescriptor* field, uint32_t* last) {
*last = *last <= static_cast<uint32_t>(field->number())
? static_cast<uint32_t>(field->number())
@@ -1760,6 +1756,7 @@
}
+
void Reflection::SetString(Message* message, const FieldDescriptor* field,
std::string value) const {
USAGE_CHECK_ALL(SetString, SINGULAR, STRING);
@@ -2485,7 +2482,7 @@
}
bool Reflection::SupportsUnknownEnumValues() const {
- return CreateUnknownEnumValues(descriptor_->file());
+ return descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO3;
}
// ===================================================================
@@ -2957,124 +2954,16 @@
}
static internal::TailCallParseFunc GetFastParseFunction(
- absl::string_view name) {
- // This list must be synchronized with TcParser.
- // Missing entries are replaced with MiniParse in opt mode to avoid runtime
- // failures. It check-fails in debug mode.
+ const internal::TailCallTableInfo::FastFieldInfo& field_info) {
+#define PROTOBUF_TC_PARSE_FUNCTION_X(value) \
+ {"::_pbi::TcParser::" #value, internal::TcParser::value},
static const auto* const map =
new absl::flat_hash_map<absl::string_view, internal::TailCallParseFunc>{
- {"::_pbi::TcParser::FastF32S1", internal::TcParser::FastF32S1},
- {"::_pbi::TcParser::FastF32S2", internal::TcParser::FastF32S2},
- {"::_pbi::TcParser::FastF32R1", internal::TcParser::FastF32R1},
- {"::_pbi::TcParser::FastF32R2", internal::TcParser::FastF32R2},
- {"::_pbi::TcParser::FastF32P1", internal::TcParser::FastF32P1},
- {"::_pbi::TcParser::FastF32P2", internal::TcParser::FastF32P2},
- {"::_pbi::TcParser::FastF64S1", internal::TcParser::FastF64S1},
- {"::_pbi::TcParser::FastF64S2", internal::TcParser::FastF64S2},
- {"::_pbi::TcParser::FastF64R1", internal::TcParser::FastF64R1},
- {"::_pbi::TcParser::FastF64R2", internal::TcParser::FastF64R2},
- {"::_pbi::TcParser::FastF64P1", internal::TcParser::FastF64P1},
- {"::_pbi::TcParser::FastF64P2", internal::TcParser::FastF64P2},
- {"::_pbi::TcParser::FastV8S1", internal::TcParser::FastV8S1},
- {"::_pbi::TcParser::FastV8S2", internal::TcParser::FastV8S2},
- {"::_pbi::TcParser::FastV8R1", internal::TcParser::FastV8R1},
- {"::_pbi::TcParser::FastV8R2", internal::TcParser::FastV8R2},
- {"::_pbi::TcParser::FastV8P1", internal::TcParser::FastV8P1},
- {"::_pbi::TcParser::FastV8P2", internal::TcParser::FastV8P2},
- {"::_pbi::TcParser::FastV32S1", internal::TcParser::FastV32S1},
- {"::_pbi::TcParser::FastV32S2", internal::TcParser::FastV32S2},
- {"::_pbi::TcParser::FastV32R1", internal::TcParser::FastV32R1},
- {"::_pbi::TcParser::FastV32R2", internal::TcParser::FastV32R2},
- {"::_pbi::TcParser::FastV32P1", internal::TcParser::FastV32P1},
- {"::_pbi::TcParser::FastV32P2", internal::TcParser::FastV32P2},
- {"::_pbi::TcParser::FastV64S1", internal::TcParser::FastV64S1},
- {"::_pbi::TcParser::FastV64S2", internal::TcParser::FastV64S2},
- {"::_pbi::TcParser::FastV64R1", internal::TcParser::FastV64R1},
- {"::_pbi::TcParser::FastV64R2", internal::TcParser::FastV64R2},
- {"::_pbi::TcParser::FastV64P1", internal::TcParser::FastV64P1},
- {"::_pbi::TcParser::FastV64P2", internal::TcParser::FastV64P2},
- {"::_pbi::TcParser::FastZ32S1", internal::TcParser::FastZ32S1},
- {"::_pbi::TcParser::FastZ32S2", internal::TcParser::FastZ32S2},
- {"::_pbi::TcParser::FastZ32R1", internal::TcParser::FastZ32R1},
- {"::_pbi::TcParser::FastZ32R2", internal::TcParser::FastZ32R2},
- {"::_pbi::TcParser::FastZ32P1", internal::TcParser::FastZ32P1},
- {"::_pbi::TcParser::FastZ32P2", internal::TcParser::FastZ32P2},
- {"::_pbi::TcParser::FastZ64S1", internal::TcParser::FastZ64S1},
- {"::_pbi::TcParser::FastZ64S2", internal::TcParser::FastZ64S2},
- {"::_pbi::TcParser::FastZ64R1", internal::TcParser::FastZ64R1},
- {"::_pbi::TcParser::FastZ64R2", internal::TcParser::FastZ64R2},
- {"::_pbi::TcParser::FastZ64P1", internal::TcParser::FastZ64P1},
- {"::_pbi::TcParser::FastZ64P2", internal::TcParser::FastZ64P2},
- {"::_pbi::TcParser::FastErS1", internal::TcParser::FastErS1},
- {"::_pbi::TcParser::FastErS2", internal::TcParser::FastErS2},
- {"::_pbi::TcParser::FastErR1", internal::TcParser::FastErR1},
- {"::_pbi::TcParser::FastErR2", internal::TcParser::FastErR2},
- {"::_pbi::TcParser::FastErP1", internal::TcParser::FastErP1},
- {"::_pbi::TcParser::FastErP2", internal::TcParser::FastErP2},
- {"::_pbi::TcParser::FastEr0S1", internal::TcParser::FastEr0S1},
- {"::_pbi::TcParser::FastEr0S2", internal::TcParser::FastEr0S2},
- {"::_pbi::TcParser::FastEr0R1", internal::TcParser::FastEr0R1},
- {"::_pbi::TcParser::FastEr0R2", internal::TcParser::FastEr0R2},
- {"::_pbi::TcParser::FastEr0P1", internal::TcParser::FastEr0P1},
- {"::_pbi::TcParser::FastEr0P2", internal::TcParser::FastEr0P2},
- {"::_pbi::TcParser::FastEr1S1", internal::TcParser::FastEr1S1},
- {"::_pbi::TcParser::FastEr1S2", internal::TcParser::FastEr1S2},
- {"::_pbi::TcParser::FastEr1R1", internal::TcParser::FastEr1R1},
- {"::_pbi::TcParser::FastEr1R2", internal::TcParser::FastEr1R2},
- {"::_pbi::TcParser::FastEr1P1", internal::TcParser::FastEr1P1},
- {"::_pbi::TcParser::FastEr1P2", internal::TcParser::FastEr1P2},
- {"::_pbi::TcParser::FastEvS1", internal::TcParser::FastEvS1},
- {"::_pbi::TcParser::FastEvS2", internal::TcParser::FastEvS2},
- {"::_pbi::TcParser::FastEvR1", internal::TcParser::FastEvR1},
- {"::_pbi::TcParser::FastEvR2", internal::TcParser::FastEvR2},
- {"::_pbi::TcParser::FastEvP1", internal::TcParser::FastEvP1},
- {"::_pbi::TcParser::FastEvP2", internal::TcParser::FastEvP2},
- {"::_pbi::TcParser::FastBS1", internal::TcParser::FastBS1},
- {"::_pbi::TcParser::FastBS2", internal::TcParser::FastBS2},
- {"::_pbi::TcParser::FastBR1", internal::TcParser::FastBR1},
- {"::_pbi::TcParser::FastBR2", internal::TcParser::FastBR2},
- {"::_pbi::TcParser::FastSS1", internal::TcParser::FastSS1},
- {"::_pbi::TcParser::FastSS2", internal::TcParser::FastSS2},
- {"::_pbi::TcParser::FastSR1", internal::TcParser::FastSR1},
- {"::_pbi::TcParser::FastSR2", internal::TcParser::FastSR2},
- {"::_pbi::TcParser::FastUS1", internal::TcParser::FastUS1},
- {"::_pbi::TcParser::FastUS2", internal::TcParser::FastUS2},
- {"::_pbi::TcParser::FastUR1", internal::TcParser::FastUR1},
- {"::_pbi::TcParser::FastUR2", internal::TcParser::FastUR2},
- {"::_pbi::TcParser::FastBiS1", internal::TcParser::FastBiS1},
- {"::_pbi::TcParser::FastBiS2", internal::TcParser::FastBiS2},
- {"::_pbi::TcParser::FastSiS1", internal::TcParser::FastSiS1},
- {"::_pbi::TcParser::FastSiS2", internal::TcParser::FastSiS2},
- {"::_pbi::TcParser::FastUiS1", internal::TcParser::FastUiS1},
- {"::_pbi::TcParser::FastUiS2", internal::TcParser::FastUiS2},
- {"::_pbi::TcParser::FastBcS1", internal::TcParser::FastBcS1},
- {"::_pbi::TcParser::FastBcS2", internal::TcParser::FastBcS2},
- {"::_pbi::TcParser::FastScS1", internal::TcParser::FastScS1},
- {"::_pbi::TcParser::FastScS2", internal::TcParser::FastScS2},
- {"::_pbi::TcParser::FastUcS1", internal::TcParser::FastUcS1},
- {"::_pbi::TcParser::FastUcS2", internal::TcParser::FastUcS2},
- {"::_pbi::TcParser::FastMdS1", internal::TcParser::FastMdS1},
- {"::_pbi::TcParser::FastMdS2", internal::TcParser::FastMdS2},
- {"::_pbi::TcParser::FastGdS1", internal::TcParser::FastGdS1},
- {"::_pbi::TcParser::FastGdS2", internal::TcParser::FastGdS2},
- {"::_pbi::TcParser::FastMtS1", internal::TcParser::FastMtS1},
- {"::_pbi::TcParser::FastMtS2", internal::TcParser::FastMtS2},
- {"::_pbi::TcParser::FastGtS1", internal::TcParser::FastGtS1},
- {"::_pbi::TcParser::FastGtS2", internal::TcParser::FastGtS2},
- {"::_pbi::TcParser::FastMdR1", internal::TcParser::FastMdR1},
- {"::_pbi::TcParser::FastMdR2", internal::TcParser::FastMdR2},
- {"::_pbi::TcParser::FastGdR1", internal::TcParser::FastGdR1},
- {"::_pbi::TcParser::FastGdR2", internal::TcParser::FastGdR2},
- {"::_pbi::TcParser::FastMtR1", internal::TcParser::FastMtR1},
- {"::_pbi::TcParser::FastMtR2", internal::TcParser::FastMtR2},
- {"::_pbi::TcParser::FastGtR1", internal::TcParser::FastGtR1},
- {"::_pbi::TcParser::FastGtR2", internal::TcParser::FastGtR2},
- {"::_pbi::TcParser::FastEndG1", internal::TcParser::FastEndG1},
- {"::_pbi::TcParser::FastEndG2", internal::TcParser::FastEndG2},
- };
- auto it = map->find(name);
+ PROTOBUF_TC_PARSE_FUNCTION_LIST};
+#undef PROTOBUF_TC_PARSE_FUNCTION_X
+ auto it = map->find(field_info.func_name);
if (it == map->end()) {
- ABSL_DLOG(FATAL) << "Failed to find function: " << name;
+ ABSL_DLOG(FATAL) << "Failed to find function: " << field_info.func_name;
// Let's not crash in opt, just in case.
// MiniParse is always a valid parser.
return &internal::TcParser::MiniParse;
@@ -3092,9 +2981,9 @@
// We use `operator new` here because the destruction will be done with
// `operator delete` unconditionally.
void* p = ::operator new(sizeof(Table));
- auto* full_table = ::new (p) Table{
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, schema_.default_instance_, nullptr},
- {{{&internal::TcParser::ReflectionParseLoop, {}}}}};
+ auto* full_table = ::new (p)
+ Table{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, schema_.default_instance_, nullptr},
+ {{{&internal::TcParser::ReflectionParseLoop, {}}}}};
ABSL_DCHECK_EQ(static_cast<void*>(&full_table->header),
static_cast<void*>(full_table));
return &full_table->header;
@@ -3110,7 +2999,7 @@
*fast_entries++ = {internal::TcParser::MiniParse, {}};
} else {
// No field, but still a special entry.
- *fast_entries++ = {GetFastParseFunction(fast_field.func_name),
+ *fast_entries++ = {GetFastParseFunction(fast_field),
{fast_field.coded_tag, fast_field.nonfield_info}};
}
} else if (fast_field.func_name.find("TcParser::FastEv") !=
@@ -3121,7 +3010,7 @@
*fast_entries++ = {internal::TcParser::MiniParse, {}};
} else {
*fast_entries++ = {
- GetFastParseFunction(fast_field.func_name),
+ GetFastParseFunction(fast_field),
{fast_field.coded_tag, fast_field.hasbit_idx, fast_field.aux_idx,
static_cast<uint16_t>(schema_.GetFieldOffset(fast_field.field))}};
}
@@ -3197,8 +3086,16 @@
break;
case internal::TailCallTableInfo::kSubTable:
case internal::TailCallTableInfo::kSubMessageWeak:
+ case internal::TailCallTableInfo::kCreateInArena:
ABSL_LOG(FATAL) << "Not supported";
break;
+ case internal::TailCallTableInfo::kMapAuxInfo:
+ // Default constructed info, which causes MpMap to call the fallback.
+ // DynamicMessage uses DynamicMapField, which uses variant keys and
+ // values. TcParser does not support them yet, so mark the field as
+ // unsupported to fallback to reflection.
+ field_aux++->map_info = internal::MapAuxInfo{};
+ break;
case internal::TailCallTableInfo::kSubMessage:
field_aux++->message_default_p =
GetDefaultMessageInstance(aux_entry.field);
@@ -3251,18 +3148,21 @@
explicit ReflectionOptionProvider(const Reflection& ref) : ref_(ref) {}
internal::TailCallTableInfo::PerFieldOptions GetForField(
const FieldDescriptor* field) const final {
- return {ref_.IsLazyField(field), //
- ref_.IsInlined(field), //
+ return {
+ ref_.IsLazyField(field), //
+ ref_.IsInlined(field), //
- // Only LITE can be implicitly weak.
- /* is_implicitly_weak */ false,
+ // Only LITE can be implicitly weak.
+ /* is_implicitly_weak */ false,
- // We could change this to use direct table.
- // Might be easier to do when all messages support TDP.
- /* use_direct_tcparser_table */ false,
+ // We could change this to use direct table.
+ // Might be easier to do when all messages support TDP.
+ /* use_direct_tcparser_table */ false,
- /* is_lite */ false, //
- ref_.schema_.IsSplit(field)};
+ /* is_lite */ false, //
+ ref_.schema_.IsSplit(field), //
+ /* uses_codegen */ false //
+ };
}
private:
@@ -3292,14 +3192,19 @@
void* p = ::operator new(byte_size);
auto* res = ::new (p) TcParseTableBase{
static_cast<uint16_t>(schema_.HasHasbits() ? schema_.HasBitsOffset() : 0),
- // extensions handled through reflection.
- 0, 0, 0,
+ schema_.HasExtensionSet()
+ ? static_cast<uint16_t>(schema_.GetExtensionSetOffset())
+ : uint16_t{0},
static_cast<uint32_t>(fields.empty() ? 0 : fields.back()->number()),
- static_cast<uint8_t>((fast_entries_count - 1) << 3), lookup_table_offset,
- table_info.num_to_entry_table.skipmap32, field_entry_offset,
+ static_cast<uint8_t>((fast_entries_count - 1) << 3),
+ lookup_table_offset,
+ table_info.num_to_entry_table.skipmap32,
+ field_entry_offset,
static_cast<uint16_t>(fields.size()),
- static_cast<uint16_t>(table_info.aux_entries.size()), aux_offset,
- schema_.default_instance_, &internal::TcParser::ReflectionFallback};
+ static_cast<uint16_t>(table_info.aux_entries.size()),
+ aux_offset,
+ schema_.default_instance_,
+ &internal::TcParser::ReflectionFallback};
// Now copy the rest of the payloads
PopulateTcParseFastEntries(table_info, res->fast_entry(0));
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index f707cf5..3de242c 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -64,7 +64,6 @@
// Must be included last.
#include "google/protobuf/port_def.inc"
-
namespace google {
namespace protobuf {
diff --git a/src/google/protobuf/generated_message_tctable_decl.h b/src/google/protobuf/generated_message_tctable_decl.h
index dd4845b..f9affbe 100644
--- a/src/google/protobuf/generated_message_tctable_decl.h
+++ b/src/google/protobuf/generated_message_tctable_decl.h
@@ -54,6 +54,7 @@
// Additional information about this field:
struct TcFieldData {
constexpr TcFieldData() : data(0) {}
+ explicit constexpr TcFieldData(uint64_t data) : data(data) {}
// Fast table entry constructor:
constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t aux_idx,
@@ -63,6 +64,24 @@
uint64_t{hasbit_idx} << 16 | //
uint64_t{coded_tag}) {}
+ // Constructor to create an explicit 'uninitialized' instance.
+ // This constructor can be used to pass an uninitialized `data` value to a
+ // table driven parser function that does not use `data`. The purpose of this
+ // is that it allows the compiler to reallocate and re-purpose the register
+ // that is currently holding its value for other data. This reduces register
+ // allocations inside the highly optimized varint parsing functions.
+ //
+ // Applications not using `data` use the `PROTOBUF_TC_PARAM_NO_DATA_DECL`
+ // macro to declare the standard input arguments with no name for the `data`
+ // argument. Callers then use the `PROTOBUF_TC_PARAM_NO_DATA_PASS` macro.
+ //
+ // Example:
+ // if (ptr == nullptr) {
+ // PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ // }
+ struct DefaultInit {};
+ TcFieldData(DefaultInit) {} // NOLINT(google-explicit-constructor)
+
// Fields used in fast table parsing:
//
// Bit:
@@ -122,7 +141,9 @@
uint32_t tag() const { return static_cast<uint32_t>(data); }
uint32_t entry_offset() const { return static_cast<uint32_t>(data >> 32); }
- uint64_t data;
+ union {
+ uint64_t data;
+ };
};
struct TcParseTableBase;
@@ -144,13 +165,119 @@
struct FieldAuxDefaultMessage {};
+// Small type card used by mini parse to handle map entries.
+// Map key/values are very limited, so we can encode the whole thing in a single
+// byte.
+class MapTypeCard {
+ public:
+ enum CppType { kBool, k32, k64, kString, kMessage };
+ MapTypeCard() = default;
+ constexpr MapTypeCard(WireFormatLite::WireType wiretype, CppType cpp_type,
+ bool is_zigzag_utf8)
+ : data_(
+ static_cast<uint8_t>((static_cast<uint8_t>(wiretype) << 0) |
+ (static_cast<uint8_t>(cpp_type) << 3) |
+ (static_cast<uint8_t>(is_zigzag_utf8) << 6))) {
+ }
+
+ WireFormatLite::WireType wiretype() const {
+ return static_cast<WireFormatLite::WireType>((data_ >> 0) & 0x7);
+ }
+
+ CppType cpp_type() const { return static_cast<CppType>((data_ >> 3) & 0x7); }
+
+ bool is_zigzag() const {
+ ABSL_DCHECK(wiretype() == WireFormatLite::WIRETYPE_VARINT);
+ ABSL_DCHECK(cpp_type() == CppType::k32 || cpp_type() == CppType::k64);
+ return is_zigzag_utf8();
+ }
+ bool is_utf8() const {
+ ABSL_DCHECK(wiretype() == WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
+ ABSL_DCHECK(cpp_type() == CppType::kString);
+ return is_zigzag_utf8();
+ }
+
+ private:
+ bool is_zigzag_utf8() const { return static_cast<bool>((data_ >> 6) & 0x1); }
+ uint8_t data_;
+};
+static_assert(sizeof(MapTypeCard) == sizeof(uint8_t), "");
+
+// Make the map entry type card for a specified field type.
+constexpr MapTypeCard MakeMapTypeCard(WireFormatLite::FieldType type) {
+ switch (type) {
+ case WireFormatLite::TYPE_FLOAT:
+ case WireFormatLite::TYPE_FIXED32:
+ case WireFormatLite::TYPE_SFIXED32:
+ return {WireFormatLite::WIRETYPE_FIXED32, MapTypeCard::k32, false};
+
+ case WireFormatLite::TYPE_DOUBLE:
+ case WireFormatLite::TYPE_FIXED64:
+ case WireFormatLite::TYPE_SFIXED64:
+ return {WireFormatLite::WIRETYPE_FIXED64, MapTypeCard::k64, false};
+
+ case WireFormatLite::TYPE_BOOL:
+ return {WireFormatLite::WIRETYPE_VARINT, MapTypeCard::kBool, false};
+
+ case WireFormatLite::TYPE_ENUM:
+ // Enum validation is handled via `value_is_validated_enum` below.
+ case WireFormatLite::TYPE_INT32:
+ case WireFormatLite::TYPE_UINT32:
+ return {WireFormatLite::WIRETYPE_VARINT, MapTypeCard::k32, false};
+
+ case WireFormatLite::TYPE_INT64:
+ case WireFormatLite::TYPE_UINT64:
+ return {WireFormatLite::WIRETYPE_VARINT, MapTypeCard::k64, false};
+
+ case WireFormatLite::TYPE_SINT32:
+ return {WireFormatLite::WIRETYPE_VARINT, MapTypeCard::k32, true};
+ case WireFormatLite::TYPE_SINT64:
+ return {WireFormatLite::WIRETYPE_VARINT, MapTypeCard::k64, true};
+
+ case WireFormatLite::TYPE_STRING:
+ return {WireFormatLite::WIRETYPE_LENGTH_DELIMITED, MapTypeCard::kString,
+ true};
+ case WireFormatLite::TYPE_BYTES:
+ return {WireFormatLite::WIRETYPE_LENGTH_DELIMITED, MapTypeCard::kString,
+ false};
+
+ case WireFormatLite::TYPE_MESSAGE:
+ return {WireFormatLite::WIRETYPE_LENGTH_DELIMITED, MapTypeCard::kMessage,
+ false};
+
+ default:
+ PROTOBUF_ASSUME(false);
+ }
+}
+
+enum class MapNodeSizeInfoT : uint32_t;
+
+// Aux entry for map fields.
+struct MapAuxInfo {
+ MapTypeCard key_type_card;
+ MapTypeCard value_type_card;
+ // When off, we fall back to table->fallback to handle the parse. An example
+ // of this is for DynamicMessage.
+ uint8_t is_supported : 1;
+ // Determines if we are using LITE or the full runtime. When using the full
+ // runtime we have to synchronize with reflection before accessing the map.
+ uint8_t use_lite : 1;
+ // If true UTF8 errors cause the parsing to fail.
+ uint8_t fail_on_utf8_failure : 1;
+ // If true UTF8 errors are logged, but they are accepted.
+ uint8_t log_debug_utf8_failure : 1;
+ // If true the next aux contains the enum validator.
+ uint8_t value_is_validated_enum : 1;
+ // Size information derived from the actual node type.
+ MapNodeSizeInfoT node_size_info;
+};
+static_assert(sizeof(MapAuxInfo) <= 8, "");
+
// Base class for message-level table with info for the tail-call parser.
struct alignas(uint64_t) TcParseTableBase {
// Common attributes for message layout:
uint16_t has_bits_offset;
uint16_t extension_offset;
- uint32_t extension_range_low;
- uint32_t extension_range_high;
uint32_t max_field_number;
uint8_t fast_idx_mask;
uint16_t lookup_table_offset;
@@ -173,7 +300,6 @@
// compiled.
constexpr TcParseTableBase(
uint16_t has_bits_offset, uint16_t extension_offset,
- uint32_t extension_range_low, uint32_t extension_range_high,
uint32_t max_field_number, uint8_t fast_idx_mask,
uint16_t lookup_table_offset, uint32_t skipmap32,
uint32_t field_entries_offset, uint16_t num_field_entries,
@@ -181,8 +307,6 @@
const MessageLite* default_instance, TailCallParseFunc fallback)
: has_bits_offset(has_bits_offset),
extension_offset(extension_offset),
- extension_range_low(extension_range_low),
- extension_range_high(extension_range_high),
max_field_number(max_field_number),
fast_idx_mask(fast_idx_mask),
lookup_table_offset(lookup_table_offset),
@@ -275,6 +399,9 @@
constexpr FieldAux(FieldAuxDefaultMessage, const void* msg)
: message_default_p(msg) {}
constexpr FieldAux(const TcParseTableBase* table) : table(table) {}
+ constexpr FieldAux(MapAuxInfo map_info) : map_info(map_info) {}
+ constexpr FieldAux(void (*create_in_arena)(Arena*, void*))
+ : create_in_arena(create_in_arena) {}
bool (*enum_validator)(int);
struct {
int16_t start; // minimum enum number (if it fits)
@@ -283,6 +410,8 @@
uint32_t offset;
const void* message_default_p;
const TcParseTableBase* table;
+ MapAuxInfo map_info;
+ void (*create_in_arena)(Arena*, void*);
const MessageLite* message_default() const {
return static_cast<const MessageLite*>(message_default_p);
diff --git a/src/google/protobuf/generated_message_tctable_gen.cc b/src/google/protobuf/generated_message_tctable_gen.cc
index b829bb7..987b669 100644
--- a/src/google/protobuf/generated_message_tctable_gen.cc
+++ b/src/google/protobuf/generated_message_tctable_gen.cc
@@ -78,100 +78,161 @@
}
}
+absl::string_view ParseFunctionValue(TcParseFunction function) {
+#define PROTOBUF_TC_PARSE_FUNCTION_X(value) #value,
+ static constexpr absl::string_view functions[] = {
+ {}, PROTOBUF_TC_PARSE_FUNCTION_LIST};
+#undef PROTOBUF_TC_PARSE_FUNCTION_X
+ return functions[static_cast<int>(function)];
+};
+
+enum class EnumRangeInfo {
+ kNone, // No contiguous range
+ kContiguous, // Has a contiguous range
+ kContiguous0, // Has a small contiguous range starting at 0
+ kContiguous1, // Has a small contiguous range starting at 1
+};
+
+// Returns enum validation range info, and sets `rmax_value` iff
+// the returned range is a small range. `rmax_value` is guaranteed
+// to remain unchanged if the enum range is not small.
+EnumRangeInfo GetEnumRangeInfo(const FieldDescriptor* field,
+ uint8_t& rmax_value) {
+ int16_t start;
+ uint16_t size;
+ if (!GetEnumValidationRange(field->enum_type(), start, size)) {
+ return EnumRangeInfo::kNone;
+ }
+ int max_value = start + size - 1;
+ if (max_value <= 127 && (start == 0 || start == 1)) {
+ rmax_value = static_cast<uint8_t>(max_value);
+ return start == 0 ? EnumRangeInfo::kContiguous0
+ : EnumRangeInfo::kContiguous1;
+ }
+ return EnumRangeInfo::kContiguous;
+}
+
void PopulateFastFieldEntry(const TailCallTableInfo::FieldEntryInfo& entry,
const TailCallTableInfo::PerFieldOptions& options,
TailCallTableInfo::FastFieldInfo& info) {
+#define PROTOBUF_PICK_FUNCTION(fn) \
+ (field->number() < 16 ? TcParseFunction::fn##1 : TcParseFunction::fn##2)
+
+#define PROTOBUF_PICK_SINGLE_FUNCTION(fn) PROTOBUF_PICK_FUNCTION(fn##S)
+
+#define PROTOBUF_PICK_REPEATABLE_FUNCTION(fn) \
+ (field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \
+ : PROTOBUF_PICK_FUNCTION(fn##S))
+
+#define PROTOBUF_PICK_PACKABLE_FUNCTION(fn) \
+ (field->is_packed() ? PROTOBUF_PICK_FUNCTION(fn##P) \
+ : field->is_repeated() ? PROTOBUF_PICK_FUNCTION(fn##R) \
+ : PROTOBUF_PICK_FUNCTION(fn##S))
+
+#define PROTOBUF_PICK_STRING_FUNCTION(fn) \
+ (field->options().ctype() == FieldOptions::CORD \
+ ? PROTOBUF_PICK_FUNCTION(fn##cS) \
+ : options.is_string_inlined ? PROTOBUF_PICK_FUNCTION(fn##iS) \
+ : PROTOBUF_PICK_REPEATABLE_FUNCTION(fn))
+
+#define PROTOBUF_PICK_MESSAGE_FUNCTION(fn) \
+ (options.use_direct_tcparser_table \
+ ? PROTOBUF_PICK_REPEATABLE_FUNCTION(fn##t) \
+ : PROTOBUF_PICK_REPEATABLE_FUNCTION(fn##d))
+
const FieldDescriptor* field = entry.field;
- std::string name = "::_pbi::TcParser::Fast";
- uint8_t aux_idx = static_cast<uint8_t>(entry.aux_idx);
-
- static const char* kPrefix[] = {
- nullptr, // 0
- "F64", // TYPE_DOUBLE = 1,
- "F32", // TYPE_FLOAT = 2,
- "V64", // TYPE_INT64 = 3,
- "V64", // TYPE_UINT64 = 4,
- "V32", // TYPE_INT32 = 5,
- "F64", // TYPE_FIXED64 = 6,
- "F32", // TYPE_FIXED32 = 7,
- "V8", // TYPE_BOOL = 8,
- "", // TYPE_STRING = 9,
- "G", // TYPE_GROUP = 10,
- "M", // TYPE_MESSAGE = 11,
- "B", // TYPE_BYTES = 12,
- "V32", // TYPE_UINT32 = 13,
- "", // TYPE_ENUM = 14,
- "F32", // TYPE_SFIXED32 = 15,
- "F64", // TYPE_SFIXED64 = 16,
- "Z32", // TYPE_SINT32 = 17,
- "Z64", // TYPE_SINT64 = 18,
- };
- name.append(kPrefix[field->type()]);
-
- if (field->type() == field->TYPE_ENUM) {
- // Enums are handled as:
- // - V32 for open enums
- // - Er (and Er0/Er1) for sequential enums
- // - Ev for the rest
- if (cpp::HasPreservingUnknownEnumSemantics(field)) {
- name.append("V32");
- } else {
- int16_t start;
- uint16_t size;
- if (GetEnumValidationRange(field->enum_type(), start, size)) {
- name.append("Er");
- int max_value = start + size - 1;
- if (max_value <= 127 && (start == 0 || start == 1)) {
- name.append(1, '0' + start);
- aux_idx = max_value;
- }
- } else {
- name.append("Ev");
- }
- }
- }
- if (field->type() == field->TYPE_STRING) {
- switch (internal::cpp::GetUtf8CheckMode(field, options.is_lite)) {
- case internal::cpp::Utf8CheckMode::kStrict:
- name.append("U");
- break;
- case internal::cpp::Utf8CheckMode::kVerify:
- name.append("S");
- break;
- case internal::cpp::Utf8CheckMode::kNone:
- name.append("B");
- break;
- }
- }
- if (field->type() == field->TYPE_STRING ||
- field->type() == field->TYPE_BYTES) {
- if (field->options().ctype() == FieldOptions::CORD) {
- name.append("c");
- } else if (options.is_string_inlined) {
- name.append("i");
+ info.aux_idx = static_cast<uint8_t>(entry.aux_idx);
+ if (field->type() == FieldDescriptor::TYPE_BYTES ||
+ field->type() == FieldDescriptor::TYPE_STRING) {
+ if (options.is_string_inlined) {
ABSL_CHECK(!field->is_repeated());
- aux_idx = static_cast<uint8_t>(entry.inlined_string_idx);
+ info.aux_idx = static_cast<uint8_t>(entry.inlined_string_idx);
}
}
- if (field->type() == field->TYPE_MESSAGE ||
- field->type() == field->TYPE_GROUP) {
- name.append(options.use_direct_tcparser_table ? "t" : "d");
+
+ TcParseFunction picked = TcParseFunction::kNone;
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_BOOL:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV8);
+ break;
+ case FieldDescriptor::TYPE_INT32:
+ case FieldDescriptor::TYPE_UINT32:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV32);
+ break;
+ case FieldDescriptor::TYPE_SINT32:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastZ32);
+ break;
+ case FieldDescriptor::TYPE_INT64:
+ case FieldDescriptor::TYPE_UINT64:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV64);
+ break;
+ case FieldDescriptor::TYPE_SINT64:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastZ64);
+ break;
+ case FieldDescriptor::TYPE_FLOAT:
+ case FieldDescriptor::TYPE_FIXED32:
+ case FieldDescriptor::TYPE_SFIXED32:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastF32);
+ break;
+ case FieldDescriptor::TYPE_DOUBLE:
+ case FieldDescriptor::TYPE_FIXED64:
+ case FieldDescriptor::TYPE_SFIXED64:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastF64);
+ break;
+ case FieldDescriptor::TYPE_ENUM:
+ if (cpp::HasPreservingUnknownEnumSemantics(field)) {
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastV32);
+ } else {
+ switch (GetEnumRangeInfo(field, info.aux_idx)) {
+ case EnumRangeInfo::kNone:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEv);
+ break;
+ case EnumRangeInfo::kContiguous:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr);
+ break;
+ case EnumRangeInfo::kContiguous0:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr0);
+ break;
+ case EnumRangeInfo::kContiguous1:
+ picked = PROTOBUF_PICK_PACKABLE_FUNCTION(kFastEr1);
+ break;
+ }
+ }
+ break;
+ case FieldDescriptor::TYPE_BYTES:
+ picked = PROTOBUF_PICK_STRING_FUNCTION(kFastB);
+ break;
+ case FieldDescriptor::TYPE_STRING:
+ switch (internal::cpp::GetUtf8CheckMode(field, options.is_lite)) {
+ case internal::cpp::Utf8CheckMode::kStrict:
+ picked = PROTOBUF_PICK_STRING_FUNCTION(kFastU);
+ break;
+ case internal::cpp::Utf8CheckMode::kVerify:
+ picked = PROTOBUF_PICK_STRING_FUNCTION(kFastS);
+ break;
+ case internal::cpp::Utf8CheckMode::kNone:
+ picked = PROTOBUF_PICK_STRING_FUNCTION(kFastB);
+ break;
+ }
+ break;
+ case FieldDescriptor::TYPE_MESSAGE:
+ picked = PROTOBUF_PICK_MESSAGE_FUNCTION(kFastM);
+ break;
+ case FieldDescriptor::TYPE_GROUP:
+ picked = PROTOBUF_PICK_MESSAGE_FUNCTION(kFastG);
+ break;
}
- // The field implementation functions are prefixed by cardinality:
- // `S` for optional or implicit fields.
- // `R` for non-packed repeated.
- // `P` for packed repeated.
- name.append(field->is_packed() ? "P"
- : field->is_repeated() ? "R"
- : field->real_containing_oneof() ? "O"
- : "S");
+ ABSL_CHECK(picked != TcParseFunction::kNone);
+ static constexpr absl::string_view ns = "::_pbi::TcParser::";
+ info.func_name = absl::StrCat(ns, ParseFunctionValue(picked));
- // Append the tag length. Fast parsing only handles 1- or 2-byte tags.
- name.append(field->number() < 16 ? "1" : "2");
-
- info.func_name = std::move(name);
- info.aux_idx = aux_idx;
+#undef PROTOBUF_PICK_FUNCTION
+#undef PROTOBUF_PICK_SINGLE_FUNCTION
+#undef PROTOBUF_PICK_REPEATABLE_FUNCTION
+#undef PROTOBUF_PICK_PACKABLE_FUNCTION
+#undef PROTOBUF_PICK_STRING_FUNCTION
+#undef PROTOBUF_PICK_MESSAGE_FUNCTION
}
bool IsFieldEligibleForFastParsing(
@@ -364,7 +425,7 @@
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
// TODO(b/210762816): support remaining field types.
- if (field->is_map() || field->options().weak() || options.is_lazy) {
+ if (field->options().weak() || options.is_lazy) {
handled = false;
} else {
handled = true;
@@ -383,33 +444,38 @@
// We only need field names for reporting UTF-8 parsing errors, so we only
// emit them for string fields with Utf8 transform specified.
-absl::string_view FieldNameForTable(
- const TailCallTableInfo::FieldEntryInfo& entry) {
- const auto* field = entry.field;
- if (field->type() == FieldDescriptor::TYPE_STRING) {
- const uint16_t xform_val = entry.type_card & field_layout::kTvMask;
+bool NeedsFieldNameForTable(const FieldDescriptor* field, bool is_lite) {
+ if (cpp::GetUtf8CheckMode(field, is_lite) == cpp::Utf8CheckMode::kNone)
+ return false;
+ return field->type() == FieldDescriptor::TYPE_STRING ||
+ (field->is_map() && (field->message_type()->map_key()->type() ==
+ FieldDescriptor::TYPE_STRING ||
+ field->message_type()->map_value()->type() ==
+ FieldDescriptor::TYPE_STRING));
+}
- switch (xform_val) {
- case field_layout::kTvUtf8:
- case field_layout::kTvUtf8Debug:
- return field->name();
- }
+absl::string_view FieldNameForTable(
+ const TailCallTableInfo::FieldEntryInfo& entry,
+ const TailCallTableInfo::OptionProvider& option_provider) {
+ if (NeedsFieldNameForTable(
+ entry.field, option_provider.GetForField(entry.field).is_lite)) {
+ return entry.field->name();
}
return "";
}
std::vector<uint8_t> GenerateFieldNames(
const Descriptor* descriptor,
- const std::vector<TailCallTableInfo::FieldEntryInfo>& entries) {
+ const std::vector<TailCallTableInfo::FieldEntryInfo>& entries,
+ const TailCallTableInfo::OptionProvider& option_provider) {
static constexpr int kMaxNameLength = 255;
std::vector<uint8_t> out;
+ std::vector<absl::string_view> names;
bool found_needed_name = false;
for (const auto& entry : entries) {
- if (!FieldNameForTable(entry).empty()) {
- found_needed_name = true;
- break;
- }
+ names.push_back(FieldNameForTable(entry, option_provider));
+ if (!names.back().empty()) found_needed_name = true;
}
// No names needed. Omit the whole table.
@@ -422,8 +488,8 @@
int count = 1;
out.push_back(std::min(static_cast<int>(descriptor->full_name().size()),
kMaxNameLength));
- for (const auto& entry : entries) {
- out.push_back(FieldNameForTable(entry).size());
+ for (auto field_name : names) {
+ out.push_back(field_name.size());
++count;
}
while (count & 7) { // align to an 8-byte boundary
@@ -440,8 +506,7 @@
}
out.insert(out.end(), message_name.begin(), message_name.end());
// Then we output the actual field names
- for (const auto& entry : entries) {
- const auto& field_name = FieldNameForTable(entry);
+ for (auto field_name : names) {
out.insert(out.end(), field_name.begin(), field_name.end());
}
@@ -718,7 +783,19 @@
field->type() == FieldDescriptor::TYPE_GROUP) {
// Message-typed fields have a FieldAux with the default instance pointer.
if (field->is_map()) {
- // TODO(b/205904770): generate aux entries for maps
+ field_entries.back().aux_idx = aux_entries.size();
+ aux_entries.push_back({kMapAuxInfo, {field}});
+ if (options.uses_codegen) {
+ // If we don't use codegen we can't add these.
+ auto* map_value = field->message_type()->map_value();
+ if (auto* sub = map_value->message_type()) {
+ aux_entries.push_back({kCreateInArena});
+ aux_entries.back().desc = sub;
+ } else if (map_value->type() == FieldDescriptor::TYPE_ENUM &&
+ !cpp::HasPreservingUnknownEnumSemantics(map_value)) {
+ aux_entries.push_back({kEnumValidator, {map_value}});
+ }
+ }
} else if (field->options().weak()) {
// Don't generate anything for weak fields. They are handled by the
// generated fallback.
@@ -819,13 +896,13 @@
num_to_entry_table = MakeNumToEntryTable(ordered_fields);
ABSL_CHECK_EQ(field_entries.size(), ordered_fields.size());
- field_name_data = GenerateFieldNames(descriptor, field_entries);
+ field_name_data =
+ GenerateFieldNames(descriptor, field_entries, option_provider);
// If there are no fallback fields, and at most one extension range, the
// parser can use a generic fallback function. Otherwise, a message-specific
// fallback routine is needed.
- use_generated_fallback =
- !fallback_fields.empty() || descriptor->extension_range_count() > 1;
+ use_generated_fallback = !fallback_fields.empty();
}
} // namespace internal
diff --git a/src/google/protobuf/generated_message_tctable_gen.h b/src/google/protobuf/generated_message_tctable_gen.h
index ac24dd7..3f5f7ec 100644
--- a/src/google/protobuf/generated_message_tctable_gen.h
+++ b/src/google/protobuf/generated_message_tctable_gen.h
@@ -59,6 +59,7 @@
bool use_direct_tcparser_table;
bool is_lite;
bool should_split;
+ bool uses_codegen;
};
class OptionProvider {
public:
@@ -106,6 +107,8 @@
kEnumRange,
kEnumValidator,
kNumericOffset,
+ kMapAuxInfo,
+ kCreateInArena,
};
struct AuxEntry {
AuxType type;
@@ -115,6 +118,7 @@
};
union {
const FieldDescriptor* field;
+ const Descriptor* desc;
uint32_t offset;
EnumRange enum_range;
};
diff --git a/src/google/protobuf/generated_message_tctable_impl.h b/src/google/protobuf/generated_message_tctable_impl.h
index a39245d..2527fd0 100644
--- a/src/google/protobuf/generated_message_tctable_impl.h
+++ b/src/google/protobuf/generated_message_tctable_impl.h
@@ -40,6 +40,7 @@
#include "google/protobuf/port.h"
#include "google/protobuf/extension_set.h"
#include "google/protobuf/generated_message_tctable_decl.h"
+#include "google/protobuf/map.h"
#include "google/protobuf/metadata_lite.h"
#include "google/protobuf/parse_context.h"
#include "google/protobuf/wire_format_lite.h"
@@ -84,6 +85,7 @@
namespace field_layout {
// clang-format off
+
// Field kind (3 bits):
// These values broadly represent a wire type and an in-memory storage class.
enum FieldKind : uint16_t {
@@ -128,6 +130,7 @@
kFcOneof = 3 << kFcShift,
};
+
// Field representation (3 bits):
// These values are the specific refinements of storage classes in FieldType.
enum FieldRep : uint16_t {
@@ -267,11 +270,114 @@
std::uintptr_t address) {}
#endif
+#define PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(fn) \
+ PROTOBUF_TC_PARSE_FUNCTION_X(fn##S1) \
+ PROTOBUF_TC_PARSE_FUNCTION_X(fn##S2)
+
+#define PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(fn) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(fn) \
+ PROTOBUF_TC_PARSE_FUNCTION_X(fn##R1) \
+ PROTOBUF_TC_PARSE_FUNCTION_X(fn##R2)
+
+#define PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(fn) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(fn) \
+ PROTOBUF_TC_PARSE_FUNCTION_X(fn##P1) \
+ PROTOBUF_TC_PARSE_FUNCTION_X(fn##P2)
+
+#define PROTOBUF_TC_PARSE_FUNCTION_LIST_END_GROUP() \
+ PROTOBUF_TC_PARSE_FUNCTION_X(FastEndG1) \
+ PROTOBUF_TC_PARSE_FUNCTION_X(FastEndG2)
+
+// TcParseFunction defines the set of table driven, tail call optimized parse
+// functions. This list currently does not include all types such as maps.
+//
+// This table identifies the logical set of functions, it does not imply that
+// functions of the same name do exist, and some entries may point to thunks or
+// generic implementations accepting multiple types of input.
+//
+// The names are encoded as follows:
+// kFast<type>[<validation>][cardinality][tag_width]
+//
+// type:
+// V8 - bool
+// V32 - int32/uint32 varint
+// Z32 - int32/uint32 varint with zigzag encoding
+// V64 - int64/uint64 varint
+// Z64 - int64/uint64 varint with zigzag encoding
+// F32 - int32/uint32/float fixed width value
+// F64 - int64/uint64/double fixed width value
+// E - enum
+// B - string (bytes)*
+// S - utf8 string, verified in debug mode only*
+// U - utf8 string, strictly verified*
+// Gd - group
+// Gt - group width table driven parse tables
+// Md - message
+// Mt - message width table driven parse tables
+// End - End group tag
+//
+// * string types can have a `c` or `i` suffix, indicating the
+// underlying storage type to be cord or inlined respectively.
+//
+// validation:
+// For enums:
+// v - verify
+// r - verify; enum values are a contiguous range
+// r0 - verify; enum values are a small contiguous range starting at 0
+// r1 - verify; enum values are a small contiguous range starting at 1
+// For strings:
+// u - validate utf8 encoding
+// v - validate utf8 encoding for debug only
+//
+// cardinality:
+// S - singular / optional
+// R - repeated
+// P - packed
+// G - group terminated
+//
+// tag_width:
+// 1: single byte encoded tag
+// 2: two byte encoded tag
+//
+// Examples:
+// FastV8S1, FastZ64S2, FastEr1P2, FastBcS1, FastMtR2, FastEndG1
+//
+#define PROTOBUF_TC_PARSE_FUNCTION_LIST \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV8) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV32) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastV64) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastZ32) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastZ64) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastF32) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastF64) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEv) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr0) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_PACKED(FastEr1) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastB) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastS) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastU) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastBi) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastSi) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastUi) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastBc) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastSc) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_SINGLE(FastUc) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastGd) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastGt) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastMd) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_REPEATED(FastMt) \
+ PROTOBUF_TC_PARSE_FUNCTION_LIST_END_GROUP()
+
+#define PROTOBUF_TC_PARSE_FUNCTION_X(value) k##value,
+enum class TcParseFunction { kNone, PROTOBUF_TC_PARSE_FUNCTION_LIST };
+#undef PROTOBUF_TC_PARSE_FUNCTION_X
+
// TcParser implements most of the parsing logic for tailcall tables.
class PROTOBUF_EXPORT TcParser final {
public:
template <typename T>
- static constexpr const TcParseTableBase* GetTable() {
+ static constexpr auto GetTable() -> decltype(&T::_table_.header) {
return &T::_table_.header;
}
@@ -292,7 +398,7 @@
// the function is used as a way to get a UnknownFieldOps vtable, returned
// via the `const char*` return type. See `GetUnknownFieldOps()`
- static bool MustFallbackToGeneric(PROTOBUF_TC_PARAM_DECL) {
+ static bool MustFallbackToGeneric(PROTOBUF_TC_PARAM_NO_DATA_DECL) {
return ptr == nullptr;
}
@@ -359,36 +465,16 @@
static const char* FastZ64P1(PROTOBUF_TC_PARAM_DECL);
static const char* FastZ64P2(PROTOBUF_TC_PARAM_DECL);
- // Manually unrolled and specialized Varint parsing.
- template <typename FieldType, int data_offset, int hasbit_idx>
- static const char* FastTV32S1(PROTOBUF_TC_PARAM_DECL);
- template <typename FieldType, int data_offset, int hasbit_idx>
- static const char* FastTV64S1(PROTOBUF_TC_PARAM_DECL);
- template <int data_offset, int hasbit_idx>
- static const char* FastTV8S1(PROTOBUF_TC_PARAM_DECL);
-
- template <typename FieldType, int data_offset, int hasbit_idx>
+ template <typename FieldType, int unused_data_offset, int unused_hasbit_idx>
static constexpr TailCallParseFunc SingularVarintNoZag1() {
if (sizeof(FieldType) == 1) {
- if (data_offset < 100) {
- return &FastTV8S1<data_offset, hasbit_idx>;
- } else {
- return &FastV8S1;
- }
+ return &FastV8S1;
}
if (sizeof(FieldType) == 4) {
- if (data_offset < 100) {
- return &FastTV32S1<FieldType, data_offset, hasbit_idx>;
- } else { //
- return &FastV32S1;
- }
+ return &FastV32S1;
}
if (sizeof(FieldType) == 8) {
- if (data_offset < 128) {
- return &FastTV64S1<FieldType, data_offset, hasbit_idx>;
- } else {
- return &FastV64S1;
- }
+ return &FastV64S1;
}
static_assert(sizeof(FieldType) == 1 || sizeof(FieldType) == 4 ||
sizeof(FieldType) == 8,
@@ -529,12 +615,43 @@
// NOTE: Currently, this function only calls the table-level fallback
// function, so it should only be called as the fallback from fast table
// parsing.
- static const char* MiniParse(PROTOBUF_TC_PARAM_DECL);
+ static const char* MiniParse(PROTOBUF_TC_PARAM_NO_DATA_DECL);
static const char* FastEndG1(PROTOBUF_TC_PARAM_DECL);
static const char* FastEndG2(PROTOBUF_TC_PARAM_DECL);
+ // For `map` mini parsing generate a type card for the key/value.
+ template <typename MapField>
+ static constexpr MapAuxInfo GetMapAuxInfo(bool fail_on_utf8_failure,
+ bool log_debug_utf8_failure,
+ bool validated_enum_value) {
+ using MapType = typename MapField::MapType;
+ using Node = typename MapType::Node;
+ static_assert(alignof(Node) == alignof(NodeBase), "");
+ // Verify the assumption made in MpMap, guaranteed by Map<>.
+ assert(PROTOBUF_FIELD_OFFSET(Node, kv.first) == sizeof(NodeBase));
+ return {
+ MakeMapTypeCard(MapField::kKeyFieldType),
+ MakeMapTypeCard(MapField::kValueFieldType),
+ true,
+ !std::is_base_of<MapFieldBaseForParse, MapField>::value,
+ fail_on_utf8_failure,
+ log_debug_utf8_failure,
+ validated_enum_value,
+ Node::size_info(),
+ };
+ }
+
+ template <typename T>
+ static void CreateInArenaStorageCb(Arena* arena, void* p) {
+ Arena::CreateInArenaStorage(static_cast<T*>(p), arena);
+ }
+
private:
+ // Optimized small tag varint parser for int32/int64
+ template <typename FieldType>
+ static const char* FastVarintS1(PROTOBUF_TC_PARAM_DECL);
+
friend class GeneratedTcTableLiteTest;
static void* MaybeGetSplitBase(MessageLite* msg, const bool is_split,
const TcParseTableBase* table);
@@ -569,12 +686,13 @@
}
}
- static const char* TagDispatch(PROTOBUF_TC_PARAM_DECL);
- static const char* ToTagDispatch(PROTOBUF_TC_PARAM_DECL);
- static const char* ToParseLoop(PROTOBUF_TC_PARAM_DECL);
- static const char* Error(PROTOBUF_TC_PARAM_DECL);
+ static const char* TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+ static const char* ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+ static const char* ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_DECL);
+ static const char* Error(PROTOBUF_TC_PARAM_NO_DATA_DECL);
static const char* FastUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
+ static const char* MpUnknownEnumFallback(PROTOBUF_TC_PARAM_DECL);
class ScopedArenaSwap;
@@ -618,18 +736,21 @@
return ptr;
}
- uint32_t num = tag >> 3;
- if (table->extension_range_low <= num &&
- num <= table->extension_range_high) {
+ if (table->extension_offset != 0) {
+ // We don't need to check the extension ranges. If it is not an extension
+ // it will be handled just like if it was an unknown extension: sent to
+ // the unknown field set.
return RefAt<ExtensionSet>(msg, table->extension_offset)
.ParseField(tag, ptr,
static_cast<const MessageBaseT*>(table->default_instance),
&msg->_internal_metadata_, ctx);
+ } else {
+ // Otherwise, we directly put it on the unknown field set.
+ return UnknownFieldParse(
+ tag,
+ msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
+ ptr, ctx);
}
-
- return UnknownFieldParse(
- tag, msg->_internal_metadata_.mutable_unknown_fields<UnknownFieldsT>(),
- ptr, ctx);
}
// Note: `inline` is needed on template function declarations below to avoid
@@ -680,8 +801,23 @@
const char* ptr, Arena* arena, SerialArena* serial_arena,
ParseContext* ctx, RepeatedPtrField<std::string>& field);
- static void UnknownPackedEnum(MessageLite* msg, const TcParseTableBase* table,
- uint32_t tag, int32_t enum_value);
+ static void AddUnknownEnum(MessageLite* msg, const TcParseTableBase* table,
+ uint32_t tag, int32_t enum_value);
+
+ static void WriteMapEntryAsUnknown(MessageLite* msg,
+ const TcParseTableBase* table,
+ uint32_t tag, NodeBase* node,
+ MapAuxInfo map_info);
+
+ static void InitializeMapNodeEntry(void* obj, MapTypeCard type_card,
+ UntypedMapBase& map,
+ const TcParseTableBase::FieldAux* aux);
+ static void DestroyMapNode(NodeBase* node, MapAuxInfo map_info,
+ UntypedMapBase& map);
+ static const char* ParseOneMapEntry(
+ NodeBase* node, const char* ptr, ParseContext* ctx,
+ const TcParseTableBase::FieldAux* aux, const TcParseTableBase* table,
+ const TcParseTableBase::FieldEntry& entry);
// Mini field lookup:
static const TcParseTableBase::FieldEntry* FindFieldEntry(
@@ -724,264 +860,17 @@
static const char* MpMessage(PROTOBUF_TC_PARAM_DECL);
static const char* MpRepeatedMessage(PROTOBUF_TC_PARAM_DECL);
static const char* MpFallback(PROTOBUF_TC_PARAM_DECL);
+ static const char* MpMap(PROTOBUF_TC_PARAM_DECL);
};
-// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
-template <int n>
-inline PROTOBUF_ALWAYS_INLINE int64_t shift_left_fill_with_ones(uint64_t byte,
- uint64_t ones) {
- return static_cast<int64_t>((byte << (n * 7)) | (ones >> (64 - (n * 7))));
-}
-
-// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
-// put the new value in res. Return whether the result was negative.
-template <int n>
-inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
- uint64_t byte, uint64_t ones, int64_t& res) {
-#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
- // For the first two rounds (ptr[1] and ptr[2]), micro benchmarks show a
- // substantial improvement from capturing the sign from the condition code
- // register on x86-64.
- bool sign_bit;
- asm("shldq %3, %2, %1"
- : "=@ccs"(sign_bit), "+r"(byte)
- : "r"(ones), "i"(n * 7));
- res = static_cast<int64_t>(byte);
- return sign_bit;
-#else
- // Generic fallback:
- res = shift_left_fill_with_ones<n>(byte, ones);
- return res < 0;
-#endif
-}
-
-template <class VarintType>
-inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, VarintType>
-ParseFallbackPair(const char* p, int64_t res1) {
- constexpr bool kIs64BitVarint = std::is_same<VarintType, uint64_t>::value;
- constexpr bool kIs32BitVarint = std::is_same<VarintType, uint32_t>::value;
- static_assert(kIs64BitVarint || kIs32BitVarint,
- "Only 32 or 64 bit varints are supported");
- auto ptr = reinterpret_cast<const int8_t*>(p);
-
- // The algorithm relies on sign extension for each byte to set all high bits
- // when the varint continues. It also relies on asserting all of the lower
- // bits for each successive byte read. This allows the result to be aggregated
- // using a bitwise AND. For example:
- //
- // 8 1 64 57 ... 24 17 16 9 8 1
- // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111 1111 1111 1aaa aaaa
- // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111 11bb bbbb b111 1111
- // ptr[2] = 1ccc cccc ; res3 = 0000 0000 ... 000c cccc cc11 1111 1111 1111
- // ---------------------------------------------
- // res1 & res2 & res3 = 0000 0000 ... 000c cccc ccbb bbbb baaa aaaa
- //
- // On x86-64, a shld from a single register filled with enough 1s in the high
- // bits can accomplish all this in one instruction. It so happens that res1
- // has 57 high bits of ones, which is enough for the largest shift done.
- //
- // Just as importantly, by keeping results in res1, res2, and res3, we take
- // advantage of the superscalar abilities of the CPU.
- ABSL_DCHECK_EQ(res1 >> 7, -1);
- uint64_t ones = res1; // save the high 1 bits from res1 (input to SHLD)
- int64_t res2, res3; // accumulated result chunks
-
- if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
- goto done2;
- if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
- goto done3;
-
- // For the remainder of the chunks, check the sign of the AND result.
- res2 &= shift_left_fill_with_ones<3>(ptr[3], ones);
- if (res2 >= 0) goto done4;
- res1 &= shift_left_fill_with_ones<4>(ptr[4], ones);
- if (res1 >= 0) goto done5;
- if (kIs64BitVarint) {
- res2 &= shift_left_fill_with_ones<5>(ptr[5], ones);
- if (res2 >= 0) goto done6;
- res3 &= shift_left_fill_with_ones<6>(ptr[6], ones);
- if (res3 >= 0) goto done7;
- res1 &= shift_left_fill_with_ones<7>(ptr[7], ones);
- if (res1 >= 0) goto done8;
- res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
- if (res3 >= 0) goto done9;
- } else if (kIs32BitVarint) {
- if (PROTOBUF_PREDICT_TRUE(!(ptr[5] & 0x80))) goto done6;
- if (PROTOBUF_PREDICT_TRUE(!(ptr[6] & 0x80))) goto done7;
- if (PROTOBUF_PREDICT_TRUE(!(ptr[7] & 0x80))) goto done8;
- if (PROTOBUF_PREDICT_TRUE(!(ptr[8] & 0x80))) goto done9;
- }
-
- // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
- // case, the continuation bit of ptr[8] already set the top bit of res3
- // correctly, so all we have to do is check that the expected case is true.
- if (PROTOBUF_PREDICT_TRUE(kIs64BitVarint && ptr[9] == 1)) goto done10;
-
- if (PROTOBUF_PREDICT_FALSE(ptr[9] & 0x80)) {
- // If the continue bit is set, it is an unterminated varint.
- return {nullptr, 0};
- }
-
- // A zero value of the first bit of the 10th byte represents an
- // over-serialized varint. This case should not happen, but if does (say, due
- // to a nonconforming serializer), deassert the continuation bit that came
- // from ptr[8].
- if (kIs64BitVarint && (ptr[9] & 1) == 0) {
-#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
- // Use a small instruction since this is an uncommon code path.
- asm("btcq $63,%0" : "+r"(res3));
-#else
- res3 ^= static_cast<uint64_t>(1) << 63;
-#endif
- }
- goto done10;
-
-done2:
- return {p + 2, res1 & res2};
-done3:
- return {p + 3, res1 & res2 & res3};
-done4:
- return {p + 4, res1 & res2 & res3};
-done5:
- return {p + 5, res1 & res2 & res3};
-done6:
- return {p + 6, res1 & res2 & res3};
-done7:
- return {p + 7, res1 & res2 & res3};
-done8:
- return {p + 8, res1 & res2 & res3};
-done9:
- return {p + 9, res1 & res2 & res3};
-done10:
- return {p + 10, res1 & res2 & res3};
-}
-
-// Notes:
-// 1) if data_offset is negative, it's read from data.offset()
-// 2) if hasbit_idx is negative, it's read from data.hasbit_idx()
-template <int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV8S1(PROTOBUF_TC_PARAM_DECL) {
- using TagType = uint8_t;
-
- // Special case for a varint bool field with a tag of 1 byte:
- // The coded_tag() field will actually contain the value too and we can check
- // both at the same time.
- auto coded_tag = data.coded_tag<uint16_t>();
- if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
- auto& field =
- RefAt<bool>(msg, data_offset >= 0 ? data_offset : data.offset());
- // Note: we use `data.data` because Clang generates suboptimal code when
- // using coded_tag.
- // In x86_64 this uses the CH register to read the second byte out of
- // `data`.
- uint8_t value = data.data >> 8;
- // The assume allows using a mov instead of test+setne.
- PROTOBUF_ASSUME(value <= 1);
- field = static_cast<bool>(value);
-
- ptr += sizeof(TagType) + 1; // Consume the tag and the value.
- if (hasbit_idx < 0) {
- hasbits |= (uint64_t{1} << data.hasbit_idx());
- } else {
- if (hasbit_idx < 32) {
- // `& 31` avoids a compiler warning when hasbit_idx is negative.
- hasbits |= (uint64_t{1} << (hasbit_idx & 31));
- } else {
- static_assert(hasbit_idx == 63 || (hasbit_idx < 32),
- "hard-coded hasbit_idx should be 0-31, or the special"
- "value 63, which indicates the field has no has-bit.");
- // TODO(jorg): investigate whether higher hasbit indices are worth
- // supporting. Something like:
- // auto& hasblock = TcParser::RefAt<uint32_t>(msg, hasbit_idx / 32 * 4);
- // hasblock |= uint32_t{1} << (hasbit_idx % 32);
- }
- }
-
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
- }
-
- // If it didn't match above either the tag is wrong, or the value is encoded
- // non-canonically.
- // Jump to MiniParse as wrong tag is the most probable reason.
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
-}
-
-template <typename FieldType, int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV64S1(PROTOBUF_TC_PARAM_DECL) {
- using TagType = uint8_t;
- // super-early success test...
- if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
- uint8_t value = data.data >> 8;
- RefAt<FieldType>(msg, data_offset) = value;
- ptr += 1;
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
- }
- if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
- }
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
-
- auto tmp =
- ParseFallbackPair<uint64_t>(ptr, static_cast<int8_t>(data.data >> 8));
- data.data = 0; // Indicate to the compiler that we don't need this anymore.
- ptr = tmp.first;
- if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
- }
-
- RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-}
-
-template <typename FieldType, int data_offset, int hasbit_idx>
-PROTOBUF_NOINLINE const char* TcParser::FastTV32S1(PROTOBUF_TC_PARAM_DECL) {
- using TagType = uint8_t;
- // super-early success test...
- if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
- uint8_t value = data.data >> 8;
- RefAt<FieldType>(msg, data_offset) = value;
- ptr += 1;
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
- }
- if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
- }
- ptr += sizeof(TagType); // Consume tag
- if (hasbit_idx < 32) {
- hasbits |= (uint64_t{1} << hasbit_idx);
- }
-
- auto tmp =
- ParseFallbackPair<uint32_t>(ptr, static_cast<int8_t>(data.data >> 8));
- data.data = 0; // Indicate to the compiler that we don't need this anymore.
- ptr = tmp.first;
- if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
- }
-
- RefAt<FieldType>(msg, data_offset) = static_cast<FieldType>(tmp.second);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
-}
-
// Dispatch to the designated parse function
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::TagDispatch(
- PROTOBUF_TC_PARAM_DECL) {
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
const auto coded_tag = UnalignedLoad<uint16_t>(ptr);
const size_t idx = coded_tag & table->fast_idx_mask;
PROTOBUF_ASSUME((idx & 7) == 0);
auto* fast_entry = table->fast_entry(idx >> 3);
- data = fast_entry->bits;
+ TcFieldData data = fast_entry->bits;
data.data ^= coded_tag;
PROTOBUF_MUSTTAIL return fast_entry->target()(PROTOBUF_TC_PARAM_PASS);
}
@@ -992,25 +881,23 @@
// mode. Luckily the structure of the algorithm is such that it's always
// possible to just return and use the enclosing parse loop as a trampoline.
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToTagDispatch(
- PROTOBUF_TC_PARAM_DECL) {
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
constexpr bool always_return = !PROTOBUF_TAILCALL;
if (always_return || !ctx->DataAvailable(ptr)) {
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
- PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return TagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::ToParseLoop(
- PROTOBUF_TC_PARAM_DECL) {
- (void)data;
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
(void)ctx;
SyncHasbits(msg, hasbits, table);
return ptr;
}
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::Error(
- PROTOBUF_TC_PARAM_DECL) {
- (void)data;
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
(void)ctx;
(void)ptr;
SyncHasbits(msg, hasbits, table);
diff --git a/src/google/protobuf/generated_message_tctable_lite.cc b/src/google/protobuf/generated_message_tctable_lite.cc
index 86d067b..95869ff 100644
--- a/src/google/protobuf/generated_message_tctable_lite.cc
+++ b/src/google/protobuf/generated_message_tctable_lite.cc
@@ -37,6 +37,8 @@
#include "google/protobuf/generated_message_tctable_decl.h"
#include "google/protobuf/generated_message_tctable_impl.h"
#include "google/protobuf/inlined_string_field.h"
+#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+#include "google/protobuf/map.h"
#include "google/protobuf/message_lite.h"
#include "google/protobuf/parse_context.h"
#include "google/protobuf/wire_format_lite.h"
@@ -98,7 +100,7 @@
// TODO(b/64614992): remove this asm
asm("" : "+r"(table));
#endif
- ptr = TagDispatch(msg, ptr, ctx, {}, table - 1, 0);
+ ptr = TagDispatch(msg, ptr, ctx, TcFieldData::DefaultInit(), table - 1, 0);
if (ptr == nullptr) break;
if (ctx->LastTag() != 1) break; // Ended on terminating tag
}
@@ -279,7 +281,7 @@
ptr = ReadTagInlined(ptr, &tag);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
if (export_called_function) *test_out = {Error};
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
auto* entry = FindFieldEntry(table, tag >> 3);
@@ -308,7 +310,7 @@
&MpPackedFixed, // FieldKind::kFkPackedFixed
&MpString<false>, // FieldKind::kFkString
&MpMessage<false>, // FieldKind::kFkMessage
- &MpFallback, // FieldKind::kFkMap
+ &MpMap, // FieldKind::kFkMap
&Error, // kSplitMask | FieldKind::kFkNone
&MpVarint<true>, // kSplitMask | FieldKind::kFkVarint
&Error, // kSplitMask | FieldKind::kFkPackedVarint
@@ -351,8 +353,9 @@
PROTOBUF_MUSTTAIL return parse_fn(PROTOBUF_TC_PARAM_PASS);
}
-PROTOBUF_NOINLINE const char* TcParser::MiniParse(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse<false>(PROTOBUF_TC_PARAM_PASS);
+PROTOBUF_NOINLINE const char* TcParser::MiniParse(
+ PROTOBUF_TC_PARAM_NO_DATA_DECL) {
+ PROTOBUF_MUSTTAIL return MiniParse<false>(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE TcParser::TestMiniParseResult TcParser::TestMiniParse(
PROTOBUF_TC_PARAM_DECL) {
@@ -362,18 +365,18 @@
return result;
}
-const char* TcParser::MpFallback(PROTOBUF_TC_PARAM_DECL) {
+PROTOBUF_NOINLINE const char* TcParser::MpFallback(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
}
template <typename TagType>
const char* TcParser::FastEndGroupImpl(PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ctx->SetLastTag(data.decoded_tag());
ptr += sizeof(TagType);
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastEndG1(PROTOBUF_TC_PARAM_DECL) {
@@ -403,7 +406,7 @@
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularParseMessageAuxImpl(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
auto saved_tag = UnalignedLoad<TagType>(ptr);
ptr += sizeof(TagType);
@@ -478,7 +481,7 @@
inline PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedParseMessageAuxImpl(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const auto expected_tag = UnalignedLoad<TagType>(ptr);
const auto aux = *table->field_aux(data.aux_idx());
@@ -502,14 +505,14 @@
}
}
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) {
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastMdR1(PROTOBUF_TC_PARAM_DECL) {
@@ -560,13 +563,13 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularFixed(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ptr += sizeof(TagType); // Consume tag
hasbits |= (uint64_t{1} << data.hasbit_idx());
RefAt<LayoutType>(msg, data.offset()) = UnalignedLoad<LayoutType>(ptr);
ptr += sizeof(LayoutType);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastF32S1(PROTOBUF_TC_PARAM_DECL) {
@@ -598,7 +601,7 @@
if (data.coded_tag<TagType>() == 0) {
return PackedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<LayoutType>>(msg, data.offset());
@@ -607,7 +610,7 @@
field.Add(UnalignedLoad<LayoutType>(ptr + sizeof(TagType)));
ptr += sizeof(TagType) + sizeof(LayoutType);
} while (ctx->DataAvailable(ptr) && UnalignedLoad<TagType>(ptr) == tag);
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastF32R1(PROTOBUF_TC_PARAM_DECL) {
@@ -643,7 +646,7 @@
if (data.coded_tag<TagType>() == 0) {
return RepeatedFixed<LayoutType, TagType>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
ptr += sizeof(TagType);
@@ -680,6 +683,136 @@
namespace {
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE int64_t shift_left_fill_with_ones(uint64_t byte,
+ uint64_t ones) {
+ return static_cast<int64_t>((byte << (n * 7)) | (ones >> (64 - (n * 7))));
+}
+
+// Shift "byte" left by n * 7 bits, filling vacated bits with ones, and
+// put the new value in res. Return whether the result was negative.
+template <int n>
+inline PROTOBUF_ALWAYS_INLINE bool shift_left_fill_with_ones_was_negative(
+ uint64_t byte, uint64_t ones, int64_t& res) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+ // For the first two rounds (up to 2 varint bytes), micro benchmarks show a
+ // substantial improvement from capturing the sign from the condition code
+ // register on x86-64.
+ bool sign_bit;
+ asm("shldq %3, %2, %1"
+ : "=@ccs"(sign_bit), "+r"(byte)
+ : "r"(ones), "i"(n * 7));
+ res = static_cast<int64_t>(byte);
+ return sign_bit;
+#else
+ // Generic fallback:
+ res = shift_left_fill_with_ones<n>(byte, ones);
+ return res < 0;
+#endif
+}
+
+template <class VarintType>
+inline PROTOBUF_ALWAYS_INLINE std::pair<const char*, VarintType>
+ParseFallbackPair(const char* p, int64_t res1) {
+ constexpr bool kIs64BitVarint = std::is_same<VarintType, uint64_t>::value;
+ constexpr bool kIs32BitVarint = std::is_same<VarintType, uint32_t>::value;
+ static_assert(kIs64BitVarint || kIs32BitVarint,
+ "Only 32 or 64 bit varints are supported");
+ auto ptr = reinterpret_cast<const int8_t*>(p);
+
+ // The algorithm relies on sign extension for each byte to set all high bits
+ // when the varint continues. It also relies on asserting all of the lower
+ // bits for each successive byte read. This allows the result to be aggregated
+ // using a bitwise AND. For example:
+ //
+ // 8 1 64 57 ... 24 17 16 9 8 1
+ // ptr[0] = 1aaa aaaa ; res1 = 1111 1111 ... 1111 1111 1111 1111 1aaa aaaa
+ // ptr[1] = 1bbb bbbb ; res2 = 1111 1111 ... 1111 1111 11bb bbbb b111 1111
+ // ptr[2] = 0ccc cccc ; res3 = 0000 0000 ... 000c cccc cc11 1111 1111 1111
+ // ---------------------------------------------
+ // res1 & res2 & res3 = 0000 0000 ... 000c cccc ccbb bbbb baaa aaaa
+ //
+ // On x86-64, a shld from a single register filled with enough 1s in the high
+ // bits can accomplish all this in one instruction. It so happens that res1
+ // has 57 high bits of ones, which is enough for the largest shift done.
+ //
+ // Just as importantly, by keeping results in res1, res2, and res3, we take
+ // advantage of the superscalar abilities of the CPU.
+ ABSL_DCHECK_EQ(res1 >> 7, -1);
+ uint64_t ones = res1; // save the high 1 bits from res1 (input to SHLD)
+ int64_t res2, res3; // accumulated result chunks
+
+ if (!shift_left_fill_with_ones_was_negative<1>(ptr[1], ones, res2))
+ goto done2;
+ if (!shift_left_fill_with_ones_was_negative<2>(ptr[2], ones, res3))
+ goto done3;
+
+ // For the remainder of the chunks, check the sign of the AND result.
+ res2 &= shift_left_fill_with_ones<3>(ptr[3], ones);
+ if (res2 >= 0) goto done4;
+ res1 &= shift_left_fill_with_ones<4>(ptr[4], ones);
+ if (res1 >= 0) goto done5;
+ if (kIs64BitVarint) {
+ res2 &= shift_left_fill_with_ones<5>(ptr[5], ones);
+ if (res2 >= 0) goto done6;
+ res3 &= shift_left_fill_with_ones<6>(ptr[6], ones);
+ if (res3 >= 0) goto done7;
+ res1 &= shift_left_fill_with_ones<7>(ptr[7], ones);
+ if (res1 >= 0) goto done8;
+ res3 &= shift_left_fill_with_ones<8>(ptr[8], ones);
+ if (res3 >= 0) goto done9;
+ } else if (kIs32BitVarint) {
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[5] & 0x80))) goto done6;
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[6] & 0x80))) goto done7;
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[7] & 0x80))) goto done8;
+ if (PROTOBUF_PREDICT_TRUE(!(ptr[8] & 0x80))) goto done9;
+ }
+
+ // For valid 64bit varints, the 10th byte/ptr[9] should be exactly 1. In this
+ // case, the continuation bit of ptr[8] already set the top bit of res3
+ // correctly, so all we have to do is check that the expected case is true.
+ if (PROTOBUF_PREDICT_TRUE(kIs64BitVarint && ptr[9] == 1)) goto done10;
+
+ if (PROTOBUF_PREDICT_FALSE(ptr[9] & 0x80)) {
+ // If the continue bit is set, it is an unterminated varint.
+ return {nullptr, 0};
+ }
+
+ // A zero value of the first bit of the 10th byte represents an
+ // over-serialized varint. This case should not happen, but if does (say, due
+ // to a nonconforming serializer), deassert the continuation bit that came
+ // from ptr[8].
+ if (kIs64BitVarint && (ptr[9] & 1) == 0) {
+#if defined(__GCC_ASM_FLAG_OUTPUTS__) && defined(__x86_64__)
+ // Use a small instruction since this is an uncommon code path.
+ asm("btcq $63,%0" : "+r"(res3));
+#else
+ res3 ^= static_cast<uint64_t>(1) << 63;
+#endif
+ }
+ goto done10;
+
+done2:
+ return {p + 2, res1 & res2};
+done3:
+ return {p + 3, res1 & res2 & res3};
+done4:
+ return {p + 4, res1 & res2 & res3};
+done5:
+ return {p + 5, res1 & res2 & res3};
+done6:
+ return {p + 6, res1 & res2 & res3};
+done7:
+ return {p + 7, res1 & res2 & res3};
+done8:
+ return {p + 8, res1 & res2 & res3};
+done9:
+ return {p + 9, res1 & res2 & res3};
+done10:
+ return {p + 10, res1 & res2 & res3};
+}
+
template <typename Type>
inline PROTOBUF_ALWAYS_INLINE const char* ParseVarint(const char* p,
Type* value) {
@@ -792,7 +925,7 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularVarint(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ptr += sizeof(TagType); // Consume tag
hasbits |= (uint64_t{1} << data.hasbit_idx());
@@ -807,7 +940,7 @@
RefAt<FieldType>(msg, data.offset()) =
ZigZagDecodeHelper<FieldType, zigzag>(static_cast<uint8_t>(*ptr++));
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <typename FieldType, typename TagType, bool zigzag>
@@ -842,31 +975,86 @@
hasbits = spill.hasbits;
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
RefAt<FieldType>(msg, data.offset()) =
ZigZagDecodeHelper<FieldType, zigzag>(tmp);
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+}
+
+template <typename FieldType>
+PROTOBUF_ALWAYS_INLINE const char* TcParser::FastVarintS1(
+ PROTOBUF_TC_PARAM_DECL) {
+ using TagType = uint8_t;
+ // super-early success test...
+ if (PROTOBUF_PREDICT_TRUE(((data.data) & 0x80FF) == 0)) {
+ ptr += sizeof(TagType); // Consume tag
+ hasbits |= (uint64_t{1} << data.hasbit_idx());
+ uint8_t value = data.data >> 8;
+ RefAt<FieldType>(msg, data.offset()) = value;
+ ptr += 1;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ ptr += sizeof(TagType); // Consume tag
+ hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+ auto tmp =
+ ParseFallbackPair<FieldType>(ptr, static_cast<int8_t>(data.data >> 8));
+ ptr = tmp.first;
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+
+ RefAt<FieldType>(msg, data.offset()) = tmp.second;
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV8S1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return FastTV8S1<-1, -1>(PROTOBUF_TC_PARAM_PASS);
+ using TagType = uint8_t;
+
+ // Special case for a varint bool field with a tag of 1 byte:
+ // The coded_tag() field will actually contain the value too and we can check
+ // both at the same time.
+ auto coded_tag = data.coded_tag<uint16_t>();
+ if (PROTOBUF_PREDICT_TRUE(coded_tag == 0x0000 || coded_tag == 0x0100)) {
+ auto& field = RefAt<bool>(msg, data.offset());
+ // Note: we use `data.data` because Clang generates suboptimal code when
+ // using coded_tag.
+ // In x86_64 this uses the CH register to read the second byte out of
+ // `data`.
+ uint8_t value = data.data >> 8;
+ // The assume allows using a mov instead of test+setne.
+ PROTOBUF_ASSUME(value <= 1);
+ field = static_cast<bool>(value);
+
+ ptr += sizeof(TagType) + 1; // Consume the tag and the value.
+ hasbits |= (uint64_t{1} << data.hasbit_idx());
+
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+
+ // If it didn't match above either the tag is wrong, or the value is encoded
+ // non-canonically.
+ // Jump to MiniParse as wrong tag is the most probable reason.
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
+
PROTOBUF_NOINLINE const char* TcParser::FastV8S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<bool, uint16_t>(
PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV32S1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint8_t>(
- PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return FastVarintS1<uint32_t>(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV32S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<uint32_t, uint16_t>(
PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV64S1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint8_t>(
- PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return FastVarintS1<uint64_t>(PROTOBUF_TC_PARAM_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV64S2(PROTOBUF_TC_PARAM_DECL) {
PROTOBUF_MUSTTAIL return SingularVarint<uint64_t, uint16_t>(
@@ -899,7 +1087,7 @@
if (data.coded_tag<TagType>() == 0) {
return PackedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<FieldType>>(msg, data.offset());
@@ -909,14 +1097,14 @@
FieldType tmp;
ptr = ParseVarint(ptr, &tmp);
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
field.Add(ZigZagDecodeHelper<FieldType, zigzag>(tmp));
if (!ctx->DataAvailable(ptr)) {
break;
}
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastV8R1(PROTOBUF_TC_PARAM_DECL) {
@@ -969,7 +1157,7 @@
if (data.coded_tag<TagType>() == 0) {
return RepeatedVarint<FieldType, TagType, zigzag>(PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
ptr += sizeof(TagType);
@@ -1038,30 +1226,48 @@
PROTOBUF_NOINLINE const char* TcParser::FastUnknownEnumFallback(
PROTOBUF_TC_PARAM_DECL) {
- // If we know we want to put this field directly into the unknown field set,
- // then we can skip the call to MiniParse and directly call table->fallback.
- // However, we first have to update `data` to contain the decoded tag.
+ // Skip MiniParse/fallback and insert the element directly into the unknown
+ // field set. We also normalize the value into an int32 as we do for known
+ // enum values.
uint32_t tag;
ptr = ReadTag(ptr, &tag);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
- data.data = tag;
- PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+ uint64_t tmp;
+ ptr = ParseVarint(ptr, &tmp);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ AddUnknownEnum(msg, table, tag, static_cast<int32_t>(tmp));
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+}
+
+PROTOBUF_NOINLINE const char* TcParser::MpUnknownEnumFallback(
+ PROTOBUF_TC_PARAM_DECL) {
+ // Like FastUnknownEnumFallback, but with the Mp ABI.
+ uint32_t tag = data.tag();
+ uint64_t tmp;
+ ptr = ParseVarint(ptr, &tmp);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ AddUnknownEnum(msg, table, tag, static_cast<int32_t>(tmp));
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <typename TagType, uint16_t xform_val>
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnum(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* ptr2 = ptr; // Save for unknown enum case
ptr += sizeof(TagType); // Consume tag
uint64_t tmp;
ptr = ParseVarint(ptr, &tmp);
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
if (PROTOBUF_PREDICT_FALSE(
@@ -1071,7 +1277,7 @@
}
hasbits |= (uint64_t{1} << data.hasbit_idx());
RefAt<int32_t>(msg, data.offset()) = tmp;
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastErS1(PROTOBUF_TC_PARAM_DECL) {
@@ -1099,7 +1305,7 @@
PROTOBUF_MUSTTAIL return PackedEnum<TagType, xform_val>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
@@ -1111,7 +1317,7 @@
uint64_t tmp;
ptr = ParseVarint(ptr, &tmp);
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (PROTOBUF_PREDICT_FALSE(
!EnumIsValidAux(static_cast<int32_t>(tmp), xform_val, aux))) {
@@ -1125,7 +1331,7 @@
break;
}
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const TcParser::UnknownFieldOps& TcParser::GetUnknownFieldOps(
@@ -1139,9 +1345,10 @@
return *reinterpret_cast<const UnknownFieldOps*>(ptr);
}
-PROTOBUF_NOINLINE void TcParser::UnknownPackedEnum(
- MessageLite* msg, const TcParseTableBase* table, uint32_t tag,
- int32_t enum_value) {
+PROTOBUF_NOINLINE void TcParser::AddUnknownEnum(MessageLite* msg,
+ const TcParseTableBase* table,
+ uint32_t tag,
+ int32_t enum_value) {
GetUnknownFieldOps(table).write_varint(msg, tag >> 3, enum_value);
}
@@ -1153,7 +1360,7 @@
PROTOBUF_MUSTTAIL return RepeatedEnum<TagType, xform_val>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
const auto saved_tag = UnalignedLoad<TagType>(ptr);
@@ -1165,7 +1372,7 @@
const TcParseTableBase::FieldAux aux = *table->field_aux(data.aux_idx());
return ctx->ReadPackedVarint(ptr, [=](int32_t value) {
if (!EnumIsValidAux(value, xform_val, aux)) {
- UnknownPackedEnum(msg, table, FastDecodeTag(saved_tag), value);
+ AddUnknownEnum(msg, table, FastDecodeTag(saved_tag), value);
} else {
field->Add(value);
}
@@ -1210,18 +1417,18 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularEnumSmallRange(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
uint8_t v = ptr[sizeof(TagType)];
if (PROTOBUF_PREDICT_FALSE(min > v || v > data.aux_idx())) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
RefAt<int32_t>(msg, data.offset()) = v;
ptr += sizeof(TagType) + 1;
hasbits |= (uint64_t{1} << data.hasbit_idx());
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastEr0S1(PROTOBUF_TC_PARAM_DECL) {
@@ -1252,7 +1459,7 @@
PROTOBUF_MUSTTAIL return PackedEnumSmallRange<TagType, min>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
auto& field = RefAt<RepeatedField<int32_t>>(msg, data.offset());
@@ -1261,14 +1468,14 @@
do {
uint8_t v = ptr[sizeof(TagType)];
if (PROTOBUF_PREDICT_FALSE(min > v || v > max)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
field.Add(static_cast<int32_t>(v));
ptr += sizeof(TagType) + 1;
if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
- PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastEr0R1(PROTOBUF_TC_PARAM_DECL) {
@@ -1297,7 +1504,7 @@
PROTOBUF_MUSTTAIL return RepeatedEnumSmallRange<TagType, min>(
PROTOBUF_TC_PARAM_PASS);
} else {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
@@ -1312,7 +1519,7 @@
return ctx->ReadPackedVarint(ptr, [=](int32_t v) {
if (PROTOBUF_PREDICT_FALSE(min > v || v > max)) {
- UnknownPackedEnum(msg, table, FastDecodeTag(saved_tag), v);
+ AddUnknownEnum(msg, table, FastDecodeTag(saved_tag), v);
} else {
field->Add(v);
}
@@ -1387,7 +1594,7 @@
PROTOBUF_ALWAYS_INLINE const char* TcParser::SingularString(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
auto saved_tag = UnalignedLoad<TagType>(ptr);
ptr += sizeof(TagType);
@@ -1400,20 +1607,24 @@
} else {
ptr = ReadStringNoArena(msg, ptr, ctx, data.aux_idx(), table, field);
}
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
switch (utf8) {
case kNoUtf8:
#ifdef NDEBUG
case kUtf8ValidateOnly:
#endif
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
default:
if (PROTOBUF_PREDICT_TRUE(IsValidUTF8(field))) {
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
ReportFastUtf8Error(FastDecodeTag(saved_tag), table);
- return utf8 == kUtf8 ? Error(PROTOBUF_TC_PARAM_PASS)
- : ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ if (utf8 == kUtf8) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
}
@@ -1447,49 +1658,49 @@
// Inlined string variants:
const char* TcParser::FastBiS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastBiS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastSiS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastSiS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUiS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUiS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
// Corded string variants:
const char* TcParser::FastBcS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastBcS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastScS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastScS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUcS1(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const char* TcParser::FastUcS2(PROTOBUF_TC_PARAM_DECL) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <typename TagType, typename FieldType, TcParser::Utf8Type utf8>
PROTOBUF_ALWAYS_INLINE const char* TcParser::RepeatedString(
PROTOBUF_TC_PARAM_DECL) {
if (PROTOBUF_PREDICT_FALSE(data.coded_tag<TagType>() != 0)) {
- PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MiniParse(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
const auto expected_tag = UnalignedLoad<TagType>(ptr);
auto& field = RefAt<FieldType>(msg, data.offset());
@@ -1522,7 +1733,7 @@
ptr = ParseRepeatedStringOnce(ptr, arena, serial_arena, ctx, field);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr || !validate_last_string())) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
@@ -1532,12 +1743,12 @@
std::string* str = field.Add();
ptr = InlineGreedyStringParser(str, ptr, ctx);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr || !validate_last_string())) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
} while (UnalignedLoad<TagType>(ptr) == expected_tag);
}
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::FastBR1(PROTOBUF_TC_PARAM_DECL) {
@@ -1712,7 +1923,7 @@
RefAt<uint32_t>(base, entry.offset) = UnalignedLoad<uint32_t>(ptr);
ptr += sizeof(uint32_t);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpRepeatedFixed(
@@ -1761,7 +1972,7 @@
} while (next_tag == decoded_tag);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpPackedFixed(PROTOBUF_TC_PARAM_DECL) {
@@ -1790,9 +2001,9 @@
}
if (ptr == nullptr) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <bool is_split>
@@ -1817,7 +2028,9 @@
const char* ptr2 = ptr; // save for unknown enum case
uint64_t tmp;
ptr = ParseVarint(ptr, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
// Transform and/or validate the value
uint16_t rep = type_card & field_layout::kRepMask;
@@ -1829,7 +2042,7 @@
if (is_validated_enum) {
if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
ptr = ptr2;
- PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MpUnknownEnumFallback(PROTOBUF_TC_PARAM_PASS);
}
} else if (is_zigzag) {
tmp = WireFormatLite::ZigZagDecode32(static_cast<uint32_t>(tmp));
@@ -1854,7 +2067,7 @@
RefAt<bool>(base, entry.offset) = static_cast<bool>(tmp);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpRepeatedVarint(
@@ -1884,11 +2097,15 @@
do {
uint64_t tmp;
ptr = ParseVarint(ptr2, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
field.Add(is_zigzag ? WireFormatLite::ZigZagDecode64(tmp) : tmp);
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
- if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr2 == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
} while (next_tag == decoded_tag);
} else if (rep == field_layout::kRep32Bits) {
auto& field = RefAt<RepeatedField<uint32_t>>(msg, entry.offset);
@@ -1897,11 +2114,14 @@
do {
uint64_t tmp;
ptr = ParseVarint(ptr2, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
if (is_validated_enum) {
if (!EnumIsValidAux(tmp, xform_val, *table->field_aux(&entry))) {
ptr = ptr2;
- PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return MpUnknownEnumFallback(
+ PROTOBUF_TC_PARAM_PASS);
}
} else if (is_zigzag) {
tmp = WireFormatLite::ZigZagDecode32(tmp);
@@ -1909,7 +2129,9 @@
field.Add(tmp);
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
- if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr2 == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
} while (next_tag == decoded_tag);
} else {
ABSL_DCHECK_EQ(rep, static_cast<uint16_t>(field_layout::kRep8Bits));
@@ -1919,15 +2141,19 @@
do {
uint64_t tmp;
ptr = ParseVarint(ptr2, &tmp);
- if (ptr == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
field.Add(static_cast<bool>(tmp));
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
- if (ptr2 == nullptr) return Error(PROTOBUF_TC_PARAM_PASS);
+ if (ptr2 == nullptr) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
} while (next_tag == decoded_tag);
}
- PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_NOINLINE const char* TcParser::MpPackedVarint(PROTOBUF_TC_PARAM_DECL) {
@@ -1959,7 +2185,7 @@
const TcParseTableBase::FieldAux aux = *table->field_aux(entry.aux_idx);
return ctx->ReadPackedVarint(ptr, [=](int32_t value) {
if (!EnumIsValidAux(value, xform_val, aux)) {
- UnknownPackedEnum(msg, table, data.tag(), value);
+ AddUnknownEnum(msg, table, data.tag(), value);
} else {
field->Add(value);
}
@@ -1978,7 +2204,7 @@
ptr, [field](uint64_t value) { field->Add(value); });
}
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
bool TcParser::MpVerifyUtf8(absl::string_view wire_bytes,
@@ -2018,10 +2244,6 @@
}
const uint16_t xform_val = type_card & field_layout::kTvMask;
const uint16_t rep = type_card & field_layout::kRepMask;
- if (rep == field_layout::kRepIString) {
- // TODO(b/198211897): support InilnedStringField.
- PROTOBUF_MUSTTAIL return table->fallback(PROTOBUF_TC_PARAM_PASS);
- }
// Mark the field as present:
const bool is_oneof = card == field_layout::kFcOneof;
@@ -2051,14 +2273,15 @@
}
case field_layout::kRepIString: {
+ ABSL_DCHECK(false);
break;
}
}
if (ptr == nullptr || !is_valid) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
PROTOBUF_ALWAYS_INLINE const char* TcParser::ParseRepeatedStringOnce(
@@ -2105,7 +2328,7 @@
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr ||
!MpVerifyUtf8(field[field.size() - 1],
table, entry, xform_val))) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
@@ -2118,7 +2341,7 @@
if (PROTOBUF_PREDICT_FALSE(
ptr == nullptr ||
!MpVerifyUtf8(*str, table, entry, xform_val))) {
- return Error(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
if (!ctx->DataAvailable(ptr)) break;
ptr2 = ReadTag(ptr, &next_tag);
@@ -2135,7 +2358,7 @@
#endif
}
- return ToParseLoop(PROTOBUF_TC_PARAM_PASS);
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
}
template <bool is_split>
@@ -2271,6 +2494,332 @@
}
}
+static void SerializeMapKey(const NodeBase* node, MapTypeCard type_card,
+ io::CodedOutputStream& coded_output) {
+ switch (type_card.wiretype()) {
+ case WireFormatLite::WIRETYPE_VARINT:
+ switch (type_card.cpp_type()) {
+ case MapTypeCard::kBool:
+ WireFormatLite::WriteBool(
+ 1, static_cast<const KeyNode<bool>*>(node)->key(), &coded_output);
+ break;
+ case MapTypeCard::k32:
+ if (type_card.is_zigzag()) {
+ WireFormatLite::WriteSInt32(
+ 1, static_cast<const KeyNode<uint32_t>*>(node)->key(),
+ &coded_output);
+ } else {
+ WireFormatLite::WriteInt32(
+ 1, static_cast<const KeyNode<uint32_t>*>(node)->key(),
+ &coded_output);
+ }
+ break;
+ case MapTypeCard::k64:
+ if (type_card.is_zigzag()) {
+ WireFormatLite::WriteSInt64(
+ 1, static_cast<const KeyNode<uint64_t>*>(node)->key(),
+ &coded_output);
+ } else {
+ WireFormatLite::WriteInt64(
+ 1, static_cast<const KeyNode<uint64_t>*>(node)->key(),
+ &coded_output);
+ }
+ break;
+ default:
+ PROTOBUF_ASSUME(false);
+ }
+ break;
+ case WireFormatLite::WIRETYPE_FIXED32:
+ WireFormatLite::WriteFixed32(
+ 1, static_cast<const KeyNode<uint32_t>*>(node)->key(), &coded_output);
+ break;
+ case WireFormatLite::WIRETYPE_FIXED64:
+ WireFormatLite::WriteFixed64(
+ 1, static_cast<const KeyNode<uint64_t>*>(node)->key(), &coded_output);
+ break;
+ case WireFormatLite::WIRETYPE_LENGTH_DELIMITED:
+ // We should never have a message here. They can only be values maps.
+ ABSL_DCHECK_EQ(+type_card.cpp_type(), +MapTypeCard::kString);
+ WireFormatLite::WriteString(
+ 1, static_cast<const KeyNode<std::string>*>(node)->key(),
+ &coded_output);
+ break;
+ default:
+ PROTOBUF_ASSUME(false);
+ }
+}
+
+void TcParser::WriteMapEntryAsUnknown(MessageLite* msg,
+ const TcParseTableBase* table,
+ uint32_t tag, NodeBase* node,
+ MapAuxInfo map_info) {
+ std::string serialized;
+ {
+ io::StringOutputStream string_output(&serialized);
+ io::CodedOutputStream coded_output(&string_output);
+ SerializeMapKey(node, map_info.key_type_card, coded_output);
+ // The mapped_type is always an enum here.
+ ABSL_DCHECK(map_info.value_is_validated_enum);
+ WireFormatLite::WriteInt32(2,
+ *reinterpret_cast<int32_t*>(
+ node->GetVoidValue(map_info.node_size_info)),
+ &coded_output);
+ }
+ GetUnknownFieldOps(table).write_length_delimited(msg, tag >> 3, serialized);
+}
+
+PROTOBUF_ALWAYS_INLINE inline void TcParser::InitializeMapNodeEntry(
+ void* obj, MapTypeCard type_card, UntypedMapBase& map,
+ const TcParseTableBase::FieldAux* aux) {
+ switch (type_card.cpp_type()) {
+ case MapTypeCard::kBool:
+ memset(obj, 0, sizeof(bool));
+ break;
+ case MapTypeCard::k32:
+ memset(obj, 0, sizeof(uint32_t));
+ break;
+ case MapTypeCard::k64:
+ memset(obj, 0, sizeof(uint64_t));
+ break;
+ case MapTypeCard::kString:
+ Arena::CreateInArenaStorage(reinterpret_cast<std::string*>(obj),
+ map.arena());
+ break;
+ case MapTypeCard::kMessage:
+ aux[1].create_in_arena(map.arena(), reinterpret_cast<MessageLite*>(obj));
+ break;
+ default:
+ PROTOBUF_ASSUME(false);
+ }
+}
+
+PROTOBUF_NOINLINE void TcParser::DestroyMapNode(NodeBase* node,
+ MapAuxInfo map_info,
+ UntypedMapBase& map) {
+ if (map_info.key_type_card.cpp_type() == MapTypeCard::kString) {
+ static_cast<std::string*>(node->GetVoidKey())->~basic_string();
+ }
+ if (map_info.value_type_card.cpp_type() == MapTypeCard::kString) {
+ static_cast<std::string*>(node->GetVoidValue(map_info.node_size_info))
+ ->~basic_string();
+ } else if (map_info.value_type_card.cpp_type() == MapTypeCard::kMessage) {
+ static_cast<MessageLite*>(node->GetVoidValue(map_info.node_size_info))
+ ->~MessageLite();
+ }
+ map.DeallocNode(node, map_info.node_size_info);
+}
+
+template <typename T>
+const char* ReadFixed(void* obj, const char* ptr) {
+ auto v = UnalignedLoad<T>(ptr);
+ ptr += sizeof(v);
+ memcpy(obj, &v, sizeof(v));
+ return ptr;
+}
+
+const char* TcParser::ParseOneMapEntry(
+ NodeBase* node, const char* ptr, ParseContext* ctx,
+ const TcParseTableBase::FieldAux* aux, const TcParseTableBase* table,
+ const TcParseTableBase::FieldEntry& entry) {
+ using WFL = WireFormatLite;
+
+ const auto map_info = aux[0].map_info;
+ const uint8_t key_tag = WFL::MakeTag(1, map_info.key_type_card.wiretype());
+ const uint8_t value_tag =
+ WFL::MakeTag(2, map_info.value_type_card.wiretype());
+
+ while (!ctx->Done(&ptr)) {
+ uint32_t inner_tag = ptr[0];
+
+ if (PROTOBUF_PREDICT_FALSE(inner_tag != key_tag &&
+ inner_tag != value_tag)) {
+ // Do a full parse and check again in case the tag has non-canonical
+ // encoding.
+ ptr = ReadTag(ptr, &inner_tag);
+ if (PROTOBUF_PREDICT_FALSE(inner_tag != key_tag &&
+ inner_tag != value_tag)) {
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+
+ if (inner_tag == 0 || (inner_tag & 7) == WFL::WIRETYPE_END_GROUP) {
+ ctx->SetLastTag(inner_tag);
+ break;
+ }
+
+ ptr = UnknownFieldParse(inner_tag, nullptr, ptr, ctx);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+ continue;
+ }
+ } else {
+ ++ptr;
+ }
+
+ MapTypeCard type_card;
+ void* obj;
+ if (inner_tag == key_tag) {
+ type_card = map_info.key_type_card;
+ obj = node->GetVoidKey();
+ } else {
+ type_card = map_info.value_type_card;
+ obj = node->GetVoidValue(map_info.node_size_info);
+ }
+
+ switch (type_card.wiretype()) {
+ case WFL::WIRETYPE_VARINT:
+ uint64_t tmp;
+ ptr = ParseVarint(ptr, &tmp);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+ switch (type_card.cpp_type()) {
+ case MapTypeCard::kBool:
+ *reinterpret_cast<bool*>(obj) = static_cast<bool>(tmp);
+ continue;
+ case MapTypeCard::k32: {
+ uint32_t v = static_cast<uint32_t>(tmp);
+ if (type_card.is_zigzag()) v = WFL::ZigZagDecode32(v);
+ memcpy(obj, &v, sizeof(v));
+ continue;
+ }
+ case MapTypeCard::k64:
+ if (type_card.is_zigzag()) tmp = WFL::ZigZagDecode64(tmp);
+ memcpy(obj, &tmp, sizeof(tmp));
+ continue;
+ default:
+ PROTOBUF_ASSUME(false);
+ }
+ case WFL::WIRETYPE_FIXED32:
+ ptr = ReadFixed<uint32_t>(obj, ptr);
+ continue;
+ case WFL::WIRETYPE_FIXED64:
+ ptr = ReadFixed<uint64_t>(obj, ptr);
+ continue;
+ case WFL::WIRETYPE_LENGTH_DELIMITED:
+ if (type_card.cpp_type() == MapTypeCard::kString) {
+ const int size = ReadSize(&ptr);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+ std::string* str = reinterpret_cast<std::string*>(obj);
+ ptr = ctx->ReadString(ptr, size, str);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+ bool do_utf8_check = map_info.fail_on_utf8_failure;
+#ifndef NDEBUG
+ do_utf8_check |= map_info.log_debug_utf8_failure;
+#endif
+ if (type_card.is_utf8() && do_utf8_check &&
+ !utf8_range::IsStructurallyValid(*str)) {
+ PrintUTF8ErrorLog(MessageName(table), FieldName(table, &entry),
+ "parsing", false);
+ if (map_info.fail_on_utf8_failure) {
+ return nullptr;
+ }
+ }
+ continue;
+ } else {
+ ABSL_DCHECK_EQ(+type_card.cpp_type(), +MapTypeCard::kMessage);
+ ABSL_DCHECK_EQ(inner_tag, value_tag);
+ ptr = ctx->ParseMessage(reinterpret_cast<MessageLite*>(obj), ptr);
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;
+ continue;
+ }
+ default:
+ PROTOBUF_ASSUME(false);
+ }
+ }
+ return ptr;
+}
+
+PROTOBUF_NOINLINE const char* TcParser::MpMap(PROTOBUF_TC_PARAM_DECL) {
+ const auto& entry = RefAt<FieldEntry>(table, data.entry_offset());
+ // `aux[0]` points into a MapAuxInfo.
+ // If we have a message mapped_type aux[1] points into a `create_in_arena`.
+ // If we have a validated enum mapped_type aux[1] point into a
+ // `enum_validator`.
+ const auto* aux = table->field_aux(&entry);
+ const auto map_info = aux[0].map_info;
+
+ if (PROTOBUF_PREDICT_FALSE(!map_info.is_supported ||
+ (data.tag() & 7) !=
+ WireFormatLite::WIRETYPE_LENGTH_DELIMITED)) {
+ PROTOBUF_MUSTTAIL return MpFallback(PROTOBUF_TC_PARAM_PASS);
+ }
+
+ // When using LITE, the offset points directly into the Map<> object.
+ // Otherwise, it points into a MapField and we must synchronize with
+ // reflection. It is done by calling the MutableMap() virtual function on the
+ // field's base class.
+ UntypedMapBase& map =
+ map_info.use_lite
+ ? RefAt<UntypedMapBase>(msg, entry.offset)
+ : *RefAt<MapFieldBaseForParse>(msg, entry.offset).MutableMap();
+
+ const uint32_t saved_tag = data.tag();
+
+ while (true) {
+ NodeBase* node = map.AllocNode(map_info.node_size_info);
+
+ InitializeMapNodeEntry(node->GetVoidKey(), map_info.key_type_card, map,
+ aux);
+ InitializeMapNodeEntry(node->GetVoidValue(map_info.node_size_info),
+ map_info.value_type_card, map, aux);
+
+ ptr = ctx->ParseLengthDelimitedInlined(ptr, [&](const char* ptr) {
+ return ParseOneMapEntry(node, ptr, ctx, aux, table, entry);
+ });
+
+ if (PROTOBUF_PREDICT_TRUE(ptr != nullptr)) {
+ if (PROTOBUF_PREDICT_FALSE(
+ map_info.value_is_validated_enum &&
+ !aux[1].enum_validator(*static_cast<int32_t*>(
+ node->GetVoidValue(map_info.node_size_info))))) {
+ WriteMapEntryAsUnknown(msg, table, saved_tag, node, map_info);
+ } else {
+ // Done parsing the node, try to insert it.
+ // If it overwrites something we get old node back to destroy it.
+ switch (map_info.key_type_card.cpp_type()) {
+ case MapTypeCard::kBool:
+ node = static_cast<KeyMapBase<bool>&>(map).InsertOrReplaceNode(
+ static_cast<KeyMapBase<bool>::KeyNode*>(node));
+ break;
+ case MapTypeCard::k32:
+ node = static_cast<KeyMapBase<uint32_t>&>(map).InsertOrReplaceNode(
+ static_cast<KeyMapBase<uint32_t>::KeyNode*>(node));
+ break;
+ case MapTypeCard::k64:
+ node = static_cast<KeyMapBase<uint64_t>&>(map).InsertOrReplaceNode(
+ static_cast<KeyMapBase<uint64_t>::KeyNode*>(node));
+ break;
+ case MapTypeCard::kString:
+ node =
+ static_cast<KeyMapBase<std::string>&>(map).InsertOrReplaceNode(
+ static_cast<KeyMapBase<std::string>::KeyNode*>(node));
+ break;
+ default:
+ PROTOBUF_ASSUME(false);
+ }
+ }
+ }
+
+ // Destroy the node if we have it.
+ // It could be because we failed to parse, or because insertion returned
+ // an overwritten node.
+ if (PROTOBUF_PREDICT_FALSE(node != nullptr && map.arena() == nullptr)) {
+ DestroyMapNode(node, map_info, map);
+ }
+
+ if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) {
+ PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+
+ if (PROTOBUF_PREDICT_FALSE(!ctx->DataAvailable(ptr))) {
+ PROTOBUF_MUSTTAIL return ToParseLoop(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+ }
+
+ uint32_t next_tag;
+ const char* ptr2 = ReadTagInlined(ptr, &next_tag);
+ if (next_tag != saved_tag) break;
+ ptr = ptr2;
+ }
+
+ PROTOBUF_MUSTTAIL return ToTagDispatch(PROTOBUF_TC_PARAM_NO_DATA_PASS);
+}
+
} // namespace internal
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/generated_message_tctable_lite_test.cc b/src/google/protobuf/generated_message_tctable_lite_test.cc
index e242d83..12aeced 100644
--- a/src/google/protobuf/generated_message_tctable_lite_test.cc
+++ b/src/google/protobuf/generated_message_tctable_lite_test.cc
@@ -94,7 +94,7 @@
const TcParseTable<0, 1, 0, 0, 2> parse_table = {
{
kHasBitsOffset, //
- 0, 0, 0, // no _extensions_
+ 0, // no _extensions_
1, 0, // max_field_number, fast_idx_mask
offsetof(decltype(parse_table), field_lookup_table),
0xFFFFFFFF - 1, // skipmap
@@ -125,7 +125,7 @@
// clang-format on
uint8_t serialize_buffer[64];
- for (int size : {8, 32, 64, -8, -32, -64}) {
+ for (int size : {8, 32, 64}) {
SCOPED_TRACE(size);
auto next_i = [](uint64_t i) {
// if i + 1 is a power of two, return that.
@@ -192,21 +192,12 @@
case 8:
fn = &TcParser::FastV8S1;
break;
- case -8:
- fn = &TcParser::FastTV8S1<kFieldOffset, kHasBitIndex>;
- break;
case 32:
fn = &TcParser::FastV32S1;
break;
- case -32:
- fn = &TcParser::FastTV32S1<uint32_t, kFieldOffset, kHasBitIndex>;
- break;
case 64:
fn = &TcParser::FastV64S1;
break;
- case -64:
- fn = &TcParser::FastTV64S1<uint64_t, kFieldOffset, kHasBitIndex>;
- break;
}
fallback_ptr_received = absl::nullopt;
fallback_hasbits_received = absl::nullopt;
@@ -215,7 +206,6 @@
Xor2SerializedBytes(parse_table.fast_entries[0].bits, ptr),
&parse_table.header, /*hasbits=*/0);
switch (size) {
- case -8:
case 8: {
if (end_ptr == nullptr) {
// If end_ptr is nullptr, that means the FastParser gave up and
@@ -240,7 +230,6 @@
EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i)) //
<< " hex: " << absl::StrCat(absl::Hex(actual_field));
}; break;
- case -32:
case 32: {
ASSERT_TRUE(end_ptr);
ASSERT_EQ(end_ptr - ptr, serialized.size());
@@ -249,7 +238,6 @@
EXPECT_EQ(actual_field, static_cast<decltype(actual_field)>(i)) //
<< " hex: " << absl::StrCat(absl::Hex(actual_field));
}; break;
- case -64:
case 64: {
ASSERT_EQ(end_ptr - ptr, serialized.size());
@@ -297,9 +285,9 @@
TcParseTable<0, 3, 0, 0, 2> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 0, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 0, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - 7, // 7 = fields 1, 2, and 3.
offsetof(decltype(table), field_names),
@@ -364,9 +352,9 @@
TcParseTable<0, 5, 0, 0, 8> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 111, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 111, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1 << 1) - (1 << 2) // fields 2, 3
- (1 << 3) - (1 << 4), // fields 4, 5
@@ -405,9 +393,9 @@
TcParseTable<0, 6, 0, 0, 8> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 111, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 111, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4) - (1<<6), // 1,3-5,7
offsetof(decltype(table), field_entries),
@@ -451,9 +439,9 @@
TcParseTable<0, 10, 0, 0, 8> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 70, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 70, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1<<0) - (1<<2) - (1<<3) - (1<<4) // 1, 3, 4, 5, 6
- (1<<5) - (1<<7) - (1<<8) - (1<<10) // 8, 9, 11, 12
@@ -497,9 +485,9 @@
TcParseTable<0, 3, 0, 15, 2> table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 3, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 3, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF - (1<<0) - (1<<1) - (1<<2), // fields 1, 2, 3
offsetof(decltype(table), field_entries),
@@ -547,9 +535,9 @@
TableType table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
- 0, // max_field_number
- 0, // fast_idx_mask,
+ 0, 0, // has_bits_offset, extensions
+ 0, // max_field_number
+ 0, // fast_idx_mask,
offsetof(decltype(table), field_lookup_table),
0xFFFFFFFF, // no fields
offsetof(decltype(table), field_names), // no field_entries
@@ -598,7 +586,7 @@
const TcParseTable<5, 134, 5, 2176, 55> test_all_types_table = {
// header:
{
- 0, 0, 0, 0, // has_bits_offset, extensions
+ 0, 0, // has_bits_offset, extensions
418, 248, // max_field_number, fast_idx_mask
offsetof(decltype(test_all_types_table), field_lookup_table),
977895424, // skipmap for fields 1-15,18-19,21-22,24-25,27,31-32
diff --git a/src/google/protobuf/lazy_field_heavy.cc b/src/google/protobuf/lazy_field_heavy.cc
new file mode 100644
index 0000000..02d4d2e
--- /dev/null
+++ b/src/google/protobuf/lazy_field_heavy.cc
@@ -0,0 +1,105 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2023 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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 "google/protobuf/lazy_field.h"
+#include "google/protobuf/message.h"
+
+namespace google {
+namespace protobuf {
+namespace internal {
+namespace {
+class ByFactory {
+ public:
+ explicit ByFactory(const Descriptor* type, MessageFactory* factory)
+ : type_(type), factory_(factory) {}
+
+ Message* New(Arena* arena) const {
+ return factory_->GetPrototype(type_)->New(arena);
+ }
+
+ const Message& Default() const { return *factory_->GetPrototype(type_); }
+
+ private:
+ const Descriptor* type_;
+ MessageFactory* factory_;
+};
+
+} // namespace
+
+const Message& LazyField::GetDynamic(const Descriptor* type,
+ MessageFactory* factory,
+ Arena* arena) const {
+ return DownCast<const Message&>(GetGeneric(ByFactory(type, factory), arena));
+}
+
+Message* LazyField::MutableDynamic(const Descriptor* type,
+ MessageFactory* factory, Arena* arena) {
+ return DownCast<Message*>(
+ MutableGeneric(ByFactory(type, factory), arena, nullptr));
+}
+
+Message* LazyField::ReleaseDynamic(const Descriptor* type,
+ MessageFactory* factory, Arena* arena) {
+ return DownCast<Message*>(ReleaseGeneric(ByFactory(type, factory), arena));
+}
+
+Message* LazyField::UnsafeArenaReleaseDynamic(const Descriptor* type,
+ MessageFactory* factory,
+ Arena* arena) {
+ return DownCast<Message*>(
+ UnsafeArenaReleaseGeneric(ByFactory(type, factory), arena));
+}
+
+size_t LazyField::SpaceUsedExcludingSelfLong() const {
+ // absl::Cord::EstimatedMemoryUsage counts itself that should be excluded
+ // because sizeof(Cord) is already counted in self.
+ size_t total_size = unparsed_.EstimatedMemoryUsage() - sizeof(absl::Cord);
+ switch (GetLogicalState()) {
+ case LogicalState::kClearExposed:
+ case LogicalState::kNoParseRequired:
+ case LogicalState::kDirty:
+ case LogicalState::kParseError: {
+ const auto* message = raw_.load(std::memory_order_relaxed).message();
+ total_size += DownCast<const Message*>(message)->SpaceUsedLong();
+ } break;
+ case LogicalState::kClear:
+ case LogicalState::kParseRequired:
+ // We may have a `Message*` here, but we cannot safely access it
+ // because, a racing SharedInit could delete it out from under us.
+ // Other states in this structure are already passed kSharedInit and are
+ // thus safe.
+ break; // Nothing to add.
+ }
+ return total_size;
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index e3bc9ec..99369d3 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -90,6 +90,8 @@
WireFormatLite::FieldType value_wire_type>
class MapField;
+struct MapTestPeer;
+
template <typename Key, typename T>
class TypeDefinedMapFieldBase;
@@ -291,11 +293,30 @@
using key_arg = K;
};
+enum class MapNodeSizeInfoT : uint32_t;
+inline uint16_t SizeFromInfo(MapNodeSizeInfoT node_size_info) {
+ return static_cast<uint16_t>(static_cast<uint32_t>(node_size_info) >> 16);
+}
+inline uint16_t ValueOffsetFromInfo(MapNodeSizeInfoT node_size_info) {
+ return static_cast<uint16_t>(static_cast<uint32_t>(node_size_info) >> 0);
+}
+constexpr MapNodeSizeInfoT MakeNodeInfo(uint16_t size, uint16_t value_offset) {
+ return static_cast<MapNodeSizeInfoT>((static_cast<uint32_t>(size) << 16) |
+ value_offset);
+}
+
struct NodeBase {
// Align the node to allow KeyNode to predict the location of the key.
// This way sizeof(NodeBase) contains any possible padding it was going to
// have between NodeBase and the key.
alignas(kMaxMessageAlignment) NodeBase* next;
+
+ void* GetVoidKey() { return this + 1; }
+ const void* GetVoidKey() const { return this + 1; }
+
+ void* GetVoidValue(MapNodeSizeInfoT size_info) {
+ return reinterpret_cast<char*>(this) + ValueOffsetFromInfo(size_info);
+ }
};
inline NodeBase* EraseFromLinkedList(NodeBase* item, NodeBase* head) {
@@ -474,6 +495,7 @@
protected:
friend class TcParser;
+ friend struct MapTestPeer;
struct NodeAndBucket {
NodeBase* node;
@@ -538,11 +560,19 @@
using AllocFor = absl::allocator_traits<Allocator>::template rebind_alloc<T>;
// Alignment of the nodes is the same as alignment of NodeBase.
+ NodeBase* AllocNode(MapNodeSizeInfoT size_info) {
+ return AllocNode(SizeFromInfo(size_info));
+ }
+
NodeBase* AllocNode(size_t node_size) {
PROTOBUF_ASSUME(node_size % sizeof(NodeBase) == 0);
return AllocFor<NodeBase>(alloc_).allocate(node_size / sizeof(NodeBase));
}
+ void DeallocNode(NodeBase* node, MapNodeSizeInfoT size_info) {
+ DeallocNode(node, SizeFromInfo(size_info));
+ }
+
void DeallocNode(NodeBase* node, size_t node_size) {
PROTOBUF_ASSUME(node_size % sizeof(NodeBase) == 0);
AllocFor<NodeBase>(alloc_).deallocate(node, node_size / sizeof(NodeBase));
@@ -595,6 +625,17 @@
Allocator alloc_;
};
+// Base class used by TcParser to extract the map object from a map field.
+// We keep it here to avoid a dependency into map_field.h from the main TcParser
+// code, since that would bring in Message too.
+class MapFieldBaseForParse {
+ public:
+ virtual UntypedMapBase* MutableMap() = 0;
+
+ protected:
+ ~MapFieldBaseForParse() = default;
+};
+
// The value might be of different signedness, so use memcpy to extract it.
template <typename T, std::enable_if_t<std::is_integral<T>::value, int> = 0>
T ReadKey(const void* ptr) {
@@ -608,6 +649,12 @@
return *reinterpret_cast<const T*>(ptr);
}
+template <typename Key>
+struct KeyNode : NodeBase {
+ static constexpr size_t kOffset = sizeof(NodeBase);
+ decltype(auto) key() const { return ReadKey<Key>(GetVoidKey()); }
+};
+
// KeyMapBase is a chaining hash map with the additional feature that some
// buckets can be converted to use an ordered container. This ensures O(lg n)
// bounds on find, insert, and erase, while avoiding the overheads of ordered
@@ -644,12 +691,7 @@
using UntypedMapBase::UntypedMapBase;
protected:
- struct KeyNode : NodeBase {
- static constexpr size_t kOffset = sizeof(NodeBase);
- decltype(auto) key() const {
- return ReadKey<Key>(reinterpret_cast<const char*>(this) + kOffset);
- }
- };
+ using KeyNode = internal::KeyNode<Key>;
// Trees. The payload type is a copy of Key, so that we can query the tree
// with Keys that are not in any particular data structure.
@@ -728,6 +770,9 @@
hasher hash_function() const { return {}; }
protected:
+ friend class TcParser;
+ friend struct MapTestPeer;
+
PROTOBUF_NOINLINE void erase_no_destroy(size_type b, KeyNode* node) {
TreeIterator tree_it;
const bool is_list = revalidate_if_necessary(b, node, &tree_it);
@@ -785,6 +830,25 @@
return {nullptr, b};
}
+ // Insert the given node.
+ // If the key is a duplicate, it inserts the new node and returns the old one.
+ // Gives ownership to the caller.
+ // If the key is unique, it returns `nullptr`.
+ KeyNode* InsertOrReplaceNode(KeyNode* node) {
+ KeyNode* to_erase = nullptr;
+ auto p = this->FindHelper(node->key());
+ if (p.node != nullptr) {
+ erase_no_destroy(p.bucket, static_cast<KeyNode*>(p.node));
+ to_erase = static_cast<KeyNode*>(p.node);
+ } else if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) {
+ p = FindHelper(node->key());
+ }
+ const size_type b = p.bucket; // bucket number
+ InsertUnique(b, node);
+ ++num_elements_;
+ return to_erase;
+ }
+
// Insert the given Node in bucket b. If that would make bucket b too big,
// and bucket b is not a tree, create a tree for buckets b.
// Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct
@@ -1417,6 +1481,10 @@
// Linked-list nodes, as one would expect for a chaining hash table.
struct Node : Base::KeyNode {
+ static constexpr internal::MapNodeSizeInfoT size_info() {
+ return internal::MakeNodeInfo(sizeof(Node),
+ PROTOBUF_FIELD_OFFSET(Node, kv.second));
+ }
value_type kv;
};
@@ -1543,6 +1611,8 @@
internal::WireFormatLite::FieldType key_wire_type,
internal::WireFormatLite::FieldType value_wire_type>
friend class internal::MapFieldLite;
+ friend class internal::TcParser;
+ friend struct internal::MapTestPeer;
};
namespace internal {
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h
index 4529b0e..a6f5f90 100644
--- a/src/google/protobuf/map_field.h
+++ b/src/google/protobuf/map_field.h
@@ -336,7 +336,7 @@
// This class provides access to map field using reflection, which is the same
// as those provided for RepeatedPtrField<Message>. It is used for internal
// reflection implementation only. Users should never use this directly.
-class PROTOBUF_EXPORT MapFieldBase {
+class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
public:
MapFieldBase()
: arena_(nullptr), repeated_field_(nullptr), state_(STATE_MODIFIED_MAP) {}
@@ -523,7 +523,9 @@
bool EqualIterator(const MapIterator& a, const MapIterator& b) const override;
virtual const Map<Key, T>& GetMap() const = 0;
- virtual Map<Key, T>* MutableMap() = 0;
+ // This overrides the base's method to specialize the signature via
+ // covariance, but we do not yet provide an implementation here, so `= 0`.
+ Map<Key, T>* MutableMap() override = 0;
protected:
typename Map<Key, T>::const_iterator& InternalGetIterator(
@@ -543,19 +545,19 @@
// internal generated message implementation only. Users should never use this
// directly.
template <typename Derived, typename Key, typename T,
- WireFormatLite::FieldType kKeyFieldType,
- WireFormatLite::FieldType kValueFieldType>
+ WireFormatLite::FieldType kKeyFieldType_,
+ WireFormatLite::FieldType kValueFieldType_>
class MapField : public TypeDefinedMapFieldBase<Key, T> {
// Provide utilities to parse/serialize key/value. Provide utilities to
// manipulate internal stored type.
- typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
- typedef MapTypeHandler<kValueFieldType, T> ValueTypeHandler;
+ typedef MapTypeHandler<kKeyFieldType_, Key> KeyTypeHandler;
+ typedef MapTypeHandler<kValueFieldType_, T> ValueTypeHandler;
// Define message type for internal repeated field.
typedef Derived EntryType;
// Define abbreviation for parent MapFieldLite
- typedef MapFieldLite<Derived, Key, T, kKeyFieldType, kValueFieldType>
+ typedef MapFieldLite<Derived, Key, T, kKeyFieldType_, kValueFieldType_>
MapFieldLiteType;
// Enum needs to be handled differently from other types because it has
@@ -567,6 +569,8 @@
public:
typedef Map<Key, T> MapType;
+ static constexpr WireFormatLite::FieldType kKeyFieldType = kKeyFieldType_;
+ static constexpr WireFormatLite::FieldType kValueFieldType = kValueFieldType_;
MapField() : impl_() {}
MapField(const MapField&) = delete;
diff --git a/src/google/protobuf/map_field_lite.h b/src/google/protobuf/map_field_lite.h
index dd41c18..9ecbf8b 100644
--- a/src/google/protobuf/map_field_lite.h
+++ b/src/google/protobuf/map_field_lite.h
@@ -67,6 +67,8 @@
public:
typedef Map<Key, T> MapType;
+ static constexpr WireFormatLite::FieldType kKeyFieldType = key_wire_type;
+ static constexpr WireFormatLite::FieldType kValueFieldType = value_wire_type;
constexpr MapFieldLite() : map_() {}
explicit MapFieldLite(Arena* arena) : map_(arena) {}
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index f988d6b..f7e5b32 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -76,6 +76,7 @@
void SetRepeatedDirty() {
state_.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
}
+ UntypedMapBase* MutableMap() override { return nullptr; }
bool ContainsMapKey(const MapKey& map_key) const override { return false; }
bool InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) override {
diff --git a/src/google/protobuf/map_proto2_unittest.proto b/src/google/protobuf/map_proto2_unittest.proto
index 9cda195..ade970d 100644
--- a/src/google/protobuf/map_proto2_unittest.proto
+++ b/src/google/protobuf/map_proto2_unittest.proto
@@ -55,11 +55,39 @@
message TestEnumMap {
map<int32, Proto2MapEnum> known_map_field = 101;
map<int32, Proto2MapEnum> unknown_map_field = 102;
+
+ // Other maps with all key types to test the unknown entry serialization
+ map<int64, Proto2MapEnum> unknown_map_field_int64 = 200;
+ map<uint64, Proto2MapEnum> unknown_map_field_uint64 = 201;
+ map<int32, Proto2MapEnum> unknown_map_field_int32 = 202;
+ map<uint32, Proto2MapEnum> unknown_map_field_uint32 = 203;
+ map<fixed32, Proto2MapEnum> unknown_map_field_fixed32 = 204;
+ map<fixed64, Proto2MapEnum> unknown_map_field_fixed64 = 205;
+ map<bool, Proto2MapEnum> unknown_map_field_bool = 206;
+ map<string, Proto2MapEnum> unknown_map_field_string = 207;
+ map<sint32, Proto2MapEnum> unknown_map_field_sint32 = 208;
+ map<sint64, Proto2MapEnum> unknown_map_field_sint64 = 209;
+ map<sfixed32, Proto2MapEnum> unknown_map_field_sfixed32 = 210;
+ map<sfixed64, Proto2MapEnum> unknown_map_field_sfixed64 = 211;
}
message TestEnumMapPlusExtra {
map<int32, Proto2MapEnumPlusExtra> known_map_field = 101;
map<int32, Proto2MapEnumPlusExtra> unknown_map_field = 102;
+
+ // Other maps with all key types to test the unknown entry serialization
+ map<int64, Proto2MapEnumPlusExtra> unknown_map_field_int64 = 200;
+ map<uint64, Proto2MapEnumPlusExtra> unknown_map_field_uint64 = 201;
+ map<int32, Proto2MapEnumPlusExtra> unknown_map_field_int32 = 202;
+ map<uint32, Proto2MapEnumPlusExtra> unknown_map_field_uint32 = 203;
+ map<fixed32, Proto2MapEnumPlusExtra> unknown_map_field_fixed32 = 204;
+ map<fixed64, Proto2MapEnumPlusExtra> unknown_map_field_fixed64 = 205;
+ map<bool, Proto2MapEnumPlusExtra> unknown_map_field_bool = 206;
+ map<string, Proto2MapEnumPlusExtra> unknown_map_field_string = 207;
+ map<sint32, Proto2MapEnumPlusExtra> unknown_map_field_sint32 = 208;
+ map<sint64, Proto2MapEnumPlusExtra> unknown_map_field_sint64 = 209;
+ map<sfixed32, Proto2MapEnumPlusExtra> unknown_map_field_sfixed32 = 210;
+ map<sfixed64, Proto2MapEnumPlusExtra> unknown_map_field_sfixed64 = 211;
}
message TestImportEnumMap {
@@ -90,3 +118,8 @@
message TestSubmessageMaps {
optional TestMaps m = 1;
}
+
+message TestProto2BytesMap {
+ map<int32, bytes> map_bytes = 1;
+ map<int32, string> map_string = 2;
+}
diff --git a/src/google/protobuf/map_proto3_unittest.proto b/src/google/protobuf/map_proto3_unittest.proto
new file mode 100644
index 0000000..cea8ef6
--- /dev/null
+++ b/src/google/protobuf/map_proto3_unittest.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+
+syntax = "proto3";
+
+// This file contains definitions that have different behavior in proto3.
+
+// We don't put this in a package within proto2 because we need to make sure
+// that the generated code doesn't depend on being in the proto2 namespace.
+// In map_test_util.h we do "using namespace unittest = protobuf_unittest".
+package proto3_unittest;
+
+message TestProto3BytesMap {
+ map<int32, bytes> map_bytes = 1;
+ map<int32, string> map_string = 2;
+}
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc
index 76c5ce8..8cd3cc2 100644
--- a/src/google/protobuf/map_test.inc
+++ b/src/google/protobuf/map_test.inc
@@ -49,6 +49,7 @@
#include "google/protobuf/testing/googletest.h"
#include <gtest/gtest.h>
#include "absl/base/casts.h"
+#include "absl/cleanup/cleanup.h"
#include "absl/container/btree_set.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
@@ -64,6 +65,8 @@
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/map.h"
#include "google/protobuf/map_field_inl.h"
+#include "google/protobuf/map_proto2_unittest.pb.h"
+#include "google/protobuf/map_proto3_unittest.pb.h"
#include "google/protobuf/message.h"
#include "google/protobuf/reflection.h"
#include "google/protobuf/reflection_ops.h"
@@ -179,6 +182,28 @@
template <>
struct is_internal_map_value_type<CountedInstance> : std::true_type {};
+struct MapTestPeer {
+ template <typename T>
+ static typename T::KeyMapBase& GetKeyMapBase(T& value) {
+ return value;
+ }
+
+ template <typename T>
+ static bool InsertOrReplaceNode(T& map, typename T::key_type key,
+ typename T::mapped_type value) {
+ using Node = typename T::Node;
+ auto* node = static_cast<Node*>(map.AllocNode(sizeof(Node)));
+ ::new (static_cast<void*>(&node->kv)) typename T::value_type{key, value};
+ node = static_cast<Node*>(GetKeyMapBase(map).InsertOrReplaceNode(node));
+ if (node) {
+ node->~Node();
+ GetKeyMapBase(map).DeallocNode(node, sizeof(Node));
+ return false;
+ }
+ return true;
+ }
+};
+
namespace {
using internal::DownCast;
@@ -2738,6 +2763,42 @@
EXPECT_EQ(UNITTEST::PROTO2_MAP_ENUM_FOO, to.known_map_field().at(0));
}
+TEST(GeneratedMapFieldTest, Proto2UnknownEnumAllKeyTypesWork) {
+#define PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(Type, Value) \
+ { \
+ UNITTEST::TestEnumMapPlusExtra from; \
+ auto value = Value; \
+ ABSL_LOG(INFO) << "Testing " << #Type; \
+ (*from.mutable_unknown_map_field_##Type())[Value] = \
+ UNITTEST::E_PROTO2_MAP_ENUM_EXTRA; \
+ UNITTEST::TestEnumMap to; \
+ ASSERT_TRUE(to.ParseFromString(from.SerializeAsString())); \
+ EXPECT_EQ(0, to.unknown_map_field_##Type().size()) \
+ << testing::PrintToString(to.unknown_map_field_##Type()); \
+ const UnknownFieldSet& unknown_field_set = \
+ to.GetReflection()->GetUnknownFields(to); \
+ EXPECT_EQ(1, unknown_field_set.field_count()); \
+ from.Clear(); \
+ EXPECT_EQ(from.unknown_map_field_##Type().size(), 0); \
+ EXPECT_TRUE(from.ParseFromString(to.SerializeAsString())); \
+ EXPECT_THAT(from.unknown_map_field_##Type(), \
+ ElementsAre(Pair(value, UNITTEST::E_PROTO2_MAP_ENUM_EXTRA))); \
+ }
+
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(int64, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(uint64, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(int32, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(uint32, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(fixed32, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(fixed64, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(bool, true);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(string, "17");
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(sint32, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(sint64, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(sfixed32, 17);
+ PROTOBUF_INTERNAL_TEST_MAP_KEY_TYPE(sfixed64, 17);
+}
+
TEST(GeneratedMapFieldTest, StandardWireFormat) {
UNITTEST::TestMap message;
std::string data = "\x0A\x04\x08\x01\x10\x01";
@@ -2910,6 +2971,41 @@
EXPECT_EQ(3, message.map_int32_int32().at(2));
}
+TEST(GeneratedMapFieldTest, ToplevelTagNotLengthPrefixed) {
+ UNITTEST::TestMap message;
+
+ // The toplevel matches a field number, but does not match the wire type.
+ std::string data = "\x08\x81\x04";
+ EXPECT_TRUE(message.ParseFromString(data));
+ EXPECT_EQ(0, message.map_int32_int32().size());
+
+ const UnknownFieldSet& unknown_field_set =
+ message.GetReflection()->GetUnknownFields(message);
+ ASSERT_EQ(1, unknown_field_set.field_count());
+ auto& field = unknown_field_set.field(0);
+ ASSERT_EQ(field.TYPE_VARINT, field.type());
+ EXPECT_EQ(((0x1 << 0) | (0x04 << 7)), field.varint());
+}
+
+TEST(GeneratedMapFieldTest, InnerTagsInLongForm) {
+ UNITTEST::TestMap message;
+
+ // First, control
+ absl::string_view data("\012\004\010\007\020\005", 6);
+ ASSERT_TRUE(message.ParseFromString(data));
+ EXPECT_THAT(message.map_int32_int32(), ElementsAre(Pair(7, 5)));
+
+ // Now we make the key tag long form
+ data = absl::string_view("\012\005\210\000\007\020\005", 7);
+ ASSERT_TRUE(message.ParseFromString(data));
+ EXPECT_THAT(message.map_int32_int32(), ElementsAre(Pair(7, 5)));
+
+ // Now we make the value tag long form
+ data = absl::string_view("\012\005\010\007\220\000\005", 7);
+ ASSERT_TRUE(message.ParseFromString(data));
+ EXPECT_THAT(message.map_int32_int32(), ElementsAre(Pair(7, 5)));
+}
+
TEST(GeneratedMapFieldTest, CorruptedWireFormat) {
UNITTEST::TestMap message;
@@ -3365,7 +3461,7 @@
message->SerializeToString(&data);
TestMap to;
- to.ParseFromString(data);
+ ASSERT_TRUE(to.ParseFromString(data));
EXPECT_EQ(128, to.map_int32_foreign_message().at(0).c());
}
@@ -4134,6 +4230,63 @@
EXPECT_EQ(nested_msg43_ptr, &moved_to_map[43].optional_nested_message());
}
+TEST(KeyMapBaseTest, InsertOrReplaceNodeWorks) {
+ using M = Map<int32_t, std::string>;
+ M map;
+ EXPECT_TRUE(MapTestPeer::InsertOrReplaceNode(map, 10, "Foo"));
+ EXPECT_EQ(map.size(), 1);
+ EXPECT_EQ(map[10], "Foo");
+ EXPECT_FALSE(MapTestPeer::InsertOrReplaceNode(map, 10, "Bar"));
+ EXPECT_EQ(map.size(), 1);
+ EXPECT_EQ(map[10], "Bar");
+ map[100] = "BAD";
+ EXPECT_EQ(map.size(), 2);
+ EXPECT_EQ(map[10], "Bar");
+ EXPECT_EQ(map[100], "BAD");
+ EXPECT_FALSE(MapTestPeer::InsertOrReplaceNode(map, 100, "GOOD"));
+ EXPECT_EQ(map.size(), 2);
+ EXPECT_EQ(map[10], "Bar");
+ EXPECT_EQ(map[100], "GOOD");
+}
+
+TEST(NonUtf8Test, StringValuePassesInProto2) {
+ protobuf_unittest::TestProto2BytesMap message;
+ (*message.mutable_map_string())[1] = "\xFF";
+
+ auto serialized = message.SerializeAsString();
+ // Parsing passes, but a failure is logged in debug mode.
+ ASSERT_TRUE(message.ParseFromString(serialized));
+ EXPECT_EQ((*message.mutable_map_string())[1], "\xFF");
+}
+
+TEST(NonUtf8Test, BytesValuePassesInProto2) {
+ protobuf_unittest::TestProto2BytesMap message;
+ (*message.mutable_map_bytes())[1] = "\xFF";
+
+ auto serialized = message.SerializeAsString();
+ ASSERT_TRUE(message.ParseFromString(serialized));
+ EXPECT_EQ((*message.mutable_map_bytes())[1], "\xFF");
+}
+
+TEST(NonUtf8Test, StringValueFailsInProto3) {
+ proto3_unittest::TestProto3BytesMap message;
+ (*message.mutable_map_string())[1] = "\xFF";
+
+ auto serialized = message.SerializeAsString();
+ // It will fail, and log an error.
+ ASSERT_FALSE(message.ParseFromString(serialized));
+}
+
+
+TEST(NonUtf8Test, BytesValuePassesInProto3) {
+ proto3_unittest::TestProto3BytesMap message;
+ (*message.mutable_map_bytes())[1] = "\xFF";
+
+ auto serialized = message.SerializeAsString();
+ ASSERT_TRUE(message.ParseFromString(serialized));
+ EXPECT_EQ((*message.mutable_map_bytes())[1], "\xFF");
+}
+
} // namespace
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index ffd639e..645dc3d 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -118,6 +118,7 @@
#include "google/protobuf/stubs/common.h"
#include "google/protobuf/arena.h"
#include "google/protobuf/port.h"
+#include "absl/base/attributes.h"
#include "absl/base/call_once.h"
#include "absl/base/casts.h"
#include "absl/functional/function_ref.h"
@@ -630,6 +631,7 @@
std::string* scratch) const;
+
// Singular field mutators -----------------------------------------
// These mutate the value of a non-repeated field.
@@ -960,6 +962,7 @@
// reflection->SetEnumValue(message, field, new_value);
// }
// }
+ ABSL_DEPRECATED("Use EnumDescriptor::is_closed instead.")
bool SupportsUnknownEnumValues() const;
// Returns the MessageFactory associated with this message. This can be
diff --git a/src/google/protobuf/message_unittest.inc b/src/google/protobuf/message_unittest.inc
index 204da69..914e3e9 100644
--- a/src/google/protobuf/message_unittest.inc
+++ b/src/google/protobuf/message_unittest.inc
@@ -61,12 +61,14 @@
#include "absl/strings/substitute.h"
#include "google/protobuf/arena.h"
#include "google/protobuf/descriptor.h"
+#include "google/protobuf/dynamic_message.h"
#include "google/protobuf/generated_message_reflection.h"
-#include "google/protobuf/message.h"
+#include "google/protobuf/generated_message_tctable_impl.h"
#include "google/protobuf/io/coded_stream.h"
#include "google/protobuf/io/io_win32.h"
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
+#include "google/protobuf/message.h"
#include "google/protobuf/test_util2.h"
@@ -324,6 +326,20 @@
EXPECT_NE(parsed.lazy_child().child().payload().optional_int32(), -1);
}
+TEST(MESSAGE_TEST_NAME, ParseFailNonCanonicalZeroTag) {
+ const char encoded[] = {"\n\x3\x80\0\0"};
+ UNITTEST::NestedTestAllTypes parsed;
+ EXPECT_FALSE(parsed.ParsePartialFromString(
+ absl::string_view{encoded, sizeof(encoded) - 1}));
+}
+
+TEST(MESSAGE_TEST_NAME, ParseFailNonCanonicalZeroField) {
+ const char encoded[] = {"\012\x6\205\0\0\0\0\0"};
+ UNITTEST::NestedTestAllTypes parsed;
+ EXPECT_FALSE(parsed.ParsePartialFromString(
+ absl::string_view{encoded, sizeof(encoded) - 1}));
+}
+
TEST(MESSAGE_TEST_NAME, NestedExplicitLazyExceedRecursionLimit) {
UNITTEST::NestedTestAllTypes original, parsed;
// Build proto with recursion depth of 5, with nested annotated LazyField.
@@ -458,6 +474,24 @@
EXPECT_FALSE(parsed.ParseFromString(data));
}
+TEST(MESSAGE_TEST_NAME, ParseFailsIfRepeatedGroupFieldMalformed) {
+ UNITTEST::TestMutualRecursionA original, parsed;
+ original.mutable_bb()
+ ->mutable_a()
+ ->add_subgroupr()
+ ->mutable_payload()
+ ->set_optional_int64(-1);
+
+ std::string data;
+ ASSERT_TRUE(original.SerializeToString(&data));
+ // Should parse correctly.
+ ASSERT_TRUE(parsed.ParseFromString(data));
+ // Overwriting the last byte of varint (-1) to 0xFF results in malformed wire.
+ data[data.size() - 2] = 0xFF;
+
+ EXPECT_FALSE(parsed.ParseFromString(data));
+}
+
TEST(MESSAGE_TEST_NAME, UninitializedAndMalformed) {
UNITTEST::TestRequiredForeign o, p1, p2;
o.mutable_optional_message()->set_a(-1);
@@ -508,6 +542,8 @@
TEST(MESSAGE_TEST_NAME, AllSetMethodsOnStringField) {
UNITTEST::TestAllTypes msg;
+ msg.set_optional_string(absl::string_view("Abcdef"));
+ EXPECT_EQ(msg.optional_string(), "Abcdef");
msg.set_optional_string("Asciiz");
EXPECT_EQ(msg.optional_string(), "Asciiz");
@@ -528,6 +564,38 @@
EXPECT_EQ(msg.optional_string(), "std::string value 3");
}
+
+TEST(MESSAGE_TEST_NAME, AllAddMethodsOnRepeatedStringField) {
+ UNITTEST::TestAllTypes msg;
+
+ msg.add_repeated_string(absl::string_view("Abcdef"));
+ EXPECT_EQ(msg.repeated_string(0), "Abcdef");
+ msg.clear_repeated_string();
+
+ msg.add_repeated_string("Asciiz");
+ EXPECT_EQ(msg.repeated_string(0), "Asciiz");
+ msg.clear_repeated_string();
+
+ msg.add_repeated_string("Length delimited", 6);
+ EXPECT_EQ(msg.repeated_string(0), "Length");
+ msg.clear_repeated_string();
+
+ std::string value = "std::string value 1";
+ msg.add_repeated_string(value);
+ EXPECT_EQ(msg.repeated_string(0), "std::string value 1");
+ msg.clear_repeated_string();
+
+ value = "std::string value 2";
+ msg.add_repeated_string(std::cref(value));
+ EXPECT_EQ(msg.repeated_string(0), "std::string value 2");
+ msg.clear_repeated_string();
+
+ value = "std::string value 3";
+ msg.add_repeated_string(std::move(value));
+ EXPECT_EQ(msg.repeated_string(0), "std::string value 3");
+ msg.clear_repeated_string();
+}
+
TEST(MESSAGE_TEST_NAME, SuccessAfterParsingFailure) {
UNITTEST::NestedTestAllTypes o, p, q;
constexpr int kDepth = 5;
@@ -1166,6 +1234,31 @@
std::signbit(out_message.optional_double()));
}
+TEST(MESSAGE_TEST_NAME,
+ RegressionTestForParseMessageReadingUninitializedLimit) {
+ UNITTEST::TestAllTypes in_message;
+ in_message.mutable_optional_nested_message();
+ std::string serialized = in_message.SerializeAsString();
+ // We expect this to have 3 bytes: two for the tag, and one for the zero size.
+ // Break the size by making it overlong.
+ ASSERT_EQ(serialized.size(), 3);
+ serialized.back() = '\200';
+ serialized += std::string(10, '\200');
+ EXPECT_FALSE(in_message.ParseFromString(serialized));
+}
+
+TEST(MESSAGE_TEST_NAME,
+ RegressionTestForParseMessageWithSizeBeyondInputFailsToPopLimit) {
+ UNITTEST::TestAllTypes in_message;
+ in_message.mutable_optional_nested_message();
+ std::string serialized = in_message.SerializeAsString();
+ // We expect this to have 3 bytes: two for the tag, and one for the zero size.
+ // Make the size a valid varint, but it overflows in the input.
+ ASSERT_EQ(serialized.size(), 3);
+ serialized.back() = 10;
+ EXPECT_FALSE(in_message.ParseFromString(serialized));
+}
+
const uint8_t* SkipTag(const uint8_t* buf) {
while (*buf & 0x80) ++buf;
++buf;
@@ -1225,18 +1318,62 @@
}
}
+std::string EncodeInt32Value(int number, int32_t value,
+ int non_canonical_bytes) {
+ uint8_t buf[100];
+ uint8_t* p = buf;
+
+ p = internal::WireFormatLite::WriteInt32ToArray(number, value, p);
+ p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
+ return std::string(buf, p);
+}
+
+std::string EncodeInt64Value(int number, int64_t value, int non_canonical_bytes,
+ bool use_packed = false) {
+ uint8_t buf[100];
+ uint8_t* p = buf;
+
+ if (use_packed) {
+ p = internal::WireFormatLite::WriteInt64NoTagToArray(value, p);
+ p = AddNonCanonicalBytes(buf, p, non_canonical_bytes);
+
+ std::string payload(buf, p);
+ p = buf;
+ p = internal::WireFormatLite::WriteStringToArray(number, payload, p);
+ return std::string(buf, p);
+
+ } else {
+ p = internal::WireFormatLite::WriteInt64ToArray(number, value, p);
+ p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
+ return std::string(buf, p);
+ }
+}
+
std::string EncodeOtherField() {
UNITTEST::EnumParseTester obj;
obj.set_other_field(1);
return obj.SerializeAsString();
}
+template <typename T>
+static std::vector<const FieldDescriptor*> GetFields() {
+ auto* descriptor = T::descriptor();
+ std::vector<const FieldDescriptor*> fields;
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ fields.push_back(descriptor->field(i));
+ }
+ for (int i = 0; i < descriptor->extension_count(); ++i) {
+ fields.push_back(descriptor->extension(i));
+ }
+ return fields;
+}
+
TEST(MESSAGE_TEST_NAME, TestEnumParsers) {
UNITTEST::EnumParseTester obj;
const auto other_field = EncodeOtherField();
- // Encode a boolean field for many different cases and verify that it can be
+ // Encode an enum field for many different cases and verify that it can be
// parsed as expected.
// There are:
// - optional/repeated/packed fields
@@ -1246,6 +1383,9 @@
// - label combinations to trigger different parsers: sequential, small
// sequential, non-validated.
+ const std::vector<const FieldDescriptor*> fields =
+ GetFields<UNITTEST::EnumParseTester>();
+
constexpr int kInvalidValue = 0x900913;
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
@@ -1262,8 +1402,7 @@
continue;
}
SCOPED_TRACE(add_garbage_bits);
- for (int i = 0; i < descriptor->field_count(); ++i) {
- const auto* field = descriptor->field(i);
+ for (auto field : fields) {
if (field->name() == "other_field") continue;
if (!field->is_repeated() && use_packed) continue;
SCOPED_TRACE(field->full_name());
@@ -1336,6 +1475,52 @@
}
}
+TEST(MESSAGE_TEST_NAME, TestEnumParserForUnknownEnumValue) {
+ DynamicMessageFactory factory;
+ std::unique_ptr<Message> dynamic(
+ factory.GetPrototype(UNITTEST::EnumParseTester::descriptor())->New());
+
+ UNITTEST::EnumParseTester non_dynamic;
+
+ // For unknown enum values, for consistency we must include the
+ // int32_t enum value in the unknown field set, which might not be exactly the
+ // same as the input.
+ auto* descriptor = non_dynamic.descriptor();
+
+ const std::vector<const FieldDescriptor*> fields =
+ GetFields<UNITTEST::EnumParseTester>();
+
+ for (bool use_dynamic : {false, true}) {
+ SCOPED_TRACE(use_dynamic);
+ for (auto field : fields) {
+ if (field->name() == "other_field") continue;
+ SCOPED_TRACE(field->full_name());
+ for (bool use_packed : {false, true}) {
+ SCOPED_TRACE(use_packed);
+ if (!field->is_repeated() && use_packed) continue;
+
+ // -2 is an invalid enum value on all the tests here.
+ // We will encode -2 as a positive int64 that is equivalent to
+ // int32_t{-2} when truncated.
+ constexpr int64_t minus_2_non_canonical =
+ static_cast<int64_t>(static_cast<uint32_t>(int32_t{-2}));
+ static_assert(minus_2_non_canonical != -2, "");
+ std::string encoded = EncodeInt64Value(
+ field->number(), minus_2_non_canonical, 0, use_packed);
+
+ auto& obj = use_dynamic ? *dynamic : non_dynamic;
+ ASSERT_TRUE(obj.ParseFromString(encoded));
+
+ auto& unknown = obj.GetReflection()->GetUnknownFields(obj);
+ ASSERT_EQ(unknown.field_count(), 1);
+ EXPECT_EQ(unknown.field(0).number(), field->number());
+ EXPECT_EQ(unknown.field(0).type(), unknown.field(0).TYPE_VARINT);
+ EXPECT_EQ(unknown.field(0).varint(), int64_t{-2});
+ }
+ }
+ }
+}
+
std::string EncodeBoolValue(int number, bool value, int non_canonical_bytes) {
uint8_t buf[100];
uint8_t* p = buf;
@@ -1358,6 +1543,9 @@
// - canonical and non-canonical encodings of the varint
// - last vs not last field
+ const std::vector<const FieldDescriptor*> fields =
+ GetFields<UNITTEST::BoolParseTester>();
+
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
for (bool use_tail_field : {false, true}) {
@@ -1371,8 +1559,7 @@
continue;
}
SCOPED_TRACE(add_garbage_bits);
- for (int i = 0; i < descriptor->field_count(); ++i) {
- const auto* field = descriptor->field(i);
+ for (auto field : fields) {
if (field->name() == "other_field") continue;
SCOPED_TRACE(field->full_name());
for (bool value : {false, true}) {
@@ -1407,16 +1594,6 @@
}
}
-std::string EncodeInt32Value(int number, int32_t value,
- int non_canonical_bytes) {
- uint8_t buf[100];
- uint8_t* p = buf;
-
- p = internal::WireFormatLite::WriteInt32ToArray(number, value, p);
- p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
- return std::string(buf, p);
-}
-
TEST(MESSAGE_TEST_NAME, TestInt32Parsers) {
UNITTEST::Int32ParseTester obj;
@@ -1430,6 +1607,9 @@
// - canonical and non-canonical encodings of the varint
// - last vs not last field
+ const std::vector<const FieldDescriptor*> fields =
+ GetFields<UNITTEST::Int32ParseTester>();
+
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
for (bool use_tail_field : {false, true}) {
@@ -1443,8 +1623,7 @@
continue;
}
SCOPED_TRACE(add_garbage_bits);
- for (int i = 0; i < descriptor->field_count(); ++i) {
- const auto* field = descriptor->field(i);
+ for (auto field : fields) {
if (field->name() == "other_field") continue;
SCOPED_TRACE(field->full_name());
for (int32_t value : {1, 0, -1, (std::numeric_limits<int32_t>::min)(),
@@ -1480,16 +1659,6 @@
}
}
-std::string EncodeInt64Value(int number, int64_t value,
- int non_canonical_bytes) {
- uint8_t buf[100];
- uint8_t* p = buf;
-
- p = internal::WireFormatLite::WriteInt64ToArray(number, value, p);
- p = AddNonCanonicalBytes(SkipTag(buf), p, non_canonical_bytes);
- return std::string(buf, p);
-}
-
TEST(MESSAGE_TEST_NAME, TestInt64Parsers) {
UNITTEST::Int64ParseTester obj;
@@ -1503,6 +1672,9 @@
// - canonical and non-canonical encodings of the varint
// - last vs not last field
+ const std::vector<const FieldDescriptor*> fields =
+ GetFields<UNITTEST::Int64ParseTester>();
+
auto* ref = obj.GetReflection();
auto* descriptor = obj.descriptor();
for (bool use_tail_field : {false, true}) {
@@ -1516,8 +1688,7 @@
continue;
}
SCOPED_TRACE(add_garbage_bits);
- for (int i = 0; i < descriptor->field_count(); ++i) {
- const auto* field = descriptor->field(i);
+ for (auto field : fields) {
if (field->name() == "other_field") continue;
SCOPED_TRACE(field->full_name());
for (int64_t value : {int64_t{1}, int64_t{0}, int64_t{-1},
@@ -1600,6 +1771,60 @@
size_t break_pos_;
};
+template <typename T>
+static const internal::TcParseTableBase* GetTableIfAvailable(...) {
+ return nullptr;
+}
+
+template <typename T>
+static const internal::TcParseTableBase* GetTableIfAvailable(
+ decltype(internal::TcParser::GetTable<T>())) {
+ return internal::TcParser::GetTable<T>();
+}
+
+TEST(MESSAGE_TEST_NAME, TestRegressionInlinedStringAuxIdxMismatchOnFastParser) {
+ using Proto = UNITTEST::InlinedStringIdxRegressionProto;
+
+ auto* table = GetTableIfAvailable<Proto>(nullptr);
+ // Only test when TDP is on, and we have these fields inlined.
+ if (table != nullptr &&
+ table->fast_entry(1)->target() == internal::TcParser::FastSiS1) {
+ // optional string str1 = 1;
+ EXPECT_EQ(table->fast_entry(1)->bits.aux_idx(), 1);
+ // optional InlinedStringIdxRegressionProto sub = 2;
+ EXPECT_EQ(table->fast_entry(2)->bits.aux_idx(), 2);
+ // optional string str2 = 3;
+ // The aux_idx points to the inlined_string_idx and not the actual aux_idx.
+ EXPECT_EQ(table->fast_entry(3)->bits.aux_idx(), 2);
+ // optional string str3 = 4;
+ // The aux_idx points to the inlined_string_idx and not the actual aux_idx.
+ EXPECT_EQ(table->fast_entry(0)->bits.aux_idx(), 3);
+ }
+
+ std::string encoded;
+ {
+ Proto proto;
+ // We use strings longer than SSO.
+ proto.set_str1(std::string(100, 'a'));
+ proto.set_str2(std::string(100, 'a'));
+ proto.set_str3(std::string(100, 'a'));
+ encoded = proto.SerializeAsString();
+ }
+ Arena arena;
+ auto* proto = Arena::CreateMessage<Proto>(&arena);
+ // We don't alter donation here, so it works even if the idx are bad.
+ ASSERT_TRUE(proto->ParseFromString(encoded));
+ // Now we alter donation bits. str2's bit (#2) will be off, but its aux_idx
+ // (#3) will point to a donated string.
+ proto = Arena::CreateMessage<Proto>(&arena);
+ proto->mutable_str1();
+ proto->mutable_str2();
+ proto->mutable_str3();
+ // With the bug, this breaks the cleanup list, causing UB on arena
+ // destruction.
+ ASSERT_TRUE(proto->ParseFromString(encoded));
+}
+
TEST(MESSAGE_TEST_NAME, TestRepeatedStringParsers) {
google::protobuf::Arena arena;
@@ -1609,6 +1834,9 @@
const auto* const descriptor = UNITTEST::StringParseTester::descriptor();
+ const std::vector<const FieldDescriptor*> fields =
+ GetFields<UNITTEST::StringParseTester>();
+
static const size_t sso_capacity = std::string().capacity();
if (sso_capacity == 0) GTEST_SKIP();
// SSO, !SSO, and off-by-one just in case
@@ -1616,8 +1844,7 @@
{sso_capacity - 1, sso_capacity, sso_capacity + 1, sso_capacity + 2}) {
SCOPED_TRACE(size);
const std::string value = sample.substr(0, size);
- for (int i = 0; i < descriptor->field_count(); ++i) {
- const auto* field = descriptor->field(i);
+ for (auto field : fields) {
SCOPED_TRACE(field->full_name());
const auto encoded = EncodeStringValue(field->number(), sample) +
EncodeStringValue(field->number(), value);
diff --git a/src/google/protobuf/parse_context.cc b/src/google/protobuf/parse_context.cc
index 11d2181..b96e7ac 100644
--- a/src/google/protobuf/parse_context.cc
+++ b/src/google/protobuf/parse_context.cc
@@ -319,26 +319,19 @@
}
const char* ParseContext::ReadSizeAndPushLimitAndDepth(const char* ptr,
- int* old_limit) {
- int size = ReadSize(&ptr);
- if (PROTOBUF_PREDICT_FALSE(!ptr) || depth_ <= 0) {
- *old_limit = 0; // Make sure this isn't uninitialized even on error return
- return nullptr;
- }
- *old_limit = PushLimit(ptr, size);
- --depth_;
- return ptr;
+ LimitToken* old_limit) {
+ return ReadSizeAndPushLimitAndDepthInlined(ptr, old_limit);
}
const char* ParseContext::ParseMessage(MessageLite* msg, const char* ptr) {
- int old;
+ LimitToken old;
ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
if (ptr == nullptr) return ptr;
auto old_depth = depth_;
ptr = msg->_InternalParse(ptr, this);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
- if (!PopLimit(old)) return nullptr;
+ if (!PopLimit(std::move(old))) return nullptr;
return ptr;
}
diff --git a/src/google/protobuf/parse_context.h b/src/google/protobuf/parse_context.h
index 4b82927..a949eaf 100644
--- a/src/google/protobuf/parse_context.h
+++ b/src/google/protobuf/parse_context.h
@@ -36,11 +36,13 @@
#include <string>
#include <type_traits>
+#include "absl/base/config.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/cord.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
#include "google/protobuf/arena.h"
#include "google/protobuf/arenastring.h"
#include "google/protobuf/endian.h"
@@ -131,8 +133,53 @@
if (count > 0) StreamBackUp(count);
}
+#if defined(ABSL_HAVE_ADDRESS_SANITIZER) || defined(ABSL_HAVE_MEMORY_SANITIZER)
+ // In sanitizer mode we use an optional<int> to guarantee that:
+ // - We do not read an uninitialized token.
+ // - Every non-empty token is moved from and consumed.
+ class LimitToken {
+ public:
+ LimitToken() = default;
+ explicit LimitToken(int token) : token_(token) {}
+ LimitToken(LimitToken&& other) { *this = std::move(other); }
+ LimitToken& operator=(LimitToken&& other) {
+ token_ = std::exchange(other.token_, absl::nullopt);
+ return *this;
+ }
+
+ ~LimitToken() { ABSL_CHECK(!token_.has_value()); }
+
+ LimitToken(const LimitToken&) = delete;
+ LimitToken& operator=(const LimitToken&) = delete;
+
+ int token() && {
+ ABSL_CHECK(token_.has_value());
+ return *std::exchange(token_, absl::nullopt);
+ }
+
+ private:
+ absl::optional<int> token_;
+ };
+#else
+ class LimitToken {
+ public:
+ LimitToken() = default;
+ explicit LimitToken(int token) : token_(token) {}
+ LimitToken(LimitToken&&) = default;
+ LimitToken& operator=(LimitToken&&) = default;
+
+ LimitToken(const LimitToken&) = delete;
+ LimitToken& operator=(const LimitToken&) = delete;
+
+ int token() const { return token_; }
+
+ private:
+ int token_;
+ };
+#endif
+
// If return value is negative it's an error
- PROTOBUF_NODISCARD int PushLimit(const char* ptr, int limit) {
+ PROTOBUF_NODISCARD LimitToken PushLimit(const char* ptr, int limit) {
ABSL_DCHECK(limit >= 0 && limit <= INT_MAX - kSlopBytes);
// This add is safe due to the invariant above, because
// ptr - buffer_end_ <= kSlopBytes.
@@ -140,12 +187,14 @@
limit_end_ = buffer_end_ + (std::min)(0, limit);
auto old_limit = limit_;
limit_ = limit;
- return old_limit - limit;
+ return LimitToken(old_limit - limit);
}
- PROTOBUF_NODISCARD bool PopLimit(int delta) {
+ PROTOBUF_NODISCARD bool PopLimit(LimitToken delta) {
+ // We must update the limit first before the early return. Otherwise, we can
+ // end up with an invalid limit and it can lead to integer overflows.
+ limit_ = limit_ + std::move(delta).token();
if (PROTOBUF_PREDICT_FALSE(!EndedAtLimit())) return false;
- limit_ = limit_ + delta;
// TODO(gerbens) We could remove this line and hoist the code to
// DoneFallback. Study the perf/bin-size effects.
limit_end_ = buffer_end_ + (std::min)(0, limit_);
@@ -467,16 +516,24 @@
bool>::type = true>
PROTOBUF_NODISCARD const char* ParseMessage(T* msg, const char* ptr);
+ // Read the length prefix, push the new limit, call the func(ptr), and then
+ // pop the limit. Useful for situations that don't value an actual message,
+ // like map entries.
+ template <typename Func>
+ PROTOBUF_NODISCARD const char* ParseLengthDelimitedInlined(const char*,
+ const Func& func);
+
template <typename TcParser, typename Table>
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char* ParseMessage(
MessageLite* msg, const char* ptr, const Table* table) {
- int old;
+ LimitToken old;
ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
+ if (ptr == nullptr) return ptr;
auto old_depth = depth_;
- ptr = ptr ? TcParser::ParseLoop(msg, ptr, this, table) : nullptr;
+ ptr = TcParser::ParseLoop(msg, ptr, this, table);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
- if (!PopLimit(old)) return nullptr;
+ if (!PopLimit(std::move(old))) return nullptr;
return ptr;
}
@@ -518,20 +575,20 @@
private:
// Out-of-line routine to save space in ParseContext::ParseMessage<T>
- // int old;
+ // LimitToken old;
// ptr = ReadSizeAndPushLimitAndDepth(ptr, &old)
// is equivalent to:
// int size = ReadSize(&ptr);
// if (!ptr) return nullptr;
- // int old = PushLimit(ptr, size);
+ // LimitToken old = PushLimit(ptr, size);
// if (--depth_ < 0) return nullptr;
- PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(const char* ptr,
- int* old_limit);
+ PROTOBUF_NODISCARD const char* ReadSizeAndPushLimitAndDepth(
+ const char* ptr, LimitToken* old_limit);
// As above, but fully inlined for the cases where we care about performance
// more than size. eg TcParser.
PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char*
- ReadSizeAndPushLimitAndDepthInlined(const char* ptr, int* old_limit);
+ ReadSizeAndPushLimitAndDepthInlined(const char* ptr, LimitToken* old_limit);
// The context keeps an internal stack to keep track of the recursive
// part of the parse state.
@@ -598,6 +655,11 @@
memcpy(&res, &tmp, sizeof(T));
return res;
}
+template <typename T, typename Void,
+ typename = std::enable_if_t<std::is_same<Void, void>::value>>
+T UnalignedLoad(const Void* p) {
+ return UnalignedLoad<T>(reinterpret_cast<const char*>(p));
+}
PROTOBUF_EXPORT
std::pair<const char*, uint32_t> VarintParseSlow32(const char* p, uint32_t res);
@@ -883,27 +945,37 @@
!std::is_base_of<MessageLite, T>::value, bool>::type>
PROTOBUF_NODISCARD const char* ParseContext::ParseMessage(T* msg,
const char* ptr) {
- int old;
+ LimitToken old;
ptr = ReadSizeAndPushLimitAndDepth(ptr, &old);
if (ptr == nullptr) return ptr;
auto old_depth = depth_;
ptr = msg->_InternalParse(ptr, this);
if (ptr != nullptr) ABSL_DCHECK_EQ(old_depth, depth_);
depth_++;
- if (!PopLimit(old)) return nullptr;
+ if (!PopLimit(std::move(old))) return nullptr;
+ return ptr;
+}
+
+template <typename Func>
+PROTOBUF_NODISCARD PROTOBUF_ALWAYS_INLINE const char*
+ParseContext::ParseLengthDelimitedInlined(const char* ptr, const Func& func) {
+ LimitToken old;
+ ptr = ReadSizeAndPushLimitAndDepthInlined(ptr, &old);
+ if (ptr == nullptr) return ptr;
+ PROTOBUF_ALWAYS_INLINE_CALL ptr = func(ptr);
+ depth_++;
+ if (!PopLimit(std::move(old))) return nullptr;
return ptr;
}
inline const char* ParseContext::ReadSizeAndPushLimitAndDepthInlined(
- const char* ptr, int* old_limit) {
+ const char* ptr, LimitToken* old_limit) {
int size = ReadSize(&ptr);
- if (PROTOBUF_PREDICT_FALSE(!ptr)) {
- // Make sure this isn't uninitialized even on error return
- *old_limit = 0;
+ if (PROTOBUF_PREDICT_FALSE(!ptr) || depth_ <= 0) {
return nullptr;
}
*old_limit = PushLimit(ptr, size);
- if (--depth_ < 0) return nullptr;
+ --depth_;
return ptr;
}
@@ -1122,7 +1194,7 @@
InternalMetadata* metadata,
int field_num) {
return ctx->ReadPackedVarint(
- ptr, [object, is_valid, metadata, field_num](uint64_t val) {
+ ptr, [object, is_valid, metadata, field_num](int32_t val) {
if (is_valid(val)) {
static_cast<RepeatedField<int>*>(object)->Add(val);
} else {
@@ -1137,7 +1209,7 @@
bool (*is_valid)(const void*, int), const void* data,
InternalMetadata* metadata, int field_num) {
return ctx->ReadPackedVarint(
- ptr, [object, is_valid, data, metadata, field_num](uint64_t val) {
+ ptr, [object, is_valid, data, metadata, field_num](int32_t val) {
if (is_valid(data, val)) {
static_cast<RepeatedField<int>*>(object)->Add(val);
} else {
diff --git a/src/google/protobuf/port_def.inc b/src/google/protobuf/port_def.inc
index def5de4..d9bf569 100644
--- a/src/google/protobuf/port_def.inc
+++ b/src/google/protobuf/port_def.inc
@@ -213,6 +213,10 @@
// Owner: shaod@, gberg@
#define PROTOBUF_FUTURE_DESCRIPTOR_EXTENSION_DECL 1
+// Enable cord handling.
+// Owner: mvels@, mkruskal@
+#define PROTOBUF_FUTURE_OPENSOURCE_CORD 1
+
#endif
#ifdef PROTOBUF_VERSION
@@ -223,12 +227,12 @@
#ifdef PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC
#error PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC was previously defined
#endif
-#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC 4022000
+#define PROTOBUF_MIN_HEADER_VERSION_FOR_PROTOC 3021000
#ifdef PROTOBUF_MIN_PROTOC_VERSION
#error PROTOBUF_MIN_PROTOC_VERSION was previously defined
#endif
-#define PROTOBUF_MIN_PROTOC_VERSION 4022000
+#define PROTOBUF_MIN_PROTOC_VERSION 3021000
#ifdef PROTOBUF_VERSION_SUFFIX
#error PROTOBUF_VERSION_SUFFIX was previously defined
@@ -261,6 +265,21 @@
# define PROTOBUF_ALWAYS_INLINE
#endif
+#ifdef PROTOBUF_ALWAYS_INLINE_CALL
+#error PROTOBUF_ALWAYS_INLINE_CALL was previously defined
+#endif
+// For functions we want to force inline from the caller, instead of in the
+// declaration of the callee.
+// This is useful for lambdas where it is not easy to specify ALWAYS_INLINE.
+// Use like:
+// PROTOBUF_ALWAYS_INLINE_CALL res = SomeFunc(args...);
+#if defined(__clang__) && !defined(PROTOBUF_NO_INLINE_CALL) && \
+ __has_cpp_attribute(clang::always_inline)
+#define PROTOBUF_ALWAYS_INLINE_CALL [[clang::always_inline]]
+#else
+#define PROTOBUF_ALWAYS_INLINE_CALL
+#endif
+
#ifdef PROTOBUF_NDEBUG_INLINE
#error PROTOBUF_NDEBUG_INLINE was previously defined
#endif
@@ -386,16 +405,6 @@
# define PROTOBUF_DEPRECATED_MSG(msg)
#endif
-#if defined(PROTOBUF_DEPRECATED_ENUM)
-#error PROTOBUF_DEPRECATED_ENUM was previously defined
-#endif
-#if defined(__clang__) || defined(__GNUC__)
-// https://gcc.gnu.org/gcc-6/changes.html
-# define PROTOBUF_DEPRECATED_ENUM __attribute__((deprecated))
-#else
-# define PROTOBUF_DEPRECATED_ENUM
-#endif
-
#if defined(__clang__)
#define PROTOBUF_IGNORE_DEPRECATION_START \
_Pragma("clang diagnostic push") \
@@ -433,7 +442,7 @@
// The minimum library version which works with the current version of the
// headers.
-#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 4022000
+#define GOOGLE_PROTOBUF_MIN_LIBRARY_VERSION 3021000
#ifdef PROTOBUF_RTTI
#error PROTOBUF_RTTI was previously defined
@@ -856,6 +865,19 @@
// PROTOBUF_TC_PARAM_PASS passes values to match PROTOBUF_TC_PARAM_DECL.
#define PROTOBUF_TC_PARAM_PASS msg, ptr, ctx, data, table, hasbits
+// PROTOBUF_TC_PARAM_NO_DATA_DECL and PROTOBUF_TC_PARAM_NO_DATA_PASS provide the
+// exact same ABI as above, except that they don't name or pass the `data`
+// argument. Specific functions such as `Error() and `ToTagDispatch()` don't
+// use the `data` argument. By not passing `data` down the call stack, we free
+// up the register holding that value, which may matter in highly optimized
+// functions such as varint parsing.
+#define PROTOBUF_TC_PARAM_NO_DATA_DECL \
+ ::google::protobuf::MessageLite *msg, const char *ptr, \
+ ::google::protobuf::internal::ParseContext *ctx, ::google::protobuf::internal::TcFieldData, \
+ const ::google::protobuf::internal::TcParseTableBase *table, uint64_t hasbits
+#define PROTOBUF_TC_PARAM_NO_DATA_PASS \
+ msg, ptr, ctx, ::google::protobuf::internal::TcFieldData::DefaultInit(), table, hasbits
+
#ifdef PROTOBUF_UNUSED
#error PROTOBUF_UNUSED was previously defined
#endif
@@ -1014,6 +1036,13 @@
// int index = ...
// int value = vec[index];
#pragma GCC diagnostic ignored "-Wsign-conversion"
+#if __GNUC__ == 12 && __GNUC_MINOR__ < 4
+// Wrong warning emitted when assigning a single char c-string to a std::string
+// in c++20 mode and optimization on.
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329
+// Planned to be fixed by 12.3 but widen window to 12.4.
+#pragma GCC diagnostic ignored "-Wrestrict"
+#endif
#endif // __GNUC__
// Silence some MSVC warnings in all our code.
diff --git a/src/google/protobuf/port_undef.inc b/src/google/protobuf/port_undef.inc
index a0a5f64..2be01b1 100644
--- a/src/google/protobuf/port_undef.inc
+++ b/src/google/protobuf/port_undef.inc
@@ -49,6 +49,7 @@
#undef PROTOBUF_NAMESPACE
#undef PROTOBUF_NAMESPACE_ID
#undef PROTOBUF_ALWAYS_INLINE
+#undef PROTOBUF_ALWAYS_INLINE_CALL
#undef PROTOBUF_NDEBUG_INLINE
#undef PROTOBUF_MUSTTAIL
#undef PROTOBUF_TAILCALL
@@ -56,7 +57,6 @@
#undef PROTOBUF_NOINLINE
#undef PROTOBUF_SECTION_VARIABLE
#undef PROTOBUF_DEPRECATED
-#undef PROTOBUF_DEPRECATED_ENUM
#undef PROTOBUF_DEPRECATED_MSG
#undef PROTOBUF_IGNORE_DEPRECATION_START
#undef PROTOBUF_IGNORE_DEPRECATION_STOP
diff --git a/src/google/protobuf/reflection_mode.cc b/src/google/protobuf/reflection_mode.cc
new file mode 100644
index 0000000..7611c7b
--- /dev/null
+++ b/src/google/protobuf/reflection_mode.cc
@@ -0,0 +1,57 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2023 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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 "google/protobuf/reflection_mode.h"
+
+// Must be included last.
+#include "google/protobuf/port_def.inc"
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#if !defined(PROTOBUF_NO_THREADLOCAL)
+
+#if defined(PROTOBUF_USE_DLLS)
+ReflectionMode& ScopedReflectionMode::reflection_mode() {
+ static PROTOBUF_THREAD_LOCAL ReflectionMode reflection_mode =
+ ReflectionMode::kDefault;
+ return reflection_mode;
+}
+#else
+PROTOBUF_CONSTINIT PROTOBUF_THREAD_LOCAL ReflectionMode
+ ScopedReflectionMode::reflection_mode_ = ReflectionMode::kDefault;
+#endif
+
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/reflection_mode.h b/src/google/protobuf/reflection_mode.h
new file mode 100644
index 0000000..e9ff340
--- /dev/null
+++ b/src/google/protobuf/reflection_mode.h
@@ -0,0 +1,165 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2023 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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.
+//
+// This header provides support for a per thread 'reflection mode'.
+//
+// Some protocol buffer optimizations use interceptors to determine which
+// fields are effectively used in the application. These optimizations are
+// disabled if certain reflection calls are intercepted as the assumption is
+// then that any field data can be accessed.
+//
+// The 'reflection mode' defined in this header is intended to be used by
+// logic such as ad-hoc profilers to indicate that any scoped reflection usage
+// is not originating from, or affecting application code. This reflection mode
+// can then be used by such interceptors to ignore any reflection calls not
+// affecting the application behavior.
+
+#ifndef GOOGLE_PROTOBUF_REFLECTION_MODE_H__
+#define GOOGLE_PROTOBUF_REFLECTION_MODE_H__
+
+#include <cstddef>
+
+// Must be included last.
+#include "google/protobuf/port_def.inc"
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+// The ReflectionModes are ordered in observability levels:
+// kDefault: Lowest level. All reflection calls are observable.
+// kDebugString: Middle level. Only reflection calls in Message::DebugString are
+// observable.
+// kDiagnostics: Highest level. No reflection calls are observable.
+enum class ReflectionMode {
+ kDefault,
+ kDebugString,
+ kDiagnostics,
+};
+
+// Returns the current ReflectionMode of protobuf for the current thread. This
+// reflection mode can be used by interceptors to ignore any reflection calls
+// not affecting the application behavior.
+// Always returns `kDefault' if the current platform does not support thread
+// local data.
+ReflectionMode GetReflectionMode();
+
+// Scoping class to set the specific ReflectionMode for a given scope.
+class PROTOBUF_EXPORT ScopedReflectionMode final {
+ public:
+ // Sets the current reflection mode, which will be restored at destruction.
+ // The reflection mode can only be 'elevated' in observability levels.
+ // For instance, if the current mode is `kDiagnostics` then scope will remain
+ // unchanged regardless of `mode`.
+ explicit ScopedReflectionMode(ReflectionMode mode);
+
+ // Restores the previous reflection mode.
+ ~ScopedReflectionMode();
+
+ // Returns the scoped ReflectionMode for the current thread.
+ // See `GetReflectionMode()` for more information on purpose and usage.
+ static ReflectionMode current_reflection_mode();
+
+ // ScopedReflectionMode is only intended to be used as a locally scoped
+ // instance to set a reflection mode for the code scoped by this instance.
+ ScopedReflectionMode(const ScopedReflectionMode&) = delete;
+ ScopedReflectionMode& operator=(const ScopedReflectionMode&) = delete;
+
+ private:
+#if !defined(PROTOBUF_NO_THREADLOCAL)
+ const ReflectionMode previous_mode_;
+#if defined(PROTOBUF_USE_DLLS)
+ static ReflectionMode& reflection_mode();
+#else
+ PROTOBUF_CONSTINIT static PROTOBUF_THREAD_LOCAL ReflectionMode
+ reflection_mode_;
+#endif // PROTOBUF_USE_DLLS
+#endif // !PROTOBUF_NO_THREADLOCAL
+};
+
+#if !defined(PROTOBUF_NO_THREADLOCAL)
+
+#if defined(PROTOBUF_USE_DLLS)
+
+inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode)
+ : previous_mode_(reflection_mode()) {
+ if (mode > reflection_mode()) {
+ reflection_mode() = mode;
+ }
+}
+
+inline ScopedReflectionMode::~ScopedReflectionMode() {
+ reflection_mode() = previous_mode_;
+}
+
+inline ReflectionMode ScopedReflectionMode::current_reflection_mode() {
+ return reflection_mode();
+}
+
+#else
+
+inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode)
+ : previous_mode_(reflection_mode_) {
+ if (mode > reflection_mode_) {
+ reflection_mode_ = mode;
+ }
+}
+
+inline ScopedReflectionMode::~ScopedReflectionMode() {
+ reflection_mode_ = previous_mode_;
+}
+
+inline ReflectionMode ScopedReflectionMode::current_reflection_mode() {
+ return reflection_mode_;
+}
+
+#endif // PROTOBUF_USE_DLLS
+
+#else
+
+inline ScopedReflectionMode::ScopedReflectionMode(ReflectionMode mode) {}
+inline ScopedReflectionMode::~ScopedReflectionMode() {}
+inline ReflectionMode ScopedReflectionMode::current_reflection_mode() {
+ return ReflectionMode::kDefault;
+}
+
+#endif // !PROTOBUF_NO_THREADLOCAL
+
+inline ReflectionMode GetReflectionMode() {
+ return ScopedReflectionMode::current_reflection_mode();
+}
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
+
+#include "google/protobuf/port_undef.inc"
+
+#endif // GOOGLE_PROTOBUF_REFLECTION_MODE_H__
diff --git a/src/google/protobuf/reflection_mode_test.cc b/src/google/protobuf/reflection_mode_test.cc
new file mode 100644
index 0000000..9320888
--- /dev/null
+++ b/src/google/protobuf/reflection_mode_test.cc
@@ -0,0 +1,115 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2023 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 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
+// OWNER 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 "google/protobuf/reflection_mode.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace google {
+namespace protobuf {
+namespace internal {
+
+#ifndef PROTOBUF_NO_THREADLOCAL
+
+TEST(ReflectionModeTest, SimpleScopedReflection) {
+ ASSERT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ ScopedReflectionMode scope(ReflectionMode::kDiagnostics);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDiagnostics);
+}
+
+TEST(ReflectionModeTest, CleanNestedScopedReflection) {
+ ASSERT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ {
+ ScopedReflectionMode scope1(ReflectionMode::kDebugString);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDebugString);
+ {
+ ScopedReflectionMode scope2(ReflectionMode::kDiagnostics);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDiagnostics);
+ }
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDebugString);
+ }
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+}
+
+TEST(ReflectionModeTest, UglyNestedScopedReflection) {
+ ASSERT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ ScopedReflectionMode scope1(ReflectionMode::kDebugString);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDebugString);
+ ScopedReflectionMode scope2(ReflectionMode::kDiagnostics);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDiagnostics);
+}
+
+TEST(ReflectionModeTest, DebugStringModeDoesNotReplaceDiagnosticsMode) {
+ ASSERT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ ScopedReflectionMode scope1(ReflectionMode::kDiagnostics);
+ {
+ ScopedReflectionMode scope2(ReflectionMode::kDebugString);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDiagnostics);
+ }
+}
+
+#else
+
+TEST(ReflectionModeTest, AlwaysReturnDefaultWhenNoThreadLocal) {
+ ASSERT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ {
+ ScopedReflectionMode scope1(ReflectionMode::kDebugString);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ {
+ ScopedReflectionMode scope2(ReflectionMode::kDiagnostics);
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ }
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+ }
+ EXPECT_EQ(ScopedReflectionMode::current_reflection_mode(),
+ ReflectionMode::kDefault);
+}
+
+#endif
+
+} // namespace internal
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc
index 248f01e..f3b4f23 100644
--- a/src/google/protobuf/repeated_field_unittest.cc
+++ b/src/google/protobuf/repeated_field_unittest.cc
@@ -201,34 +201,24 @@
CheckAllocationSizes<RepeatedField<uint64_t>>(false);
}
-template <typename Rep>
-void CheckNaturalGrowthOnArenasReuseBlocks(bool is_ptr) {
+TEST(RepeatedField, NaturalGrowthOnArenasReuseBlocks) {
Arena arena;
- std::vector<Rep*> values;
- using T = typename Rep::value_type;
+ std::vector<RepeatedField<int>*> values;
static constexpr int kNumFields = 100;
static constexpr int kNumElems = 1000;
for (int i = 0; i < kNumFields; ++i) {
- values.push_back(Arena::CreateMessage<Rep>(&arena));
+ values.push_back(Arena::CreateMessage<RepeatedField<int>>(&arena));
auto& field = *values.back();
for (int j = 0; j < kNumElems; ++j) {
- field.Add(T{});
+ field.Add(j);
}
}
- size_t used_bytes_if_reusing =
- values.size() * values[0]->Capacity() * (is_ptr ? sizeof(T*) : sizeof(T));
- // Use a 2% slack for other overhead.
- // If we were not reusing the blocks, the actual value would be ~2x the
- // expected.
- EXPECT_THAT(
- arena.SpaceUsed() - (is_ptr ? sizeof(T) * kNumElems * kNumFields : 0),
- AllOf(Ge(used_bytes_if_reusing), Le(1.02 * used_bytes_if_reusing)));
-}
-
-TEST(RepeatedField, NaturalGrowthOnArenasReuseBlocks) {
- CheckNaturalGrowthOnArenasReuseBlocks<RepeatedField<int>>(false);
+ size_t expected = values.size() * values[0]->Capacity() * sizeof(int);
+ // Use a 2% slack for other overhead. If we were not reusing the blocks, the
+ // actual value would be ~2x the expected.
+ EXPECT_THAT(arena.SpaceUsed(), AllOf(Ge(expected), Le(1.02 * expected)));
}
// Test swapping between various types of RepeatedFields.
@@ -1358,7 +1348,27 @@
}
TEST(RepeatedPtrField, NaturalGrowthOnArenasReuseBlocks) {
- CheckNaturalGrowthOnArenasReuseBlocks<RepeatedPtrField<std::string>>(true);
+ using Rep = RepeatedPtrField<std::string>;
+ Arena arena;
+ std::vector<Rep*> values;
+
+ static constexpr int kNumFields = 100;
+ static constexpr int kNumElems = 1000;
+ for (int i = 0; i < kNumFields; ++i) {
+ values.push_back(Arena::CreateMessage<Rep>(&arena));
+ auto& field = *values.back();
+ for (int j = 0; j < kNumElems; ++j) {
+ field.Add("");
+ }
+ }
+
+ size_t expected =
+ values.size() * values[0]->Capacity() * sizeof(std::string*) +
+ sizeof(std::string) * kNumElems * kNumFields;
+ // Use a 2% slack for other overhead.
+ // If we were not reusing the blocks, the actual value would be ~2x the
+ // expected.
+ EXPECT_THAT(arena.SpaceUsed(), AllOf(Ge(expected), Le(1.02 * expected)));
}
TEST(RepeatedPtrField, AddAndAssignRanges) {
diff --git a/src/google/protobuf/serial_arena.h b/src/google/protobuf/serial_arena.h
index 95767f6..8ac5cdd 100644
--- a/src/google/protobuf/serial_arena.h
+++ b/src/google/protobuf/serial_arena.h
@@ -333,6 +333,19 @@
static size_t FreeStringBlocks(StringBlock* string_block, size_t unused);
+ // Adds 'used` to space_used_ in relaxed atomic order.
+ void AddSpaceUsed(size_t space_used) {
+ space_used_.store(space_used_.load(std::memory_order_relaxed) + space_used,
+ std::memory_order_relaxed);
+ }
+
+ // Adds 'allocated` to space_allocated_ in relaxed atomic order.
+ void AddSpaceAllocated(size_t space_allocated) {
+ space_allocated_.store(
+ space_allocated_.load(std::memory_order_relaxed) + space_allocated,
+ std::memory_order_relaxed);
+ }
+
// Members are declared here to track sizeof(SerialArena) and hotness
// centrally. They are (roughly) laid out in descending order of hotness.
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index ee2b4ff..c16e410 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -96,6 +96,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/string_block.h b/src/google/protobuf/string_block.h
index fd7812b..b105d57 100644
--- a/src/google/protobuf/string_block.h
+++ b/src/google/protobuf/string_block.h
@@ -62,11 +62,21 @@
StringBlock(const StringBlock&) = delete;
StringBlock& operator=(const StringBlock&) = delete;
+ // Returns the size of the next string block based on the size information
+ // stored in `block`. `block` may be null in which case the size of the
+ // initial string block is returned.
+ static size_t NextSize(StringBlock* block);
+
// Allocates a new StringBlock pointing to `next`, which can be null.
// The size of the returned block depends on the allocated size of `next`.
static StringBlock* New(StringBlock* next);
- // Deletes `block`. `block` must not be null.
+ // Allocates a new string block `in place`. `n` must be the value returned
+ // from a previous call to `StringBlock::NextSize(next)`
+ static StringBlock* Emplace(void* p, size_t n, StringBlock* next);
+
+ // Deletes `block` if `block` is heap allocated. `block` must not be null.
+ // Returns the allocated size of `block`, or 0 if the block was emplaced.
static size_t Delete(StringBlock* block);
StringBlock* next() const;
@@ -86,6 +96,9 @@
// Returns the total allocation size of this instance.
size_t allocated_size() const { return allocated_size_; }
+ // Returns true if this block is heap allocated, false if emplaced.
+ bool heap_allocated() const { return heap_allocated_; }
+
// Returns the effective size available for allocation string instances.
// This value is guaranteed to be a multiple of sizeof(std::string), and
// guaranteed to never be zero.
@@ -97,21 +110,44 @@
~StringBlock() = default;
- explicit StringBlock(StringBlock* next, uint32_t size,
+ explicit StringBlock(StringBlock* next, bool heap_allocated, uint32_t size,
uint32_t next_size) noexcept
- : next_(next), allocated_size_(size), next_size_(next_size) {}
+ : next_(next),
+ heap_allocated_(heap_allocated),
+ allocated_size_(size),
+ next_size_(next_size) {}
static constexpr uint32_t min_size() { return size_t{256}; }
static constexpr uint32_t max_size() { return size_t{8192}; }
+ // Returns `size` rounded down such that we can fit a perfect number
+ // of std::string instances inside a StringBlock of that size.
+ static constexpr uint32_t RoundedSize(uint32_t size);
+
// Returns the size of the next block.
size_t next_size() const { return next_size_; }
StringBlock* const next_;
- const uint32_t allocated_size_;
+ const bool heap_allocated_ : 1;
+ const uint32_t allocated_size_ : 31;
const uint32_t next_size_;
};
+constexpr uint32_t StringBlock::RoundedSize(uint32_t size) {
+ return size - (size - sizeof(StringBlock)) % sizeof(std::string);
+}
+
+inline size_t StringBlock::NextSize(StringBlock* block) {
+ return block ? block->next_size() : min_size();
+}
+
+inline StringBlock* StringBlock::Emplace(void* p, size_t n, StringBlock* next) {
+ ABSL_DCHECK_EQ(n, NextSize(next));
+ uint32_t doubled = static_cast<uint32_t>(n) * 2;
+ uint32_t next_size = next ? std::min(doubled, max_size()) : min_size();
+ return new (p) StringBlock(next, false, RoundedSize(n), next_size);
+}
+
inline StringBlock* StringBlock::New(StringBlock* next) {
// Compute required size, rounding down to a multiple of sizeof(std:string)
// so that we can optimize the allocation path. I.e., we incur a (constant
@@ -122,13 +158,14 @@
size = next->next_size_;
next_size = std::min(size * 2, max_size());
}
- size -= (size - sizeof(StringBlock)) % sizeof(std::string);
+ size = RoundedSize(size);
void* p = ::operator new(size);
- return new (p) StringBlock(next, size, next_size);
+ return new (p) StringBlock(next, true, size, next_size);
}
inline size_t StringBlock::Delete(StringBlock* block) {
ABSL_DCHECK(block != nullptr);
+ if (!block->heap_allocated_) return size_t{0};
size_t size = block->allocated_size();
internal::SizedDelete(block, size);
return size;
diff --git a/src/google/protobuf/string_block_test.cc b/src/google/protobuf/string_block_test.cc
index ff1c71f..3c4562d 100644
--- a/src/google/protobuf/string_block_test.cc
+++ b/src/google/protobuf/string_block_test.cc
@@ -33,7 +33,9 @@
#include "google/protobuf/string_block.h"
#include <cstddef>
+#include <memory>
#include <string>
+#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -58,10 +60,12 @@
return EffectiveSizeFor(size) + sizeof(StringBlock);
}
-TEST(StringBlockTest, OneNewBlock) {
+TEST(StringBlockTest, HeapAllocateOneBlock) {
StringBlock* block = StringBlock::New(nullptr);
+
ASSERT_THAT(block, Ne(nullptr));
EXPECT_THAT(block->next(), Eq(nullptr));
+ ASSERT_TRUE(block->heap_allocated());
EXPECT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(256)));
EXPECT_THAT(block->effective_size(), Eq(EffectiveSizeFor(256)));
EXPECT_THAT(block->begin(), Eq(block->AtOffset(0)));
@@ -70,7 +74,26 @@
EXPECT_THAT(StringBlock::Delete(block), Eq(AllocatedSizeFor(256)));
}
-TEST(StringBlockTest, NewBlocks) {
+TEST(StringBlockTest, EmplaceOneBlock) {
+ // NextSize() returns unrounded 'min_size()' on first call.
+ size_t size = StringBlock::NextSize(nullptr);
+ EXPECT_THAT(size, Eq(256));
+
+ auto buffer = std::make_unique<char[]>(size);
+ StringBlock* block = StringBlock::Emplace(buffer.get(), size, nullptr);
+
+ ASSERT_THAT(block, Ne(nullptr));
+ EXPECT_THAT(block->next(), Eq(nullptr));
+ ASSERT_FALSE(block->heap_allocated());
+ EXPECT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(256)));
+ EXPECT_THAT(block->effective_size(), Eq(EffectiveSizeFor(256)));
+ EXPECT_THAT(block->begin(), Eq(block->AtOffset(0)));
+ EXPECT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
+
+ EXPECT_THAT(StringBlock::Delete(block), Eq(0));
+}
+
+TEST(StringBlockTest, HeapAllocateMultipleBlocks) {
// Note: first two blocks are 256
StringBlock* previous = StringBlock::New(nullptr);
@@ -78,6 +101,7 @@
StringBlock* block = StringBlock::New(previous);
ASSERT_THAT(block, Ne(nullptr));
ASSERT_THAT(block->next(), Eq(previous));
+ ASSERT_TRUE(block->heap_allocated());
ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(size)));
ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(size)));
ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
@@ -88,7 +112,8 @@
// Capped at 8K from here on
StringBlock* block = StringBlock::New(previous);
ASSERT_THAT(block, Ne(nullptr));
- EXPECT_THAT(block->next(), Eq(previous));
+ ASSERT_THAT(block->next(), Eq(previous));
+ ASSERT_TRUE(block->heap_allocated());
ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(8192)));
ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(8192)));
ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
@@ -102,6 +127,48 @@
}
}
+TEST(StringBlockTest, EmplaceMultipleBlocks) {
+ std::vector<std::unique_ptr<char[]>> buffers;
+
+ // Convenience lambda to allocate a buffer and invoke Emplace on it.
+ auto EmplaceBlock = [&](StringBlock* previous) {
+ size_t size = StringBlock::NextSize(previous);
+ buffers.push_back(std::make_unique<char[]>(size));
+ return StringBlock::Emplace(buffers.back().get(), size, previous);
+ };
+
+ // Note: first two blocks are 256
+ StringBlock* previous = EmplaceBlock(nullptr);
+
+ for (int size = 256; size <= 8192; size *= 2) {
+ StringBlock* block = EmplaceBlock(previous);
+ ASSERT_THAT(block, Ne(nullptr));
+ ASSERT_THAT(block->next(), Eq(previous));
+ ASSERT_FALSE(block->heap_allocated());
+ ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(size)));
+ ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(size)));
+ ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
+ ASSERT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
+ previous = block;
+ }
+
+ // Capped at 8K from here on
+ StringBlock* block = EmplaceBlock(previous);
+ ASSERT_THAT(block, Ne(nullptr));
+ EXPECT_THAT(block->next(), Eq(previous));
+ ASSERT_FALSE(block->heap_allocated());
+ ASSERT_THAT(block->allocated_size(), Eq(AllocatedSizeFor(8192)));
+ ASSERT_THAT(block->effective_size(), Eq(EffectiveSizeFor(8192)));
+ ASSERT_THAT(block->begin(), Eq(block->AtOffset(0)));
+ ASSERT_THAT(block->end(), Eq(block->AtOffset(block->effective_size())));
+
+ while (block) {
+ StringBlock* next = block->next();
+ EXPECT_THAT(StringBlock::Delete(block), Eq(0));
+ block = next;
+ }
+}
+
} // namespace
} // namespace internal
} // namespace protobuf
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index a5fa0b8..b1f1f4a 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -618,7 +618,7 @@
// .google.protobuf.NullValue null_value = 1;
case 1:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 8)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
_internal_set_null_value(static_cast<::PROTOBUF_NAMESPACE_ID::NullValue>(val));
} else {
@@ -701,49 +701,46 @@
::uint32_t cached_has_bits = 0;
(void) cached_has_bits;
- // .google.protobuf.NullValue null_value = 1;
- if (kind_case() == kNullValue) {
- target = stream->EnsureSpace(target);
- target = ::_pbi::WireFormatLite::WriteEnumToArray(
- 1, this->_internal_null_value(), target);
+ switch (kind_case()) {
+ case kNullValue: {
+ target = stream->EnsureSpace(target);
+ target = ::_pbi::WireFormatLite::WriteEnumToArray(
+ 1, this->_internal_null_value(), target);
+ break;
+ }
+ case kNumberValue: {
+ target = stream->EnsureSpace(target);
+ target = ::_pbi::WireFormatLite::WriteDoubleToArray(
+ 2, this->_internal_number_value(), target);
+ break;
+ }
+ case kStringValue: {
+ const std::string& _s = this->_internal_string_value();
+ ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+ _s.data(), static_cast<int>(_s.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "google.protobuf.Value.string_value");
+ target = stream->WriteStringMaybeAliased(3, _s, target);
+ break;
+ }
+ case kBoolValue: {
+ target = stream->EnsureSpace(target);
+ target = ::_pbi::WireFormatLite::WriteBoolToArray(
+ 4, this->_internal_bool_value(), target);
+ break;
+ }
+ case kStructValue: {
+ target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+ InternalWriteMessage(5, _Internal::struct_value(this),
+ _Internal::struct_value(this).GetCachedSize(), target, stream);
+ break;
+ }
+ case kListValue: {
+ target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
+ InternalWriteMessage(6, _Internal::list_value(this),
+ _Internal::list_value(this).GetCachedSize(), target, stream);
+ break;
+ }
+ default: ;
}
-
- // double number_value = 2;
- if (kind_case() == kNumberValue) {
- target = stream->EnsureSpace(target);
- target = ::_pbi::WireFormatLite::WriteDoubleToArray(
- 2, this->_internal_number_value(), target);
- }
-
- // string string_value = 3;
- if (kind_case() == kStringValue) {
- const std::string& _s = this->_internal_string_value();
- ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
- _s.data(), static_cast<int>(_s.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "google.protobuf.Value.string_value");
- target = stream->WriteStringMaybeAliased(3, _s, target);
- }
-
- // bool bool_value = 4;
- if (kind_case() == kBoolValue) {
- target = stream->EnsureSpace(target);
- target = ::_pbi::WireFormatLite::WriteBoolToArray(
- 4, this->_internal_bool_value(), target);
- }
-
- // .google.protobuf.Struct struct_value = 5;
- if (kind_case() == kStructValue) {
- target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
- InternalWriteMessage(5, _Internal::struct_value(this),
- _Internal::struct_value(this).GetCachedSize(), target, stream);
- }
-
- // .google.protobuf.ListValue list_value = 6;
- if (kind_case() == kListValue) {
- target = ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::
- InternalWriteMessage(6, _Internal::list_value(this),
- _Internal::list_value(this).GetCachedSize(), target, stream);
- }
-
if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
_internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 6494421..7863324 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -171,6 +171,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -332,6 +339,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -596,6 +610,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto
index c4ea645..1bf0c1a 100644
--- a/src/google/protobuf/struct.proto
+++ b/src/google/protobuf/struct.proto
@@ -80,7 +80,7 @@
// `NullValue` is a singleton enumeration to represent the null value for the
// `Value` type union.
//
-// The JSON representation for `NullValue` is JSON `null`.
+// The JSON representation for `NullValue` is JSON `null`.
enum NullValue {
// Null value.
NULL_VALUE = 0;
diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h
index 80426dc..3255944 100644
--- a/src/google/protobuf/stubs/common.h
+++ b/src/google/protobuf/stubs/common.h
@@ -74,15 +74,15 @@
// The minimum header version which works with the current version of
// the library. This constant should only be used by protoc's C++ code
// generator.
-static const int kMinHeaderVersionForLibrary = 4022000;
+static const int kMinHeaderVersionForLibrary = 3021000;
// The minimum protoc version which works with the current version of the
// headers.
-#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 4022000
+#define GOOGLE_PROTOBUF_MIN_PROTOC_VERSION 3021000
// The minimum header version which works with the current version of
// protoc. This constant should only be used in VerifyVersion().
-static const int kMinHeaderVersionForProtoc = 4022000;
+static const int kMinHeaderVersionForProtoc = 3021000;
// Verifies that the headers and libraries are compatible. Use the macro
// below to call this.
diff --git a/src/google/protobuf/test_messages_proto2.proto b/src/google/protobuf/test_messages_proto2.proto
index 1cc7c86..088bfa7 100644
--- a/src/google/protobuf/test_messages_proto2.proto
+++ b/src/google/protobuf/test_messages_proto2.proto
@@ -301,3 +301,97 @@
optional string concept = 2;
repeated string requires = 3;
}
+
+message TestAllRequiredTypesProto2 {
+ message NestedMessage {
+ required int32 a = 1;
+ required TestAllRequiredTypesProto2 corecursive = 2;
+ optional TestAllRequiredTypesProto2 optional_corecursive = 3;
+ }
+
+ enum NestedEnum {
+ FOO = 0;
+ BAR = 1;
+ BAZ = 2;
+ NEG = -1; // Intentionally negative.
+ }
+
+ // Singular
+ required int32 required_int32 = 1;
+ required int64 required_int64 = 2;
+ required uint32 required_uint32 = 3;
+ required uint64 required_uint64 = 4;
+ required sint32 required_sint32 = 5;
+ required sint64 required_sint64 = 6;
+ required fixed32 required_fixed32 = 7;
+ required fixed64 required_fixed64 = 8;
+ required sfixed32 required_sfixed32 = 9;
+ required sfixed64 required_sfixed64 = 10;
+ required float required_float = 11;
+ required double required_double = 12;
+ required bool required_bool = 13;
+ required string required_string = 14;
+ required bytes required_bytes = 15;
+
+ required NestedMessage required_nested_message = 18;
+ required ForeignMessageProto2 required_foreign_message = 19;
+
+ required NestedEnum required_nested_enum = 21;
+ required ForeignEnumProto2 required_foreign_enum = 22;
+
+ required string required_string_piece = 24 [ctype = STRING_PIECE];
+ required string required_cord = 25 [ctype = CORD];
+
+ required TestAllRequiredTypesProto2 recursive_message = 27;
+ optional TestAllRequiredTypesProto2 optional_recursive_message = 28;
+
+ // extensions
+ extensions 120 to 200;
+
+ // groups
+ required group Data = 201 {
+ required int32 group_int32 = 202;
+ required uint32 group_uint32 = 203;
+ }
+
+ // default values
+ required int32 default_int32 = 241 [default = -123456789];
+ required int64 default_int64 = 242 [default = -9123456789123456789];
+ required uint32 default_uint32 = 243 [default = 2123456789];
+ required uint64 default_uint64 = 244 [default = 10123456789123456789];
+ required sint32 default_sint32 = 245 [default = -123456789];
+ required sint64 default_sint64 = 246 [default = -9123456789123456789];
+ required fixed32 default_fixed32 = 247 [default = 2123456789];
+ required fixed64 default_fixed64 = 248 [default = 10123456789123456789];
+ required sfixed32 default_sfixed32 = 249 [default = -123456789];
+ required sfixed64 default_sfixed64 = 250 [default = -9123456789123456789];
+ required float default_float = 251 [default = 9e9];
+ required double default_double = 252 [default = 7e22];
+ required bool default_bool = 253 [default = true];
+ required string default_string = 254 [default = "Rosebud"];
+ required bytes default_bytes = 255 [default = "joshua"];
+
+ // Reserved for unknown fields test.
+ reserved 1000 to 9999;
+
+ // message_set test case.
+ message MessageSetCorrect {
+ option message_set_wire_format = true;
+
+ extensions 4 to max;
+ }
+
+ message MessageSetCorrectExtension1 {
+ extend MessageSetCorrect {
+ optional MessageSetCorrectExtension1 message_set_extension = 1547769;
+ }
+ required string str = 25;
+ }
+
+ message MessageSetCorrectExtension2 {
+ extend MessageSetCorrect {
+ optional MessageSetCorrectExtension2 message_set_extension = 4135312;
+ }
+ required int32 i = 9;
+ }
+}
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index 57ff14f..de994f4 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -64,6 +64,7 @@
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/map_field.h"
#include "google/protobuf/message.h"
+#include "google/protobuf/reflection_mode.h"
#include "google/protobuf/repeated_field.h"
#include "google/protobuf/unknown_field_set.h"
#include "google/protobuf/wire_format_lite.h"
@@ -74,6 +75,9 @@
namespace google {
namespace protobuf {
+using internal::ReflectionMode;
+using internal::ScopedReflectionMode;
+
namespace {
inline bool IsHexNumber(const std::string& str) {
@@ -103,6 +107,8 @@
} // namespace internal
std::string Message::DebugString() const {
+ // Indicate all scoped reflection calls are from DebugString function.
+ ScopedReflectionMode scope(ReflectionMode::kDebugString);
std::string debug_string;
TextFormat::Printer printer;
@@ -122,6 +128,8 @@
}
std::string Message::ShortDebugString() const {
+ // Indicate all scoped reflection calls are from DebugString function.
+ ScopedReflectionMode scope(ReflectionMode::kDebugString);
std::string debug_string;
TextFormat::Printer printer;
@@ -146,6 +154,8 @@
}
std::string Message::Utf8DebugString() const {
+ // Indicate all scoped reflection calls are from DebugString function.
+ ScopedReflectionMode scope(ReflectionMode::kDebugString);
std::string debug_string;
TextFormat::Printer printer;
@@ -171,6 +181,9 @@
void PerformAbslStringify(const Message& message,
absl::FunctionRef<void(absl::string_view)> append) {
+ // Indicate all scoped reflection calls are from DebugString function.
+ ScopedReflectionMode scope(ReflectionMode::kDebugString);
+
// TODO(b/249835002): consider using the single line version for short
TextFormat::Printer printer;
printer.SetExpandAny(true);
@@ -905,7 +918,7 @@
if (enum_value == nullptr) {
if (int_value != kint64max &&
- reflection->SupportsUnknownEnumValues()) {
+ !field->legacy_enum_field_treated_as_closed()) {
SET_FIELD(EnumValue, int_value);
return true;
} else if (!allow_unknown_enum_) {
@@ -2686,18 +2699,23 @@
return Parser().ParseFieldValueFromString(input, field, message);
}
+template <typename... T>
+PROTOBUF_NOINLINE void TextFormat::OutOfLinePrintString(
+ BaseTextGenerator* generator, const T&... values) {
+ generator->PrintString(absl::StrCat(values...));
+}
+
void TextFormat::Printer::PrintUnknownFields(
const UnknownFieldSet& unknown_fields, BaseTextGenerator* generator,
int recursion_budget) const {
for (int i = 0; i < unknown_fields.field_count(); i++) {
const UnknownField& field = unknown_fields.field(i);
- std::string field_number = absl::StrCat(field.number());
switch (field.type()) {
case UnknownField::TYPE_VARINT:
- generator->PrintString(field_number);
+ OutOfLinePrintString(generator, field.number());
generator->PrintMaybeWithMarker(MarkerToken(), ": ");
- generator->PrintString(absl::StrCat(field.varint()));
+ OutOfLinePrintString(generator, field.varint());
if (single_line_mode_) {
generator->PrintLiteral(" ");
} else {
@@ -2705,10 +2723,10 @@
}
break;
case UnknownField::TYPE_FIXED32: {
- generator->PrintString(field_number);
+ OutOfLinePrintString(generator, field.number());
generator->PrintMaybeWithMarker(MarkerToken(), ": ", "0x");
- generator->PrintString(
- absl::StrCat(absl::Hex(field.fixed32(), absl::kZeroPad8)));
+ OutOfLinePrintString(generator,
+ absl::Hex(field.fixed32(), absl::kZeroPad8));
if (single_line_mode_) {
generator->PrintLiteral(" ");
} else {
@@ -2717,10 +2735,10 @@
break;
}
case UnknownField::TYPE_FIXED64: {
- generator->PrintString(field_number);
+ OutOfLinePrintString(generator, field.number());
generator->PrintMaybeWithMarker(MarkerToken(), ": ", "0x");
- generator->PrintString(
- absl::StrCat(absl::Hex(field.fixed64(), absl::kZeroPad16)));
+ OutOfLinePrintString(generator,
+ absl::Hex(field.fixed64(), absl::kZeroPad16));
if (single_line_mode_) {
generator->PrintLiteral(" ");
} else {
@@ -2729,7 +2747,7 @@
break;
}
case UnknownField::TYPE_LENGTH_DELIMITED: {
- generator->PrintString(field_number);
+ OutOfLinePrintString(generator, field.number());
const std::string& value = field.length_delimited();
// We create a CodedInputStream so that we can adhere to our recursion
// budget when we attempt to parse the data. UnknownFieldSet parsing is
@@ -2770,7 +2788,7 @@
break;
}
case UnknownField::TYPE_GROUP:
- generator->PrintString(field_number);
+ OutOfLinePrintString(generator, field.number());
if (single_line_mode_) {
generator->PrintMaybeWithMarker(MarkerToken(), " ", "{ ");
} else {
diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h
index 122c8a4..74f954b 100644
--- a/src/google/protobuf/text_format.h
+++ b/src/google/protobuf/text_format.h
@@ -141,7 +141,7 @@
// Print text to the output stream.
virtual void Print(const char* text, size_t size) = 0;
- void PrintString(const std::string& str) { Print(str.data(), str.size()); }
+ void PrintString(absl::string_view str) { Print(str.data(), str.size()); }
template <size_t n>
void PrintLiteral(const char (&text)[n]) {
@@ -724,6 +724,11 @@
ParseLocationRange location);
static inline ParseInfoTree* CreateNested(ParseInfoTree* info_tree,
const FieldDescriptor* field);
+ // To reduce stack frame bloat we use an out-of-line function to print
+ // strings. This avoid local std::string temporaries.
+ template <typename... T>
+ static void OutOfLinePrintString(BaseTextGenerator* generator,
+ const T&... values);
};
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index f171855..7920acc 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -297,6 +297,22 @@
message.DebugString());
}
+TEST_F(TextFormatTest, PrintUnknownFieldsDeepestStackWorks) {
+ // Test printing of unknown fields in a message.
+
+ unittest::TestEmptyMessage message;
+ UnknownFieldSet* unknown_fields = message.mutable_unknown_fields();
+
+ for (int i = 0; i < 200; ++i) {
+ unknown_fields = unknown_fields->AddGroup(1);
+ }
+
+ unknown_fields->AddVarint(2, 100);
+
+ std::string str;
+ EXPECT_TRUE(TextFormat::PrintToString(message, &str));
+}
+
TEST_F(TextFormatTest, PrintUnknownFieldsHidden) {
// Test printing of unknown fields in a message when suppressed.
@@ -2350,6 +2366,7 @@
std::signbit(out_message.optional_double()));
}
+
} // namespace text_format_unittest
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 86ffd2a..bb9082b 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -96,6 +96,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index c608689..15a9d80 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -28,6 +28,10 @@
&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized {}
}
+ , /*decltype(_impl_.edition_)*/ {
+ &::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized {}
+ }
+
, /*decltype(_impl_.source_context_)*/nullptr
, /*decltype(_impl_.syntax_)*/ 0
@@ -90,6 +94,10 @@
&::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized {}
}
+ , /*decltype(_impl_.edition_)*/ {
+ &::_pbi::fixed_address_empty_string, ::_pbi::ConstantInitialized {}
+ }
+
, /*decltype(_impl_.source_context_)*/nullptr
, /*decltype(_impl_.syntax_)*/ 0
@@ -163,6 +171,7 @@
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.options_),
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.source_context_),
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.syntax_),
+ PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Type, _impl_.edition_),
~0u, // no _has_bits_
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Field, _internal_metadata_),
~0u, // no _extensions_
@@ -194,6 +203,7 @@
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.options_),
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.source_context_),
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.syntax_),
+ PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::Enum, _impl_.edition_),
~0u, // no _has_bits_
PROTOBUF_FIELD_OFFSET(::PROTOBUF_NAMESPACE_ID::EnumValue, _internal_metadata_),
~0u, // no _extensions_
@@ -220,10 +230,10 @@
static const ::_pbi::MigrationSchema
schemas[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
{ 0, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Type)},
- { 14, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Field)},
- { 32, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Enum)},
- { 45, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValue)},
- { 56, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Option)},
+ { 15, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Field)},
+ { 33, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Enum)},
+ { 47, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::EnumValue)},
+ { 58, -1, -1, sizeof(::PROTOBUF_NAMESPACE_ID::Option)},
};
static const ::_pb::Message* const file_default_instances[] = {
@@ -236,44 +246,46 @@
const char descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto[] PROTOBUF_SECTION_VARIABLE(protodesc_cold) = {
"\n\032google/protobuf/type.proto\022\017google.pro"
"tobuf\032\031google/protobuf/any.proto\032$google"
- "/protobuf/source_context.proto\"\327\001\n\004Type\022"
+ "/protobuf/source_context.proto\"\350\001\n\004Type\022"
"\014\n\004name\030\001 \001(\t\022&\n\006fields\030\002 \003(\0132\026.google.p"
"rotobuf.Field\022\016\n\006oneofs\030\003 \003(\t\022(\n\007options"
"\030\004 \003(\0132\027.google.protobuf.Option\0226\n\016sourc"
"e_context\030\005 \001(\0132\036.google.protobuf.Source"
"Context\022\'\n\006syntax\030\006 \001(\0162\027.google.protobu"
- "f.Syntax\"\325\005\n\005Field\022)\n\004kind\030\001 \001(\0162\033.googl"
- "e.protobuf.Field.Kind\0227\n\013cardinality\030\002 \001"
- "(\0162\".google.protobuf.Field.Cardinality\022\016"
- "\n\006number\030\003 \001(\005\022\014\n\004name\030\004 \001(\t\022\020\n\010type_url"
- "\030\006 \001(\t\022\023\n\013oneof_index\030\007 \001(\005\022\016\n\006packed\030\010 "
- "\001(\010\022(\n\007options\030\t \003(\0132\027.google.protobuf.O"
- "ption\022\021\n\tjson_name\030\n \001(\t\022\025\n\rdefault_valu"
- "e\030\013 \001(\t\"\310\002\n\004Kind\022\020\n\014TYPE_UNKNOWN\020\000\022\017\n\013TY"
- "PE_DOUBLE\020\001\022\016\n\nTYPE_FLOAT\020\002\022\016\n\nTYPE_INT6"
- "4\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n\nTYPE_INT32\020\005\022\020\n\014"
- "TYPE_FIXED64\020\006\022\020\n\014TYPE_FIXED32\020\007\022\r\n\tTYPE"
- "_BOOL\020\010\022\017\n\013TYPE_STRING\020\t\022\016\n\nTYPE_GROUP\020\n"
- "\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nTYPE_BYTES\020\014\022\017\n\013TY"
- "PE_UINT32\020\r\022\r\n\tTYPE_ENUM\020\016\022\021\n\rTYPE_SFIXE"
- "D32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SINT32\020"
- "\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013Cardinality\022\027\n\023CAR"
- "DINALITY_UNKNOWN\020\000\022\030\n\024CARDINALITY_OPTION"
- "AL\020\001\022\030\n\024CARDINALITY_REQUIRED\020\002\022\030\n\024CARDIN"
- "ALITY_REPEATED\020\003\"\316\001\n\004Enum\022\014\n\004name\030\001 \001(\t\022"
- "-\n\tenumvalue\030\002 \003(\0132\032.google.protobuf.Enu"
- "mValue\022(\n\007options\030\003 \003(\0132\027.google.protobu"
- "f.Option\0226\n\016source_context\030\004 \001(\0132\036.googl"
- "e.protobuf.SourceContext\022\'\n\006syntax\030\005 \001(\016"
- "2\027.google.protobuf.Syntax\"S\n\tEnumValue\022\014"
- "\n\004name\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\022(\n\007options\030"
- "\003 \003(\0132\027.google.protobuf.Option\";\n\006Option"
- "\022\014\n\004name\030\001 \001(\t\022#\n\005value\030\002 \001(\0132\024.google.p"
- "rotobuf.Any*.\n\006Syntax\022\021\n\rSYNTAX_PROTO2\020\000"
- "\022\021\n\rSYNTAX_PROTO3\020\001B{\n\023com.google.protob"
- "ufB\tTypeProtoP\001Z-google.golang.org/proto"
- "buf/types/known/typepb\370\001\001\242\002\003GPB\252\002\036Google"
- ".Protobuf.WellKnownTypesb\006proto3"
+ "f.Syntax\022\017\n\007edition\030\007 \001(\t\"\325\005\n\005Field\022)\n\004k"
+ "ind\030\001 \001(\0162\033.google.protobuf.Field.Kind\0227"
+ "\n\013cardinality\030\002 \001(\0162\".google.protobuf.Fi"
+ "eld.Cardinality\022\016\n\006number\030\003 \001(\005\022\014\n\004name\030"
+ "\004 \001(\t\022\020\n\010type_url\030\006 \001(\t\022\023\n\013oneof_index\030\007"
+ " \001(\005\022\016\n\006packed\030\010 \001(\010\022(\n\007options\030\t \003(\0132\027."
+ "google.protobuf.Option\022\021\n\tjson_name\030\n \001("
+ "\t\022\025\n\rdefault_value\030\013 \001(\t\"\310\002\n\004Kind\022\020\n\014TYP"
+ "E_UNKNOWN\020\000\022\017\n\013TYPE_DOUBLE\020\001\022\016\n\nTYPE_FLO"
+ "AT\020\002\022\016\n\nTYPE_INT64\020\003\022\017\n\013TYPE_UINT64\020\004\022\016\n"
+ "\nTYPE_INT32\020\005\022\020\n\014TYPE_FIXED64\020\006\022\020\n\014TYPE_"
+ "FIXED32\020\007\022\r\n\tTYPE_BOOL\020\010\022\017\n\013TYPE_STRING\020"
+ "\t\022\016\n\nTYPE_GROUP\020\n\022\020\n\014TYPE_MESSAGE\020\013\022\016\n\nT"
+ "YPE_BYTES\020\014\022\017\n\013TYPE_UINT32\020\r\022\r\n\tTYPE_ENU"
+ "M\020\016\022\021\n\rTYPE_SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020"
+ "\020\022\017\n\013TYPE_SINT32\020\021\022\017\n\013TYPE_SINT64\020\022\"t\n\013C"
+ "ardinality\022\027\n\023CARDINALITY_UNKNOWN\020\000\022\030\n\024C"
+ "ARDINALITY_OPTIONAL\020\001\022\030\n\024CARDINALITY_REQ"
+ "UIRED\020\002\022\030\n\024CARDINALITY_REPEATED\020\003\"\337\001\n\004En"
+ "um\022\014\n\004name\030\001 \001(\t\022-\n\tenumvalue\030\002 \003(\0132\032.go"
+ "ogle.protobuf.EnumValue\022(\n\007options\030\003 \003(\013"
+ "2\027.google.protobuf.Option\0226\n\016source_cont"
+ "ext\030\004 \001(\0132\036.google.protobuf.SourceContex"
+ "t\022\'\n\006syntax\030\005 \001(\0162\027.google.protobuf.Synt"
+ "ax\022\017\n\007edition\030\006 \001(\t\"S\n\tEnumValue\022\014\n\004name"
+ "\030\001 \001(\t\022\016\n\006number\030\002 \001(\005\022(\n\007options\030\003 \003(\0132"
+ "\027.google.protobuf.Option\";\n\006Option\022\014\n\004na"
+ "me\030\001 \001(\t\022#\n\005value\030\002 \001(\0132\024.google.protobu"
+ "f.Any*C\n\006Syntax\022\021\n\rSYNTAX_PROTO2\020\000\022\021\n\rSY"
+ "NTAX_PROTO3\020\001\022\023\n\017SYNTAX_EDITIONS\020\002B{\n\023co"
+ "m.google.protobufB\tTypeProtoP\001Z-google.g"
+ "olang.org/protobuf/types/known/typepb\370\001\001"
+ "\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb"
+ "\006proto3"
};
static const ::_pbi::DescriptorTable* const descriptor_table_google_2fprotobuf_2ftype_2eproto_deps[2] =
{
@@ -284,7 +296,7 @@
const ::_pbi::DescriptorTable descriptor_table_google_2fprotobuf_2ftype_2eproto = {
false,
false,
- 1592,
+ 1647,
descriptor_table_protodef_google_2fprotobuf_2ftype_2eproto,
"google/protobuf/type.proto",
&descriptor_table_google_2fprotobuf_2ftype_2eproto_once,
@@ -411,6 +423,7 @@
switch (value) {
case 0:
case 1:
+ case 2:
return true;
default:
return false;
@@ -447,6 +460,8 @@
, decltype(_impl_.options_){from._impl_.options_}
, decltype(_impl_.name_) {}
+ , decltype(_impl_.edition_) {}
+
, decltype(_impl_.source_context_){nullptr}
, decltype(_impl_.syntax_) {}
@@ -460,6 +475,13 @@
if (!from._internal_name().empty()) {
_this->_impl_.name_.Set(from._internal_name(), _this->GetArenaForAllocation());
}
+ _impl_.edition_.InitDefault();
+ #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ _impl_.edition_.Set("", GetArenaForAllocation());
+ #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ if (!from._internal_edition().empty()) {
+ _this->_impl_.edition_.Set(from._internal_edition(), _this->GetArenaForAllocation());
+ }
if (from._internal_has_source_context()) {
_this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
}
@@ -475,6 +497,8 @@
, decltype(_impl_.options_){arena}
, decltype(_impl_.name_) {}
+ , decltype(_impl_.edition_) {}
+
, decltype(_impl_.source_context_){nullptr}
, decltype(_impl_.syntax_) { 0 }
@@ -484,6 +508,10 @@
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
_impl_.name_.Set("", GetArenaForAllocation());
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ _impl_.edition_.InitDefault();
+ #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ _impl_.edition_.Set("", GetArenaForAllocation());
+ #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
}
Type::~Type() {
@@ -501,6 +529,7 @@
_impl_.oneofs_.~RepeatedPtrField();
_impl_.options_.~RepeatedPtrField();
_impl_.name_.Destroy();
+ _impl_.edition_.Destroy();
if (this != internal_default_instance()) delete _impl_.source_context_;
}
@@ -518,6 +547,7 @@
_impl_.oneofs_.Clear();
_impl_.options_.Clear();
_impl_.name_.ClearToEmpty();
+ _impl_.edition_.ClearToEmpty();
if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
delete _impl_.source_context_;
}
@@ -599,13 +629,24 @@
// .google.protobuf.Syntax syntax = 6;
case 6:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 48)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
_internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
} else {
goto handle_unusual;
}
continue;
+ // string edition = 7;
+ case 7:
+ if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 58)) {
+ auto str = _internal_mutable_edition();
+ ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+ CHK_(ptr);
+ CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Type.edition"));
+ } else {
+ goto handle_unusual;
+ }
+ continue;
default:
goto handle_unusual;
} // switch
@@ -681,6 +722,14 @@
6, this->_internal_syntax(), target);
}
+ // string edition = 7;
+ if (!this->_internal_edition().empty()) {
+ const std::string& _s = this->_internal_edition();
+ ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+ _s.data(), static_cast<int>(_s.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "google.protobuf.Type.edition");
+ target = stream->WriteStringMaybeAliased(7, _s, target);
+ }
+
if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
_internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
@@ -723,6 +772,12 @@
this->_internal_name());
}
+ // string edition = 7;
+ if (!this->_internal_edition().empty()) {
+ total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+ this->_internal_edition());
+ }
+
// .google.protobuf.SourceContext source_context = 5;
if (this->_internal_has_source_context()) {
total_size += 1 +
@@ -760,6 +815,9 @@
if (!from._internal_name().empty()) {
_this->_internal_set_name(from._internal_name());
}
+ if (!from._internal_edition().empty()) {
+ _this->_internal_set_edition(from._internal_edition());
+ }
if (from._internal_has_source_context()) {
_this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
from._internal_source_context());
@@ -791,6 +849,8 @@
_impl_.options_.InternalSwap(&other->_impl_.options_);
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.name_, lhs_arena,
&other->_impl_.name_, rhs_arena);
+ ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.edition_, lhs_arena,
+ &other->_impl_.edition_, rhs_arena);
::PROTOBUF_NAMESPACE_ID::internal::memswap<
PROTOBUF_FIELD_OFFSET(Type, _impl_.syntax_)
+ sizeof(Type::_impl_.syntax_)
@@ -965,7 +1025,7 @@
// .google.protobuf.Field.Kind kind = 1;
case 1:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 8)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
_internal_set_kind(static_cast<::PROTOBUF_NAMESPACE_ID::Field_Kind>(val));
} else {
@@ -975,7 +1035,7 @@
// .google.protobuf.Field.Cardinality cardinality = 2;
case 2:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 16)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
_internal_set_cardinality(static_cast<::PROTOBUF_NAMESPACE_ID::Field_Cardinality>(val));
} else {
@@ -1364,6 +1424,8 @@
, decltype(_impl_.options_){from._impl_.options_}
, decltype(_impl_.name_) {}
+ , decltype(_impl_.edition_) {}
+
, decltype(_impl_.source_context_){nullptr}
, decltype(_impl_.syntax_) {}
@@ -1377,6 +1439,13 @@
if (!from._internal_name().empty()) {
_this->_impl_.name_.Set(from._internal_name(), _this->GetArenaForAllocation());
}
+ _impl_.edition_.InitDefault();
+ #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ _impl_.edition_.Set("", GetArenaForAllocation());
+ #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ if (!from._internal_edition().empty()) {
+ _this->_impl_.edition_.Set(from._internal_edition(), _this->GetArenaForAllocation());
+ }
if (from._internal_has_source_context()) {
_this->_impl_.source_context_ = new ::PROTOBUF_NAMESPACE_ID::SourceContext(*from._impl_.source_context_);
}
@@ -1391,6 +1460,8 @@
, decltype(_impl_.options_){arena}
, decltype(_impl_.name_) {}
+ , decltype(_impl_.edition_) {}
+
, decltype(_impl_.source_context_){nullptr}
, decltype(_impl_.syntax_) { 0 }
@@ -1400,6 +1471,10 @@
#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
_impl_.name_.Set("", GetArenaForAllocation());
#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ _impl_.edition_.InitDefault();
+ #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ _impl_.edition_.Set("", GetArenaForAllocation());
+ #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
}
Enum::~Enum() {
@@ -1416,6 +1491,7 @@
_impl_.enumvalue_.~RepeatedPtrField();
_impl_.options_.~RepeatedPtrField();
_impl_.name_.Destroy();
+ _impl_.edition_.Destroy();
if (this != internal_default_instance()) delete _impl_.source_context_;
}
@@ -1432,6 +1508,7 @@
_impl_.enumvalue_.Clear();
_impl_.options_.Clear();
_impl_.name_.ClearToEmpty();
+ _impl_.edition_.ClearToEmpty();
if (GetArenaForAllocation() == nullptr && _impl_.source_context_ != nullptr) {
delete _impl_.source_context_;
}
@@ -1497,13 +1574,24 @@
// .google.protobuf.Syntax syntax = 5;
case 5:
if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 40)) {
- ::uint32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
+ ::int32_t val = ::PROTOBUF_NAMESPACE_ID::internal::ReadVarint32(&ptr);
CHK_(ptr);
_internal_set_syntax(static_cast<::PROTOBUF_NAMESPACE_ID::Syntax>(val));
} else {
goto handle_unusual;
}
continue;
+ // string edition = 6;
+ case 6:
+ if (PROTOBUF_PREDICT_TRUE(static_cast<::uint8_t>(tag) == 50)) {
+ auto str = _internal_mutable_edition();
+ ptr = ::_pbi::InlineGreedyStringParser(str, ptr, ctx);
+ CHK_(ptr);
+ CHK_(::_pbi::VerifyUTF8(str, "google.protobuf.Enum.edition"));
+ } else {
+ goto handle_unusual;
+ }
+ continue;
default:
goto handle_unusual;
} // switch
@@ -1571,6 +1659,14 @@
5, this->_internal_syntax(), target);
}
+ // string edition = 6;
+ if (!this->_internal_edition().empty()) {
+ const std::string& _s = this->_internal_edition();
+ ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::VerifyUtf8String(
+ _s.data(), static_cast<int>(_s.length()), ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::SERIALIZE, "google.protobuf.Enum.edition");
+ target = stream->WriteStringMaybeAliased(6, _s, target);
+ }
+
if (PROTOBUF_PREDICT_FALSE(_internal_metadata_.have_unknown_fields())) {
target = ::_pbi::WireFormat::InternalSerializeUnknownFieldsToArray(
_internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance), target, stream);
@@ -1607,6 +1703,12 @@
this->_internal_name());
}
+ // string edition = 6;
+ if (!this->_internal_edition().empty()) {
+ total_size += 1 + ::PROTOBUF_NAMESPACE_ID::internal::WireFormatLite::StringSize(
+ this->_internal_edition());
+ }
+
// .google.protobuf.SourceContext source_context = 4;
if (this->_internal_has_source_context()) {
total_size += 1 +
@@ -1643,6 +1745,9 @@
if (!from._internal_name().empty()) {
_this->_internal_set_name(from._internal_name());
}
+ if (!from._internal_edition().empty()) {
+ _this->_internal_set_edition(from._internal_edition());
+ }
if (from._internal_has_source_context()) {
_this->_internal_mutable_source_context()->::PROTOBUF_NAMESPACE_ID::SourceContext::MergeFrom(
from._internal_source_context());
@@ -1673,6 +1778,8 @@
_impl_.options_.InternalSwap(&other->_impl_.options_);
::_pbi::ArenaStringPtr::InternalSwap(&_impl_.name_, lhs_arena,
&other->_impl_.name_, rhs_arena);
+ ::_pbi::ArenaStringPtr::InternalSwap(&_impl_.edition_, lhs_arena,
+ &other->_impl_.edition_, rhs_arena);
::PROTOBUF_NAMESPACE_ID::internal::memswap<
PROTOBUF_FIELD_OFFSET(Enum, _impl_.syntax_)
+ sizeof(Enum::_impl_.syntax_)
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index 64236a6..23ff968 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -168,6 +168,7 @@
enum Syntax : int {
SYNTAX_PROTO2 = 0,
SYNTAX_PROTO3 = 1,
+ SYNTAX_EDITIONS = 2,
Syntax_INT_MIN_SENTINEL_DO_NOT_USE_ =
std::numeric_limits<::int32_t>::min(),
Syntax_INT_MAX_SENTINEL_DO_NOT_USE_ =
@@ -176,8 +177,8 @@
PROTOBUF_EXPORT bool Syntax_IsValid(int value);
constexpr Syntax Syntax_MIN = static_cast<Syntax>(0);
-constexpr Syntax Syntax_MAX = static_cast<Syntax>(1);
-constexpr int Syntax_ARRAYSIZE = 1 + 1;
+constexpr Syntax Syntax_MAX = static_cast<Syntax>(2);
+constexpr int Syntax_ARRAYSIZE = 2 + 1;
PROTOBUF_EXPORT const ::PROTOBUF_NAMESPACE_ID::EnumDescriptor*
Syntax_descriptor();
template <typename T>
@@ -190,7 +191,7 @@
template <>
inline const std::string& Syntax_Name(Syntax value) {
return ::PROTOBUF_NAMESPACE_ID::internal::NameOfDenseEnum<Syntax_descriptor,
- 0, 1>(
+ 0, 2>(
static_cast<int>(value));
}
inline bool Syntax_Parse(absl::string_view name, Syntax* value) {
@@ -234,6 +235,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -327,6 +335,7 @@
kOneofsFieldNumber = 3,
kOptionsFieldNumber = 4,
kNameFieldNumber = 1,
+ kEditionFieldNumber = 7,
kSourceContextFieldNumber = 5,
kSyntaxFieldNumber = 6,
};
@@ -414,6 +423,26 @@
std::string* _internal_mutable_name();
public:
+ // string edition = 7;
+ void clear_edition() ;
+ const std::string& edition() const;
+
+
+
+
+ template <typename Arg_ = const std::string&, typename... Args_>
+ void set_edition(Arg_&& arg, Args_... args);
+ std::string* mutable_edition();
+ PROTOBUF_NODISCARD std::string* release_edition();
+ void set_allocated_edition(std::string* ptr);
+
+ private:
+ const std::string& _internal_edition() const;
+ inline PROTOBUF_ALWAYS_INLINE void _internal_set_edition(
+ const std::string& value);
+ std::string* _internal_mutable_edition();
+
+ public:
// .google.protobuf.SourceContext source_context = 5;
bool has_source_context() const;
private:
@@ -454,6 +483,7 @@
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField<std::string> oneofs_;
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+ ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr edition_;
::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
int syntax_;
mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
@@ -493,6 +523,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -855,6 +892,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -947,6 +991,7 @@
kEnumvalueFieldNumber = 2,
kOptionsFieldNumber = 3,
kNameFieldNumber = 1,
+ kEditionFieldNumber = 6,
kSourceContextFieldNumber = 4,
kSyntaxFieldNumber = 5,
};
@@ -1006,6 +1051,26 @@
std::string* _internal_mutable_name();
public:
+ // string edition = 6;
+ void clear_edition() ;
+ const std::string& edition() const;
+
+
+
+
+ template <typename Arg_ = const std::string&, typename... Args_>
+ void set_edition(Arg_&& arg, Args_... args);
+ std::string* mutable_edition();
+ PROTOBUF_NODISCARD std::string* release_edition();
+ void set_allocated_edition(std::string* ptr);
+
+ private:
+ const std::string& _internal_edition() const;
+ inline PROTOBUF_ALWAYS_INLINE void _internal_set_edition(
+ const std::string& value);
+ std::string* _internal_mutable_edition();
+
+ public:
// .google.protobuf.SourceContext source_context = 4;
bool has_source_context() const;
private:
@@ -1045,6 +1110,7 @@
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::EnumValue > enumvalue_;
::PROTOBUF_NAMESPACE_ID::RepeatedPtrField< ::PROTOBUF_NAMESPACE_ID::Option > options_;
::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr name_;
+ ::PROTOBUF_NAMESPACE_ID::internal::ArenaStringPtr edition_;
::PROTOBUF_NAMESPACE_ID::SourceContext* source_context_;
int syntax_;
mutable ::PROTOBUF_NAMESPACE_ID::internal::CachedSize _cached_size_;
@@ -1084,6 +1150,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -1273,6 +1346,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -1742,6 +1822,53 @@
_impl_.syntax_ = value;
}
+// string edition = 7;
+inline void Type::clear_edition() {
+ _impl_.edition_.ClearToEmpty();
+}
+inline const std::string& Type::edition() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.Type.edition)
+ return _internal_edition();
+}
+template <typename Arg_, typename... Args_>
+inline PROTOBUF_ALWAYS_INLINE void Type::set_edition(Arg_&& arg,
+ Args_... args) {
+ ;
+ _impl_.edition_.Set(static_cast<Arg_&&>(arg), args..., GetArenaForAllocation());
+ // @@protoc_insertion_point(field_set:google.protobuf.Type.edition)
+}
+inline std::string* Type::mutable_edition() {
+ std::string* _s = _internal_mutable_edition();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.Type.edition)
+ return _s;
+}
+inline const std::string& Type::_internal_edition() const {
+ return _impl_.edition_.Get();
+}
+inline void Type::_internal_set_edition(const std::string& value) {
+ ;
+
+
+ _impl_.edition_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Type::_internal_mutable_edition() {
+ ;
+ return _impl_.edition_.Mutable( GetArenaForAllocation());
+}
+inline std::string* Type::release_edition() {
+ // @@protoc_insertion_point(field_release:google.protobuf.Type.edition)
+ return _impl_.edition_.Release();
+}
+inline void Type::set_allocated_edition(std::string* value) {
+ _impl_.edition_.SetAllocated(value, GetArenaForAllocation());
+ #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ if (_impl_.edition_.IsDefault()) {
+ _impl_.edition_.Set("", GetArenaForAllocation());
+ }
+ #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.Type.edition)
+}
+
// -------------------------------------------------------------------
// Field
@@ -2305,6 +2432,53 @@
_impl_.syntax_ = value;
}
+// string edition = 6;
+inline void Enum::clear_edition() {
+ _impl_.edition_.ClearToEmpty();
+}
+inline const std::string& Enum::edition() const {
+ // @@protoc_insertion_point(field_get:google.protobuf.Enum.edition)
+ return _internal_edition();
+}
+template <typename Arg_, typename... Args_>
+inline PROTOBUF_ALWAYS_INLINE void Enum::set_edition(Arg_&& arg,
+ Args_... args) {
+ ;
+ _impl_.edition_.Set(static_cast<Arg_&&>(arg), args..., GetArenaForAllocation());
+ // @@protoc_insertion_point(field_set:google.protobuf.Enum.edition)
+}
+inline std::string* Enum::mutable_edition() {
+ std::string* _s = _internal_mutable_edition();
+ // @@protoc_insertion_point(field_mutable:google.protobuf.Enum.edition)
+ return _s;
+}
+inline const std::string& Enum::_internal_edition() const {
+ return _impl_.edition_.Get();
+}
+inline void Enum::_internal_set_edition(const std::string& value) {
+ ;
+
+
+ _impl_.edition_.Set(value, GetArenaForAllocation());
+}
+inline std::string* Enum::_internal_mutable_edition() {
+ ;
+ return _impl_.edition_.Mutable( GetArenaForAllocation());
+}
+inline std::string* Enum::release_edition() {
+ // @@protoc_insertion_point(field_release:google.protobuf.Enum.edition)
+ return _impl_.edition_.Release();
+}
+inline void Enum::set_allocated_edition(std::string* value) {
+ _impl_.edition_.SetAllocated(value, GetArenaForAllocation());
+ #ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ if (_impl_.edition_.IsDefault()) {
+ _impl_.edition_.Set("", GetArenaForAllocation());
+ }
+ #endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING
+ // @@protoc_insertion_point(field_set_allocated:google.protobuf.Enum.edition)
+}
+
// -------------------------------------------------------------------
// EnumValue
diff --git a/src/google/protobuf/type.proto b/src/google/protobuf/type.proto
index fd25a41..48cb11e 100644
--- a/src/google/protobuf/type.proto
+++ b/src/google/protobuf/type.proto
@@ -57,6 +57,8 @@
SourceContext source_context = 5;
// The source syntax.
Syntax syntax = 6;
+ // The source edition string, only valid when syntax is SYNTAX_EDITIONS.
+ string edition = 7;
}
// A single field of a message type.
@@ -151,6 +153,8 @@
SourceContext source_context = 4;
// The source syntax.
Syntax syntax = 5;
+ // The source edition string, only valid when syntax is SYNTAX_EDITIONS.
+ string edition = 6;
}
// Enum value definition.
@@ -184,4 +188,6 @@
SYNTAX_PROTO2 = 0;
// Syntax `proto3`.
SYNTAX_PROTO3 = 1;
+ // Syntax `editions`.
+ SYNTAX_EDITIONS = 2;
}
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 479262f..108572e 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -552,6 +552,9 @@
optional SubMessage sub_message = 3; // Needed because of bug in javatest
optional TestAllTypes not_in_this_scc = 4;
}
+ repeated group SubGroupR = 5 {
+ optional TestAllTypes payload = 6;
+ }
}
message TestMutualRecursionB {
@@ -1544,9 +1547,16 @@
repeated Arbitrary packed_arbitrary_midfield = 1012 [packed = true];
repeated Arbitrary packed_arbitrary_hifield = 1000012 [packed = true];
+ extensions 2000000 to max;
+ extend EnumParseTester {
+ optional Arbitrary optional_arbitrary_ext = 2000000;
+ repeated Arbitrary repeated_arbitrary_ext = 2000001;
+ repeated Arbitrary packed_arbitrary_ext = 2000002 [packed = true];
+ }
+
// An arbitrary field we can append to to break the runs of repeated fields.
optional int32 other_field = 99;
-};
+}
// This message contains different kind of bool fields to exercise the different
// parsers in table-drived.
@@ -1561,9 +1571,16 @@
repeated bool packed_bool_midfield = 1003 [packed = true];
repeated bool packed_bool_hifield = 1000003 [packed = true];
+ extensions 2000000 to max;
+ extend BoolParseTester {
+ optional bool optional_bool_ext = 2000000;
+ repeated bool repeated_bool_ext = 2000001;
+ repeated bool packed_bool_ext = 2000002 [packed = true];
+ }
+
// An arbitrary field we can append to to break the runs of repeated fields.
optional int32 other_field = 99;
-};
+}
message Int32ParseTester {
optional int32 optional_int32_lowfield = 1;
@@ -1576,9 +1593,16 @@
repeated int32 packed_int32_midfield = 1003 [packed = true];
repeated int32 packed_int32_hifield = 1000003 [packed = true];
+ extensions 2000000 to max;
+ extend Int32ParseTester {
+ optional int32 optional_int32_ext = 2000000;
+ repeated int32 repeated_int32_ext = 2000001;
+ repeated int32 packed_int32_ext = 2000002 [packed = true];
+ }
+
// An arbitrary field we can append to to break the runs of repeated fields.
optional int32 other_field = 99;
-};
+}
message Int64ParseTester {
optional int64 optional_int64_lowfield = 1;
@@ -1591,9 +1615,28 @@
repeated int64 packed_int64_midfield = 1003 [packed = true];
repeated int64 packed_int64_hifield = 1000003 [packed = true];
+ extensions 2000000 to max;
+ extend Int64ParseTester {
+ optional int64 optional_int64_ext = 2000000;
+ repeated int64 repeated_int64_ext = 2000001;
+ repeated int64 packed_int64_ext = 2000002 [packed = true];
+ }
+
// An arbitrary field we can append to to break the runs of repeated fields.
optional int32 other_field = 99;
-};
+}
+
+message InlinedStringIdxRegressionProto {
+ // We mix data to make sure aux ids and inlined string idx do not match.
+ // aux_idx == inlined_string_idx == 1
+ optional string str1 = 1;
+ // aux_idx == 2
+ optional InlinedStringIdxRegressionProto sub = 2;
+ // aux_idx == 3, inlined_string_idx == 2
+ optional string str2 = 3;
+ // aux_idx == 4, inlined_string_idx == 3
+ optional bytes str3 = 4;
+}
message StringParseTester {
optional string optional_string_lowfield = 1;
@@ -1602,7 +1645,13 @@
repeated string repeated_string_lowfield = 2;
repeated string repeated_string_midfield = 1002;
repeated string repeated_string_hifield = 1000002;
-};
+
+ extensions 2000000 to max;
+ extend StringParseTester {
+ optional string optional_string_ext = 2000000;
+ repeated string repeated_string_ext = 2000001;
+ }
+}
message BadFieldNames{
optional int32 OptionalInt32 = 1;
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index e723394..67b6b3d 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -46,6 +46,7 @@
#include "google/protobuf/testing/googletest.h"
#include <gtest/gtest.h>
#include "absl/container/flat_hash_set.h"
+#include "absl/functional/bind_front.h"
#include "absl/strings/cord.h"
#include "absl/synchronization/mutex.h"
#include "absl/time/clock.h"
diff --git a/src/google/protobuf/util/type_resolver_util.cc b/src/google/protobuf/util/type_resolver_util.cc
index 1537708..e408e78 100644
--- a/src/google/protobuf/util/type_resolver_util.cc
+++ b/src/google/protobuf/util/type_resolver_util.cc
@@ -30,10 +30,13 @@
#include "google/protobuf/util/type_resolver_util.h"
+#include <string>
+#include <vector>
+
+#include "google/protobuf/source_context.pb.h"
#include "google/protobuf/type.pb.h"
#include "google/protobuf/wrappers.pb.h"
#include "google/protobuf/descriptor.pb.h"
-#include "google/protobuf/descriptor.h"
#include "absl/log/absl_log.h"
#include "absl/status/status.h"
#include "absl/strings/escaping.h"
@@ -63,10 +66,255 @@
using google::protobuf::Int64Value;
using google::protobuf::Option;
using google::protobuf::StringValue;
+using google::protobuf::Syntax;
using google::protobuf::Type;
using google::protobuf::UInt32Value;
using google::protobuf::UInt64Value;
+template <typename WrapperT, typename T>
+static WrapperT WrapValue(T value) {
+ WrapperT wrapper;
+ wrapper.set_value(value);
+ return wrapper;
+}
+
+void ConvertOptionField(const Reflection* reflection, const Message& options,
+ const FieldDescriptor* field, int index, Option* out) {
+ out->set_name(field->is_extension() ? field->full_name() : field->name());
+ Any* value = out->mutable_value();
+ switch (field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ value->PackFrom(
+ field->is_repeated()
+ ? reflection->GetRepeatedMessage(options, field, index)
+ : reflection->GetMessage(options, field));
+ return;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ value->PackFrom(WrapValue<DoubleValue>(
+ field->is_repeated()
+ ? reflection->GetRepeatedDouble(options, field, index)
+ : reflection->GetDouble(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ value->PackFrom(WrapValue<FloatValue>(
+ field->is_repeated()
+ ? reflection->GetRepeatedFloat(options, field, index)
+ : reflection->GetFloat(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_INT64:
+ value->PackFrom(WrapValue<Int64Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedInt64(options, field, index)
+ : reflection->GetInt64(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ value->PackFrom(WrapValue<UInt64Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedUInt64(options, field, index)
+ : reflection->GetUInt64(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_INT32:
+ value->PackFrom(WrapValue<Int32Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedInt32(options, field, index)
+ : reflection->GetInt32(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ value->PackFrom(WrapValue<UInt32Value>(
+ field->is_repeated()
+ ? reflection->GetRepeatedUInt32(options, field, index)
+ : reflection->GetUInt32(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ value->PackFrom(WrapValue<BoolValue>(
+ field->is_repeated()
+ ? reflection->GetRepeatedBool(options, field, index)
+ : reflection->GetBool(options, field)));
+ return;
+ case FieldDescriptor::CPPTYPE_STRING: {
+ const std::string& val =
+ field->is_repeated()
+ ? reflection->GetRepeatedString(options, field, index)
+ : reflection->GetString(options, field);
+ if (field->type() == FieldDescriptor::TYPE_STRING) {
+ value->PackFrom(WrapValue<StringValue>(val));
+ } else {
+ value->PackFrom(WrapValue<BytesValue>(val));
+ }
+ return;
+ }
+ case FieldDescriptor::CPPTYPE_ENUM: {
+ const EnumValueDescriptor* val =
+ field->is_repeated()
+ ? reflection->GetRepeatedEnum(options, field, index)
+ : reflection->GetEnum(options, field);
+ value->PackFrom(WrapValue<Int32Value>(val->number()));
+ return;
+ }
+ }
+}
+
+// Implementation details for Convert*Options.
+void ConvertOptionsInternal(const Message& options,
+ RepeatedPtrField<Option>& output) {
+ const Reflection* reflection = options.GetReflection();
+ std::vector<const FieldDescriptor*> fields;
+ reflection->ListFields(options, &fields);
+ for (const FieldDescriptor* field : fields) {
+ if (field->is_repeated()) {
+ const int size = reflection->FieldSize(options, field);
+ for (int i = 0; i < size; ++i) {
+ ConvertOptionField(reflection, options, field, i, output.Add());
+ }
+ } else {
+ ConvertOptionField(reflection, options, field, -1, output.Add());
+ }
+ }
+}
+
+void ConvertMessageOptions(const MessageOptions& options,
+ RepeatedPtrField<Option>& output) {
+ return ConvertOptionsInternal(options, output);
+}
+
+void ConvertFieldOptions(const FieldOptions& options,
+ RepeatedPtrField<Option>& output) {
+ return ConvertOptionsInternal(options, output);
+}
+
+void ConvertEnumOptions(const EnumOptions& options,
+ RepeatedPtrField<Option>& output) {
+ return ConvertOptionsInternal(options, output);
+}
+
+void ConvertEnumValueOptions(const EnumValueOptions& options,
+ RepeatedPtrField<Option>& output) {
+ return ConvertOptionsInternal(options, output);
+}
+
+std::string DefaultValueAsString(const FieldDescriptor& descriptor) {
+ switch (descriptor.cpp_type()) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ return absl::StrCat(descriptor.default_value_int32());
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ return absl::StrCat(descriptor.default_value_int64());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ return absl::StrCat(descriptor.default_value_uint32());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ return absl::StrCat(descriptor.default_value_uint64());
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ return io::SimpleFtoa(descriptor.default_value_float());
+ break;
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ return io::SimpleDtoa(descriptor.default_value_double());
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ return descriptor.default_value_bool() ? "true" : "false";
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ if (descriptor.type() == FieldDescriptor::TYPE_BYTES) {
+ return absl::CEscape(descriptor.default_value_string());
+ } else {
+ return descriptor.default_value_string();
+ }
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ return descriptor.default_value_enum()->name();
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ ABSL_DLOG(FATAL) << "Messages can't have default values!";
+ break;
+ }
+ return "";
+}
+
+template <typename T>
+std::string GetTypeUrl(absl::string_view url_prefix, const T& descriptor) {
+ return absl::StrCat(url_prefix, "/", descriptor.full_name());
+}
+
+void ConvertFieldDescriptor(absl::string_view url_prefix,
+ const FieldDescriptor& descriptor, Field* field) {
+ field->set_kind(static_cast<Field::Kind>(descriptor.type()));
+ switch (descriptor.label()) {
+ case FieldDescriptor::LABEL_OPTIONAL:
+ field->set_cardinality(Field::CARDINALITY_OPTIONAL);
+ break;
+ case FieldDescriptor::LABEL_REPEATED:
+ field->set_cardinality(Field::CARDINALITY_REPEATED);
+ break;
+ case FieldDescriptor::LABEL_REQUIRED:
+ field->set_cardinality(Field::CARDINALITY_REQUIRED);
+ break;
+ }
+ field->set_number(descriptor.number());
+ field->set_name(descriptor.name());
+ field->set_json_name(descriptor.json_name());
+ if (descriptor.has_default_value()) {
+ field->set_default_value(DefaultValueAsString(descriptor));
+ }
+ if (descriptor.type() == FieldDescriptor::TYPE_MESSAGE ||
+ descriptor.type() == FieldDescriptor::TYPE_GROUP) {
+ field->set_type_url(GetTypeUrl(url_prefix, *descriptor.message_type()));
+ } else if (descriptor.type() == FieldDescriptor::TYPE_ENUM) {
+ field->set_type_url(GetTypeUrl(url_prefix, *descriptor.enum_type()));
+ }
+ if (descriptor.containing_oneof() != nullptr) {
+ field->set_oneof_index(descriptor.containing_oneof()->index() + 1);
+ }
+ if (descriptor.is_packed()) {
+ field->set_packed(true);
+ }
+
+ ConvertFieldOptions(descriptor.options(), *field->mutable_options());
+}
+
+Syntax ConvertSyntax(FileDescriptor::Syntax syntax) {
+ switch (syntax) {
+ default:
+ return Syntax::SYNTAX_PROTO2;
+ }
+}
+
+void ConvertEnumDescriptor(const EnumDescriptor& descriptor, Enum* enum_type) {
+ enum_type->Clear();
+ enum_type->set_syntax(ConvertSyntax(descriptor.file()->syntax()));
+
+ enum_type->set_name(descriptor.full_name());
+ enum_type->mutable_source_context()->set_file_name(descriptor.file()->name());
+ for (int i = 0; i < descriptor.value_count(); ++i) {
+ const EnumValueDescriptor& value_descriptor = *descriptor.value(i);
+ EnumValue* value = enum_type->mutable_enumvalue()->Add();
+ value->set_name(value_descriptor.name());
+ value->set_number(value_descriptor.number());
+
+ ConvertEnumValueOptions(value_descriptor.options(),
+ *value->mutable_options());
+ }
+
+ ConvertEnumOptions(descriptor.options(), *enum_type->mutable_options());
+}
+
+void ConvertDescriptor(absl::string_view url_prefix,
+ const Descriptor& descriptor, Type* type) {
+ type->Clear();
+ type->set_name(descriptor.full_name());
+ type->set_syntax(ConvertSyntax(descriptor.file()->syntax()));
+ for (int i = 0; i < descriptor.field_count(); ++i) {
+ ConvertFieldDescriptor(url_prefix, *descriptor.field(i),
+ type->add_fields());
+ }
+ for (int i = 0; i < descriptor.oneof_decl_count(); ++i) {
+ type->add_oneofs(descriptor.oneof_decl(i)->name());
+ }
+ type->mutable_source_context()->set_file_name(descriptor.file()->name());
+ ConvertMessageOptions(descriptor.options(), *type->mutable_options());
+}
+
class DescriptorPoolTypeResolver : public TypeResolver {
public:
DescriptorPoolTypeResolver(absl::string_view url_prefix,
@@ -82,11 +330,11 @@
}
const Descriptor* descriptor = pool_->FindMessageTypeByName(type_name);
- if (descriptor == NULL) {
+ if (descriptor == nullptr) {
return absl::NotFoundError(
absl::StrCat("Invalid type URL, unknown type: ", type_name));
}
- ConvertDescriptor(descriptor, type);
+ ConvertDescriptor(url_prefix_, *descriptor, type);
return absl::Status();
}
@@ -99,213 +347,15 @@
}
const EnumDescriptor* descriptor = pool_->FindEnumTypeByName(type_name);
- if (descriptor == NULL) {
+ if (descriptor == nullptr) {
return absl::InvalidArgumentError(
absl::StrCat("Invalid type URL, unknown type: ", type_name));
}
- ConvertEnumDescriptor(descriptor, enum_type);
+ ConvertEnumDescriptor(*descriptor, enum_type);
return absl::Status();
}
private:
- void ConvertDescriptor(const Descriptor* descriptor, Type* type) {
- type->Clear();
- type->set_name(descriptor->full_name());
- for (int i = 0; i < descriptor->field_count(); ++i) {
- ConvertFieldDescriptor(descriptor->field(i), type->add_fields());
- }
- for (int i = 0; i < descriptor->oneof_decl_count(); ++i) {
- type->add_oneofs(descriptor->oneof_decl(i)->name());
- }
- type->mutable_source_context()->set_file_name(descriptor->file()->name());
- ConvertMessageOptions(descriptor->options(), type->mutable_options());
- }
-
- void ConvertMessageOptions(const MessageOptions& options,
- RepeatedPtrField<Option>* output) {
- return ConvertOptionsInternal(options, output);
- }
-
- void ConvertFieldOptions(const FieldOptions& options,
- RepeatedPtrField<Option>* output) {
- return ConvertOptionsInternal(options, output);
- }
-
- void ConvertEnumOptions(const EnumOptions& options,
- RepeatedPtrField<Option>* output) {
- return ConvertOptionsInternal(options, output);
- }
-
- void ConvertEnumValueOptions(const EnumValueOptions& options,
- RepeatedPtrField<Option>* output) {
- return ConvertOptionsInternal(options, output);
- }
-
- // Implementation details for Convert*Options.
- void ConvertOptionsInternal(const Message& options,
- RepeatedPtrField<Option>* output) {
- const Reflection* reflection = options.GetReflection();
- std::vector<const FieldDescriptor*> fields;
- reflection->ListFields(options, &fields);
- for (const FieldDescriptor* field : fields) {
- if (field->is_repeated()) {
- const int size = reflection->FieldSize(options, field);
- for (int i = 0; i < size; i++) {
- ConvertOptionField(reflection, options, field, i, output->Add());
- }
- } else {
- ConvertOptionField(reflection, options, field, -1, output->Add());
- }
- }
- }
-
- static void ConvertOptionField(const Reflection* reflection,
- const Message& options,
- const FieldDescriptor* field, int index,
- Option* out) {
- out->set_name(field->is_extension() ? field->full_name() : field->name());
- Any* value = out->mutable_value();
- switch (field->cpp_type()) {
- case FieldDescriptor::CPPTYPE_MESSAGE:
- value->PackFrom(
- field->is_repeated()
- ? reflection->GetRepeatedMessage(options, field, index)
- : reflection->GetMessage(options, field));
- return;
- case FieldDescriptor::CPPTYPE_DOUBLE:
- value->PackFrom(WrapValue<DoubleValue>(
- field->is_repeated()
- ? reflection->GetRepeatedDouble(options, field, index)
- : reflection->GetDouble(options, field)));
- return;
- case FieldDescriptor::CPPTYPE_FLOAT:
- value->PackFrom(WrapValue<FloatValue>(
- field->is_repeated()
- ? reflection->GetRepeatedFloat(options, field, index)
- : reflection->GetFloat(options, field)));
- return;
- case FieldDescriptor::CPPTYPE_INT64:
- value->PackFrom(WrapValue<Int64Value>(
- field->is_repeated()
- ? reflection->GetRepeatedInt64(options, field, index)
- : reflection->GetInt64(options, field)));
- return;
- case FieldDescriptor::CPPTYPE_UINT64:
- value->PackFrom(WrapValue<UInt64Value>(
- field->is_repeated()
- ? reflection->GetRepeatedUInt64(options, field, index)
- : reflection->GetUInt64(options, field)));
- return;
- case FieldDescriptor::CPPTYPE_INT32:
- value->PackFrom(WrapValue<Int32Value>(
- field->is_repeated()
- ? reflection->GetRepeatedInt32(options, field, index)
- : reflection->GetInt32(options, field)));
- return;
- case FieldDescriptor::CPPTYPE_UINT32:
- value->PackFrom(WrapValue<UInt32Value>(
- field->is_repeated()
- ? reflection->GetRepeatedUInt32(options, field, index)
- : reflection->GetUInt32(options, field)));
- return;
- case FieldDescriptor::CPPTYPE_BOOL:
- value->PackFrom(WrapValue<BoolValue>(
- field->is_repeated()
- ? reflection->GetRepeatedBool(options, field, index)
- : reflection->GetBool(options, field)));
- return;
- case FieldDescriptor::CPPTYPE_STRING: {
- const std::string& val =
- field->is_repeated()
- ? reflection->GetRepeatedString(options, field, index)
- : reflection->GetString(options, field);
- if (field->type() == FieldDescriptor::TYPE_STRING) {
- value->PackFrom(WrapValue<StringValue>(val));
- } else {
- value->PackFrom(WrapValue<BytesValue>(val));
- }
- return;
- }
- case FieldDescriptor::CPPTYPE_ENUM: {
- const EnumValueDescriptor* val =
- field->is_repeated()
- ? reflection->GetRepeatedEnum(options, field, index)
- : reflection->GetEnum(options, field);
- value->PackFrom(WrapValue<Int32Value>(val->number()));
- return;
- }
- }
- }
-
- template <typename WrapperT, typename T>
- static WrapperT WrapValue(T value) {
- WrapperT wrapper;
- wrapper.set_value(value);
- return wrapper;
- }
-
- void ConvertFieldDescriptor(const FieldDescriptor* descriptor, Field* field) {
- field->set_kind(static_cast<Field::Kind>(descriptor->type()));
- switch (descriptor->label()) {
- case FieldDescriptor::LABEL_OPTIONAL:
- field->set_cardinality(Field::CARDINALITY_OPTIONAL);
- break;
- case FieldDescriptor::LABEL_REPEATED:
- field->set_cardinality(Field::CARDINALITY_REPEATED);
- break;
- case FieldDescriptor::LABEL_REQUIRED:
- field->set_cardinality(Field::CARDINALITY_REQUIRED);
- break;
- }
- field->set_number(descriptor->number());
- field->set_name(descriptor->name());
- field->set_json_name(descriptor->json_name());
- if (descriptor->has_default_value()) {
- field->set_default_value(DefaultValueAsString(descriptor));
- }
- if (descriptor->type() == FieldDescriptor::TYPE_MESSAGE ||
- descriptor->type() == FieldDescriptor::TYPE_GROUP) {
- field->set_type_url(GetTypeUrl(descriptor->message_type()));
- } else if (descriptor->type() == FieldDescriptor::TYPE_ENUM) {
- field->set_type_url(GetTypeUrl(descriptor->enum_type()));
- }
- if (descriptor->containing_oneof() != NULL) {
- field->set_oneof_index(descriptor->containing_oneof()->index() + 1);
- }
- if (descriptor->is_packed()) {
- field->set_packed(true);
- }
-
- ConvertFieldOptions(descriptor->options(), field->mutable_options());
- }
-
- void ConvertEnumDescriptor(const EnumDescriptor* descriptor,
- Enum* enum_type) {
- enum_type->Clear();
- enum_type->set_name(descriptor->full_name());
- enum_type->mutable_source_context()->set_file_name(
- descriptor->file()->name());
- for (int i = 0; i < descriptor->value_count(); ++i) {
- const EnumValueDescriptor* value_descriptor = descriptor->value(i);
- EnumValue* value = enum_type->mutable_enumvalue()->Add();
- value->set_name(value_descriptor->name());
- value->set_number(value_descriptor->number());
-
- ConvertEnumValueOptions(value_descriptor->options(),
- value->mutable_options());
- }
-
- ConvertEnumOptions(descriptor->options(), enum_type->mutable_options());
- }
-
- std::string GetTypeUrl(const Descriptor* descriptor) {
- return absl::StrCat(url_prefix_, "/", descriptor->full_name());
- }
-
- std::string GetTypeUrl(const EnumDescriptor* descriptor) {
- return absl::StrCat(url_prefix_, "/", descriptor->full_name());
- }
-
absl::Status ParseTypeUrl(absl::string_view type_url,
std::string* type_name) {
absl::string_view stripped = type_url;
@@ -319,46 +369,6 @@
return absl::Status();
}
- std::string DefaultValueAsString(const FieldDescriptor* descriptor) {
- switch (descriptor->cpp_type()) {
- case FieldDescriptor::CPPTYPE_INT32:
- return absl::StrCat(descriptor->default_value_int32());
- break;
- case FieldDescriptor::CPPTYPE_INT64:
- return absl::StrCat(descriptor->default_value_int64());
- break;
- case FieldDescriptor::CPPTYPE_UINT32:
- return absl::StrCat(descriptor->default_value_uint32());
- break;
- case FieldDescriptor::CPPTYPE_UINT64:
- return absl::StrCat(descriptor->default_value_uint64());
- break;
- case FieldDescriptor::CPPTYPE_FLOAT:
- return io::SimpleFtoa(descriptor->default_value_float());
- break;
- case FieldDescriptor::CPPTYPE_DOUBLE:
- return io::SimpleDtoa(descriptor->default_value_double());
- break;
- case FieldDescriptor::CPPTYPE_BOOL:
- return descriptor->default_value_bool() ? "true" : "false";
- break;
- case FieldDescriptor::CPPTYPE_STRING:
- if (descriptor->type() == FieldDescriptor::TYPE_BYTES) {
- return absl::CEscape(descriptor->default_value_string());
- } else {
- return descriptor->default_value_string();
- }
- break;
- case FieldDescriptor::CPPTYPE_ENUM:
- return descriptor->default_value_enum()->name();
- break;
- case FieldDescriptor::CPPTYPE_MESSAGE:
- ABSL_DLOG(FATAL) << "Messages can't have default values!";
- break;
- }
- return "";
- }
-
std::string url_prefix_;
const DescriptorPool* pool_;
};
@@ -370,6 +380,21 @@
return new DescriptorPoolTypeResolver(url_prefix, pool);
}
+// Performs a direct conversion from a descriptor to a type proto.
+Type ConvertDescriptorToType(absl::string_view url_prefix,
+ const Descriptor& descriptor) {
+ Type type;
+ ConvertDescriptor(url_prefix, descriptor, &type);
+ return type;
+}
+
+// Performs a direct conversion from an enum descriptor to a type proto.
+Enum ConvertDescriptorToType(const EnumDescriptor& descriptor) {
+ Enum enum_type;
+ ConvertEnumDescriptor(descriptor, &enum_type);
+ return enum_type;
+}
+
} // namespace util
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/util/type_resolver_util.h b/src/google/protobuf/util/type_resolver_util.h
index 3670fcb..6e43ade 100644
--- a/src/google/protobuf/util/type_resolver_util.h
+++ b/src/google/protobuf/util/type_resolver_util.h
@@ -33,7 +33,9 @@
#ifndef GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
#define GOOGLE_PROTOBUF_UTIL_TYPE_RESOLVER_UTIL_H__
+#include "google/protobuf/type.pb.h"
#include "absl/strings/string_view.h"
+#include "google/protobuf/descriptor.h"
// Must be included last.
#include "google/protobuf/port_def.inc"
@@ -49,6 +51,14 @@
PROTOBUF_EXPORT TypeResolver* NewTypeResolverForDescriptorPool(
absl::string_view url_prefix, const DescriptorPool* pool);
+// Performs a direct conversion from a descriptor to a type proto.
+PROTOBUF_EXPORT google::protobuf::Type ConvertDescriptorToType(
+ absl::string_view url_prefix, const Descriptor& descriptor);
+
+// Performs a direct conversion from an enum descriptor to a type proto.
+PROTOBUF_EXPORT google::protobuf::Enum ConvertDescriptorToType(
+ const EnumDescriptor& descriptor);
+
} // namespace util
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/util/type_resolver_util_test.cc b/src/google/protobuf/util/type_resolver_util_test.cc
index 8a54bca..eaf6649 100644
--- a/src/google/protobuf/util/type_resolver_util_test.cc
+++ b/src/google/protobuf/util/type_resolver_util_test.cc
@@ -36,16 +36,19 @@
#include <string>
#include <vector>
+#include "google/protobuf/any.pb.h"
#include "google/protobuf/type.pb.h"
#include "google/protobuf/wrappers.pb.h"
+#include "google/protobuf/descriptor.pb.h"
#include "google/protobuf/util/type_resolver.h"
-#include "google/protobuf/testing/googletest.h"
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include "google/protobuf/descriptor.h"
#include "google/protobuf/util/json_format_proto3.pb.h"
#include "google/protobuf/map_unittest.pb.h"
-#include "google/protobuf/test_util.h"
#include "google/protobuf/unittest.pb.h"
#include "google/protobuf/unittest_custom_options.pb.h"
+#include "google/protobuf/unittest_import.pb.h"
namespace google {
namespace protobuf {
@@ -57,11 +60,113 @@
using google::protobuf::Field;
using google::protobuf::Int32Value;
using google::protobuf::Option;
+using google::protobuf::Syntax;
using google::protobuf::Type;
using google::protobuf::UInt64Value;
static const char kUrlPrefix[] = "type.googleapis.com";
+const Field* FindField(const Type& type, absl::string_view name) {
+ for (const Field& field : type.fields()) {
+ if (field.name() == name) {
+ return &field;
+ }
+ }
+ return nullptr;
+}
+
+bool HasField(const Type& type, Field::Cardinality cardinality,
+ Field::Kind kind, absl::string_view name, int number) {
+ const Field* field = FindField(type, name);
+ if (field == nullptr) {
+ return false;
+ }
+ return field->cardinality() == cardinality && field->kind() == kind &&
+ field->number() == number;
+}
+
+bool CheckFieldTypeUrl(const Type& type, absl::string_view name,
+ absl::string_view type_url) {
+ const Field* field = FindField(type, name);
+ if (field == nullptr) {
+ return false;
+ }
+ return field->type_url() == type_url;
+}
+
+bool FieldInOneof(const Type& type, absl::string_view name,
+ absl::string_view oneof_name) {
+ const Field* field = FindField(type, name);
+ if (field == nullptr || field->oneof_index() <= 0 ||
+ field->oneof_index() > type.oneofs_size()) {
+ return false;
+ }
+ return type.oneofs(field->oneof_index() - 1) == oneof_name;
+}
+
+bool IsPacked(const Type& type, absl::string_view name) {
+ const Field* field = FindField(type, name);
+ if (field == nullptr) {
+ return false;
+ }
+ return field->packed();
+}
+
+const EnumValue* FindEnumValue(const Enum& type, absl::string_view name) {
+ for (const EnumValue& value : type.enumvalue()) {
+ if (value.name() == name) {
+ return &value;
+ }
+ }
+ return nullptr;
+}
+
+bool EnumHasValue(const Enum& type, absl::string_view name, int number) {
+ const EnumValue* value = FindEnumValue(type, name);
+ if (value == nullptr) {
+ return false;
+ }
+ return value->number() == number;
+}
+
+template <typename WrapperT, typename T>
+bool HasOption(const RepeatedPtrField<Option>& options, absl::string_view name,
+ T value) {
+ for (const Option& option : options) {
+ if (option.name() == name) {
+ WrapperT wrapper;
+ if (option.value().UnpackTo(&wrapper) && wrapper.value() == value) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool HasBoolOption(const RepeatedPtrField<Option>& options,
+ absl::string_view name, bool value) {
+ return HasOption<BoolValue>(options, name, value);
+}
+
+bool HasInt32Option(const RepeatedPtrField<Option>& options,
+ absl::string_view name, int32_t value) {
+ return HasOption<Int32Value>(options, name, value);
+}
+
+bool HasUInt64Option(const RepeatedPtrField<Option>& options,
+ absl::string_view name, uint64_t value) {
+ return HasOption<UInt64Value>(options, name, value);
+}
+
+std::string GetTypeUrl(std::string full_name) {
+ return kUrlPrefix + std::string("/") + full_name;
+}
+
+template <typename T>
+std::string GetTypeUrl() {
+ return GetTypeUrl(T::descriptor()->full_name());
+}
+
class DescriptorPoolTypeResolverTest : public testing::Test {
public:
DescriptorPoolTypeResolverTest() {
@@ -69,105 +174,6 @@
kUrlPrefix, DescriptorPool::generated_pool()));
}
- const Field* FindField(const Type& type, const std::string& name) {
- for (int i = 0; i < type.fields_size(); ++i) {
- const Field& field = type.fields(i);
- if (field.name() == name) {
- return &field;
- }
- }
- return nullptr;
- }
-
- bool HasField(const Type& type, Field::Cardinality cardinality,
- Field::Kind kind, const std::string& name, int number) {
- const Field* field = FindField(type, name);
- if (field == nullptr) {
- return false;
- }
- return field->cardinality() == cardinality && field->kind() == kind &&
- field->number() == number;
- }
-
- bool CheckFieldTypeUrl(const Type& type, const std::string& name,
- const std::string& type_url) {
- const Field* field = FindField(type, name);
- if (field == nullptr) {
- return false;
- }
- return field->type_url() == type_url;
- }
-
- bool FieldInOneof(const Type& type, const std::string& name,
- const std::string& oneof_name) {
- const Field* field = FindField(type, name);
- if (field == nullptr || field->oneof_index() <= 0 ||
- field->oneof_index() > type.oneofs_size()) {
- return false;
- }
- return type.oneofs(field->oneof_index() - 1) == oneof_name;
- }
-
- bool IsPacked(const Type& type, const std::string& name) {
- const Field* field = FindField(type, name);
- if (field == nullptr) {
- return false;
- }
- return field->packed();
- }
-
- const EnumValue* FindEnumValue(const Enum& type, const std::string& name) {
- for (const EnumValue& value : type.enumvalue()) {
- if (value.name() == name) {
- return &value;
- }
- }
- return nullptr;
- }
-
- bool EnumHasValue(const Enum& type, const std::string& name, int number) {
- const EnumValue* value = FindEnumValue(type, name);
- return value != nullptr && value->number() == number;
- }
-
- bool HasBoolOption(const RepeatedPtrField<Option>& options,
- const std::string& name, bool value) {
- return HasOption<BoolValue>(options, name, value);
- }
-
- bool HasInt32Option(const RepeatedPtrField<Option>& options,
- const std::string& name, int32_t value) {
- return HasOption<Int32Value>(options, name, value);
- }
-
- bool HasUInt64Option(const RepeatedPtrField<Option>& options,
- const std::string& name, uint64_t value) {
- return HasOption<UInt64Value>(options, name, value);
- }
-
- template <typename WrapperT, typename T>
- bool HasOption(const RepeatedPtrField<Option>& options,
- const std::string& name, T value) {
- for (const Option& option : options) {
- if (option.name() == name) {
- WrapperT wrapper;
- if (option.value().UnpackTo(&wrapper) && wrapper.value() == value) {
- return true;
- }
- }
- }
- return false;
- }
-
- std::string GetTypeUrl(std::string full_name) {
- return kUrlPrefix + std::string("/") + full_name;
- }
-
- template <typename T>
- std::string GetTypeUrl() {
- return GetTypeUrl(T::descriptor()->full_name());
- }
-
protected:
std::unique_ptr<TypeResolver> resolver_;
};
@@ -432,6 +438,260 @@
EXPECT_EQ("@value", FindField(type, "value")->json_name());
}
+class DescriptorPoolTypeResolverSyntaxTest : public testing::Test {
+ protected:
+ DescriptorPoolTypeResolverSyntaxTest()
+ : resolver_(NewTypeResolverForDescriptorPool(kUrlPrefix, &pool_)) {}
+
+ const FileDescriptor* BuildFile(
+ absl::string_view syntax,
+ absl::optional<absl::string_view> edition = absl::nullopt) {
+ FileDescriptorProto proto;
+ proto.set_package("test");
+ proto.set_name("foo");
+ proto.set_syntax(syntax);
+ if (edition.has_value()) {
+ proto.set_edition(*edition);
+ }
+ DescriptorProto* message = proto.add_message_type();
+ message->set_name("MyMessage");
+ const FileDescriptor* file = pool_.BuildFile(proto);
+ ABSL_CHECK(file != nullptr);
+ return file;
+ }
+
+ DescriptorPool pool_;
+ std::unique_ptr<TypeResolver> resolver_;
+};
+
+TEST_F(DescriptorPoolTypeResolverSyntaxTest, SyntaxProto2) {
+ const FileDescriptor* file = BuildFile("proto2");
+ ASSERT_EQ(FileDescriptor::SYNTAX_PROTO2, file->syntax());
+
+ Type type;
+ ASSERT_TRUE(
+ resolver_->ResolveMessageType(GetTypeUrl("test.MyMessage"), &type).ok());
+ EXPECT_EQ(type.syntax(), Syntax::SYNTAX_PROTO2);
+ EXPECT_EQ(type.edition(), "");
+}
+
+TEST_F(DescriptorPoolTypeResolverSyntaxTest, SyntaxProto3) {
+ const FileDescriptor* file = BuildFile("proto3");
+ ASSERT_EQ(FileDescriptor::SYNTAX_PROTO3, file->syntax());
+
+ Type type;
+ ASSERT_TRUE(
+ resolver_->ResolveMessageType(GetTypeUrl("test.MyMessage"), &type).ok());
+ // TODO(b/271206501) This should be proto3.
+ EXPECT_EQ(type.syntax(), Syntax::SYNTAX_PROTO2);
+ EXPECT_EQ(type.edition(), "");
+}
+
+
+TEST(ConvertDescriptorToTypeTest, TestAllTypes) {
+ Type type = ConvertDescriptorToType(
+ kUrlPrefix, *protobuf_unittest::TestAllTypes::GetDescriptor());
+
+ // Check all optional fields.
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_INT32,
+ "optional_int32", 1));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_INT64,
+ "optional_int64", 2));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_UINT32,
+ "optional_uint32", 3));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_UINT64,
+ "optional_uint64", 4));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_SINT32,
+ "optional_sint32", 5));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_SINT64,
+ "optional_sint64", 6));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_FIXED32,
+ "optional_fixed32", 7));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_FIXED64,
+ "optional_fixed64", 8));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_SFIXED32,
+ "optional_sfixed32", 9));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_SFIXED64,
+ "optional_sfixed64", 10));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_FLOAT,
+ "optional_float", 11));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_DOUBLE,
+ "optional_double", 12));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_BOOL,
+ "optional_bool", 13));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_STRING,
+ "optional_string", 14));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_BYTES,
+ "optional_bytes", 15));
+
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_GROUP,
+ "optionalgroup", 16));
+
+ EXPECT_TRUE(CheckFieldTypeUrl(
+ type, "optionalgroup",
+ GetTypeUrl<protobuf_unittest::TestAllTypes::OptionalGroup>()));
+
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_MESSAGE,
+ "optional_nested_message", 18));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_MESSAGE,
+ "optional_foreign_message", 19));
+
+ EXPECT_TRUE(CheckFieldTypeUrl(
+ type, "optional_nested_message",
+ GetTypeUrl<protobuf_unittest::TestAllTypes::NestedMessage>()));
+ EXPECT_TRUE(CheckFieldTypeUrl(type, "optional_foreign_message",
+ GetTypeUrl<protobuf_unittest::ForeignMessage>()));
+
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_ENUM,
+ "optional_nested_enum", 21));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_ENUM,
+ "optional_foreign_enum", 22));
+
+ EXPECT_TRUE(
+ CheckFieldTypeUrl(type, "optional_nested_enum",
+ GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum")));
+ EXPECT_TRUE(CheckFieldTypeUrl(type, "optional_foreign_enum",
+ GetTypeUrl("protobuf_unittest.ForeignEnum")));
+
+ // Check all repeated fields.
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_INT32,
+ "repeated_int32", 31));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_INT64,
+ "repeated_int64", 32));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_UINT32,
+ "repeated_uint32", 33));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_UINT64,
+ "repeated_uint64", 34));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_SINT32,
+ "repeated_sint32", 35));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_SINT64,
+ "repeated_sint64", 36));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_FIXED32,
+ "repeated_fixed32", 37));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_FIXED64,
+ "repeated_fixed64", 38));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_SFIXED32,
+ "repeated_sfixed32", 39));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_SFIXED64,
+ "repeated_sfixed64", 40));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_FLOAT,
+ "repeated_float", 41));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_DOUBLE,
+ "repeated_double", 42));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_BOOL,
+ "repeated_bool", 43));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_STRING,
+ "repeated_string", 44));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_BYTES,
+ "repeated_bytes", 45));
+
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_GROUP,
+ "repeatedgroup", 46));
+
+ EXPECT_TRUE(CheckFieldTypeUrl(
+ type, "repeatedgroup",
+ GetTypeUrl<protobuf_unittest::TestAllTypes::RepeatedGroup>()));
+
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_MESSAGE,
+ "repeated_nested_message", 48));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_MESSAGE,
+ "repeated_foreign_message", 49));
+
+ EXPECT_TRUE(CheckFieldTypeUrl(
+ type, "repeated_nested_message",
+ GetTypeUrl<protobuf_unittest::TestAllTypes::NestedMessage>()));
+ EXPECT_TRUE(CheckFieldTypeUrl(type, "repeated_foreign_message",
+ GetTypeUrl<protobuf_unittest::ForeignMessage>()));
+
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_ENUM,
+ "repeated_nested_enum", 51));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_ENUM,
+ "repeated_foreign_enum", 52));
+
+ EXPECT_TRUE(
+ CheckFieldTypeUrl(type, "repeated_nested_enum",
+ GetTypeUrl("protobuf_unittest.TestAllTypes.NestedEnum")));
+ EXPECT_TRUE(CheckFieldTypeUrl(type, "repeated_foreign_enum",
+ GetTypeUrl("protobuf_unittest.ForeignEnum")));
+}
+
+TEST(ConvertDescriptorToTypeTest, ConvertDescriptorToTypePacked) {
+ Type type = ConvertDescriptorToType(
+ kUrlPrefix, *protobuf_unittest::TestPackedTypes::GetDescriptor());
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_INT32,
+ "packed_int32", 90));
+ EXPECT_TRUE(IsPacked(type, "packed_int32"));
+}
+
+TEST(ConvertDescriptorToTypeTest, TestOneof) {
+ Type type = ConvertDescriptorToType(
+ kUrlPrefix, *protobuf_unittest::TestAllTypes::GetDescriptor());
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_UINT32,
+ "oneof_uint32", 111));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_MESSAGE,
+ "oneof_nested_message", 112));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_STRING,
+ "oneof_string", 113));
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_OPTIONAL, Field::TYPE_BYTES,
+ "oneof_bytes", 114));
+ EXPECT_TRUE(FieldInOneof(type, "oneof_uint32", "oneof_field"));
+ EXPECT_TRUE(FieldInOneof(type, "oneof_nested_message", "oneof_field"));
+ EXPECT_TRUE(FieldInOneof(type, "oneof_string", "oneof_field"));
+ EXPECT_TRUE(FieldInOneof(type, "oneof_bytes", "oneof_field"));
+}
+
+TEST(ConvertDescriptorToTypeTest, TestMap) {
+ Type type = ConvertDescriptorToType(
+ kUrlPrefix, *protobuf_unittest::TestMap::GetDescriptor());
+ EXPECT_TRUE(HasField(type, Field::CARDINALITY_REPEATED, Field::TYPE_MESSAGE,
+ "map_int32_int32", 1));
+ EXPECT_TRUE(CheckFieldTypeUrl(
+ type, "map_int32_int32",
+ GetTypeUrl("protobuf_unittest.TestMap.MapInt32Int32Entry")));
+}
+
+TEST(ConvertDescriptorToTypeTest, TestCustomOptions) {
+ Type type = ConvertDescriptorToType(
+ kUrlPrefix,
+ *protobuf_unittest::TestMessageWithCustomOptions::GetDescriptor());
+ EXPECT_TRUE(
+ HasInt32Option(type.options(), "protobuf_unittest.message_opt1", -56));
+ const Field* field = FindField(type, "field1");
+ ASSERT_TRUE(field != nullptr);
+ EXPECT_TRUE(HasUInt64Option(field->options(), "protobuf_unittest.field_opt1",
+ 8765432109));
+}
+
+TEST(ConvertDescriptorToTypeTest, TestJsonName) {
+ Type type = ConvertDescriptorToType(
+ kUrlPrefix, *protobuf_unittest::TestAllTypes::GetDescriptor());
+ EXPECT_EQ("optionalInt32", FindField(type, "optional_int32")->json_name());
+
+ type = ConvertDescriptorToType(kUrlPrefix,
+ *proto3::TestCustomJsonName::GetDescriptor());
+ EXPECT_EQ("@value", FindField(type, "value")->json_name());
+}
+
+TEST(ConvertDescriptorToTypeTest, TestEnum) {
+ Enum type = ConvertDescriptorToType(
+ *protobuf_unittest::TestAllTypes::NestedEnum_descriptor());
+ EnumHasValue(type, "FOO", 1);
+ EnumHasValue(type, "BAR", 2);
+ EnumHasValue(type, "BAZ", 3);
+ EnumHasValue(type, "NEG", -1);
+}
+
+TEST(ConvertDescriptorToTypeTest, TestCustomEnumOptions) {
+ Enum type = ConvertDescriptorToType(
+ *protobuf_unittest::TestMessageWithCustomOptions::AnEnum_descriptor());
+ ASSERT_TRUE(
+ HasInt32Option(type.options(), "protobuf_unittest.enum_opt1", -789));
+ const EnumValue* value = FindEnumValue(type, "ANENUM_VAL2");
+ ASSERT_TRUE(value != nullptr);
+ ASSERT_TRUE(
+ HasInt32Option(value->options(), "protobuf_unittest.enum_value_opt1", 123));
+}
+
} // namespace
} // namespace util
} // namespace protobuf
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index 27aa64f..fe62d1c 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -874,7 +874,7 @@
ptr = internal::PackedEnumParser(rep_enum, ptr, ctx);
} else {
return ctx->ReadPackedVarint(
- ptr, [rep_enum, field, reflection, msg](uint64_t val) {
+ ptr, [rep_enum, field, reflection, msg](int32_t val) {
if (field->enum_type()->FindValueByNumber(val) != nullptr) {
rep_enum->Add(val);
} else {
@@ -1466,11 +1466,11 @@
// Write type ID.
target = WireFormatLite::WriteUInt32ToArray(
WireFormatLite::kMessageSetTypeIdNumber, field->number(), target);
- // Write message.
- auto& msg = message_reflection->GetMessage(message, field);
- target = WireFormatLite::InternalWriteMessage(
- WireFormatLite::kMessageSetMessageNumber, msg, msg.GetCachedSize(),
- target, stream);
+ // Write message.
+ auto& msg = message_reflection->GetMessage(message, field);
+ target = WireFormatLite::InternalWriteMessage(
+ WireFormatLite::kMessageSetMessageNumber, msg, msg.GetCachedSize(),
+ target, stream);
// End group.
target = stream->EnsureSpace(target);
target = io::CodedOutputStream::WriteTagToArray(
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 0b41068..e5d676a 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -9,7 +9,7 @@
#include <type_traits>
#include "google/protobuf/port_def.inc"
-#if PROTOBUF_VERSION < 4022000
+#if PROTOBUF_VERSION < 3021000
#error "This file was generated by a newer version of protoc which is"
#error "incompatible with your Protocol Buffer headers. Please update"
#error "your headers."
@@ -136,6 +136,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -283,6 +290,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -430,6 +444,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -577,6 +598,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -724,6 +752,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -871,6 +906,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -1018,6 +1060,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -1165,6 +1214,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
@@ -1322,6 +1378,13 @@
return *this;
}
+ inline const ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet& unknown_fields() const {
+ return _internal_metadata_.unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>(::PROTOBUF_NAMESPACE_ID::UnknownFieldSet::default_instance);
+ }
+ inline ::PROTOBUF_NAMESPACE_ID::UnknownFieldSet* mutable_unknown_fields() {
+ return _internal_metadata_.mutable_unknown_fields<::PROTOBUF_NAMESPACE_ID::UnknownFieldSet>();
+ }
+
static const ::PROTOBUF_NAMESPACE_ID::Descriptor* descriptor() {
return GetDescriptor();
}
diff --git a/src/libprotobuf-lite.map b/src/libprotobuf-lite.map
index 3915546..a1853ca 100644
--- a/src/libprotobuf-lite.map
+++ b/src/libprotobuf-lite.map
@@ -3,6 +3,8 @@
extern "C++" {
*google*;
};
+ scc_info_*;
+ descriptor_table_*;
local:
*;
diff --git a/src/libprotobuf.map b/src/libprotobuf.map
index 3915546..a1853ca 100644
--- a/src/libprotobuf.map
+++ b/src/libprotobuf.map
@@ -3,6 +3,8 @@
extern "C++" {
*google*;
};
+ scc_info_*;
+ descriptor_table_*;
local:
*;
diff --git a/src/libprotoc.map b/src/libprotoc.map
index 3915546..a1853ca 100644
--- a/src/libprotoc.map
+++ b/src/libprotoc.map
@@ -3,6 +3,8 @@
extern "C++" {
*google*;
};
+ scc_info_*;
+ descriptor_table_*;
local:
*;
diff --git a/version.json b/version.json
index 9593f13..695db4b 100644
--- a/version.json
+++ b/version.json
@@ -1,17 +1,17 @@
{
- "22.x": {
- "protoc_version": "22.2-dev",
+ "main": {
+ "protoc_version": "22-dev",
"lts": false,
- "date": "2023-03-07",
+ "date": "2022-07-21",
"languages": {
- "cpp": "4.22.2-dev",
- "csharp": "3.22.2-dev",
- "java": "3.22.2-dev",
- "javascript": "3.22.2-dev",
- "objectivec": "3.22.2-dev",
- "php": "3.22.2-dev",
- "python": "4.22.2-dev",
- "ruby": "3.22.2-dev"
+ "cpp": "4.22-dev",
+ "csharp": "3.22-dev",
+ "java": "3.22-dev",
+ "javascript": "3.22-dev",
+ "objectivec": "3.22-dev",
+ "php": "3.22-dev",
+ "python": "4.22-dev",
+ "ruby": "3.22-dev"
}
}
-}
\ No newline at end of file
+}