From cb39204af85533f1905b5715908c51adc46ca610 Mon Sep 17 00:00:00 2001 From: Pete Warden Date: Tue, 23 Feb 2016 10:18:32 -0800 Subject: [PATCH 001/123] Updated library generation with iOS options --- BUILD | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/BUILD b/BUILD index c4de1c4c..8667cc48 100644 --- a/BUILD +++ b/BUILD @@ -26,6 +26,25 @@ load( "internal_protobuf_py_tests", ) +config_setting( + name = "ios_arm", + values = { + "ios_cpu": "armv7", + "ios_cpu": "armv7s", + "ios_cpu": "arm64", + }, +) + +IOS_ARM_COPTS = COPTS + [ + "-DOS_IOS", + "-miphoneos-version-min=7.0", + "-arch armv7", + "-arch armv7s", + "-arch arm64", + "-D__thread=", + "-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.2.sdk/", +] + cc_library( name = "protobuf_lite", srcs = [ @@ -55,7 +74,10 @@ cc_library( "src/google/protobuf/wire_format_lite.cc", ], hdrs = glob(["src/google/protobuf/**/*.h"]), - copts = COPTS, + copts = select({ + ":ios_arm": IOS_ARM_COPTS, + "//conditions:default": COPTS, + }), includes = ["src/"], linkopts = LINK_OPTS, visibility = ["//visibility:public"], @@ -120,7 +142,10 @@ cc_library( "src/google/protobuf/wrappers.pb.cc", ], hdrs = glob(["src/**/*.h"]), - copts = COPTS, + copts = select({ + ":ios_arm": IOS_ARM_COPTS, + "//conditions:default": COPTS, + }), includes = ["src/"], linkopts = LINK_OPTS, visibility = ["//visibility:public"], From 57be1d7eb25432b9f0106d64faed323ef954f7d2 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 18 Feb 2016 14:55:00 -0800 Subject: [PATCH 002/123] Added some initial shell scripts and docker file. --- .travis.yml | 2 +- tools/docker/Dockerfile | 57 ++++++++++++++++++++ tools/jenkins/build_and_run_docker.sh | 78 +++++++++++++++++++++++++++ tools/jenkins/pull_request.sh | 6 +++ tools/run_tests/jenkins.sh | 13 +++++ travis.sh => tools/run_tests/tests.sh | 41 ++------------ tools/run_tests/travis.sh | 42 +++++++++++++++ 7 files changed, 200 insertions(+), 39 deletions(-) create mode 100644 tools/docker/Dockerfile create mode 100755 tools/jenkins/build_and_run_docker.sh create mode 100755 tools/jenkins/pull_request.sh create mode 100755 tools/run_tests/jenkins.sh rename travis.sh => tools/run_tests/tests.sh (88%) mode change 100755 => 100644 create mode 100755 tools/run_tests/travis.sh diff --git a/.travis.yml b/.travis.yml index 9bc4d88f..4a295401 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ os: # The Objective C build needs Xcode 7.0 or later. osx_image: xcode7.2 script: - - ./travis.sh $CONFIG + - ./tools/run_tests/travis.sh $CONFIG env: - CONFIG=cpp - CONFIG=cpp_distcheck diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile new file mode 100644 index 00000000..b5e26f9a --- /dev/null +++ b/tools/docker/Dockerfile @@ -0,0 +1,57 @@ +# Copyright 2015, Google Inc. +# All rights reserved. +# +# 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. + +# Base Dockerfile for gRPC dev images +FROM debian:latest + +# Install Git. +RUN apt-get update && apt-get install -y \ + autoconf \ + autotools-dev \ + build-essential \ + bzip2 \ + curl \ + gcc \ + git \ + libc6 \ + libc6-dbg \ + libc6-dev \ + libgtest-dev \ + libtool \ + make \ + strace \ + python-dev \ + python-setuptools \ + telnet \ + unzip \ + wget \ + zip && apt-get clean + +# Define the default command. +CMD ["bash"] diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/jenkins/build_and_run_docker.sh new file mode 100755 index 00000000..e77ffd61 --- /dev/null +++ b/tools/jenkins/build_and_run_docker.sh @@ -0,0 +1,78 @@ +#!/bin/bash +# Copyright 2016, Google Inc. +# All rights reserved. +# +# 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. +# +# Builds docker image and runs a command under it. +# You should never need to call this script on your own. + +set -ex + +cd $(dirname $0)/../.. +git_root=$(pwd) +cd - + +# Inputs +# DOCKERFILE_DIR - Directory in which Dockerfile file is located. +# DOCKER_RUN_SCRIPT - Script to run under docker (relative to protobuf repo root) +# OUTPUT_DIR - Directory that will be copied from inside docker after finishing. +# $@ - Extra args to pass to docker run + +# Use image name based on Dockerfile location checksum +DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ ) + +# Make sure docker image has been built. Should be instantaneous if so. +docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR + +# Choose random name for docker container +CONTAINER_NAME="build_and_run_docker_$(uuidgen)" + +# Run command inside docker +docker run \ + "$@" \ + -e EXTERNAL_GIT_ROOT="/var/local/jenkins/protobuf" \ + -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \ + -v "$git_root:/var/local/jenkins/protobuf:ro" \ + -w /var/local/git/protobuf \ + --name=$CONTAINER_NAME \ + $DOCKER_IMAGE_NAME \ + bash -l "/var/local/jenkins/protobuf/$DOCKER_RUN_SCRIPT" || FAILED="true" + +# Copy output artifacts +if [ "$OUTPUT_DIR" != "" ] +then + docker cp "$CONTAINER_NAME:/var/local/git/protobuf/$OUTPUT_DIR" "$git_root" || FAILED="true" +fi + +# remove the container, possibly killing it first +docker rm -f $CONTAINER_NAME || true + +if [ "$FAILED" != "" ] +then + exit 1 +fi diff --git a/tools/jenkins/pull_request.sh b/tools/jenkins/pull_request.sh new file mode 100755 index 00000000..cb0f4072 --- /dev/null +++ b/tools/jenkins/pull_request.sh @@ -0,0 +1,6 @@ +#!/bin/bash + + +export DOCKERFILE_DIR=tools/docker +export DOCKER_RUN_SCRIPT=tools/run_tests/jenkins.sh +./tools/jenkins/build_and_run_docker.sh diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh new file mode 100755 index 00000000..34a16829 --- /dev/null +++ b/tools/run_tests/jenkins.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +MY_DIR="$(dirname "$0")" +BUILD_DIR=/tmp/protobuf + +source $MY_DIR/tests.sh + +rm -rf $BUILD_DIR +mkdir -p $BUILD_DIR +cd $BUILD_DIR +git clone /var/local/jenkins/protobuf +cd protobuf +build_cpp diff --git a/travis.sh b/tools/run_tests/tests.sh old mode 100755 new mode 100644 similarity index 88% rename from travis.sh rename to tools/run_tests/tests.sh index ff5e99d5..f1c7e969 --- a/travis.sh +++ b/tools/run_tests/tests.sh @@ -1,17 +1,10 @@ -#!/usr/bin/env bash - -# Note: travis currently does not support testing more than one language so the -# .travis.yml cheats and claims to only be cpp. If they add multiple language -# support, this should probably get updated to install steps and/or -# rvm/gemfile/jdk/etc. entries rather than manually doing the work. - -# .travis.yml uses matrix.exclude to block the cases where app-get can't be -# use to install things. +# This file is not intended to be executed directly. It is intended to be +# included in a larger shell script. # For when some other test needs the C++ main build, including protoc and # libprotobuf. internal_build_cpp() { - if [ $(uname -s) == "Linux" ]; then + if [ $(uname -s) == "Linux" && "$TRAVIS" == "true" ]; then # Install GCC 4.8 to replace the default GCC 4.6. We need 4.8 for more # decent C++ 11 support in order to compile conformance tests. sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y @@ -284,31 +277,3 @@ build_javascript() { cd js && npm install && npm test && cd .. } -# -------- main -------- - -if [ "$#" -ne 1 ]; then - echo " -Usage: $0 { cpp | - csharp | - java_jdk6 | - java_jdk7 | - java_oracle7 | - javanano_jdk6 | - javanano_jdk7 | - javanano_oracle7 | - objectivec_ios | - objectivec_osx | - python | - python_cpp | - ruby_19 | - ruby_20 | - ruby_21 | - ruby_22 | - jruby } -" - exit 1 -fi - -set -e # exit immediately on error -set -x # display all commands -eval "build_$1" diff --git a/tools/run_tests/travis.sh b/tools/run_tests/travis.sh new file mode 100755 index 00000000..8c87a47b --- /dev/null +++ b/tools/run_tests/travis.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +my_dir="$(dirname "$0")" + +source $my_dir/tests.sh + +# Note: travis currently does not support testing more than one language so the +# .travis.yml cheats and claims to only be cpp. If they add multiple language +# support, this should probably get updated to install steps and/or +# rvm/gemfile/jdk/etc. entries rather than manually doing the work. + +# .travis.yml uses matrix.exclude to block the cases where app-get can't be +# use to install things. + +# -------- main -------- + +if [ "$#" -ne 1 ]; then + echo " +Usage: $0 { cpp | + csharp | + java_jdk6 | + java_jdk7 | + java_oracle7 | + javanano_jdk6 | + javanano_jdk7 | + javanano_oracle7 | + objectivec_ios | + objectivec_osx | + python | + python_cpp | + ruby_19 | + ruby_20 | + ruby_21 | + ruby_22 | + jruby } +" + exit 1 +fi + +set -e # exit immediately on error +set -x # display all commands +eval "build_$1" From d33e93b83367ea4dfabeed9cda03bc06a1ff0f6a Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 18 Feb 2016 19:13:07 -0800 Subject: [PATCH 003/123] Added ccache support. --- tools/docker/Dockerfile | 9 +++++++++ tools/run_tests/jenkins.sh | 4 ++++ tools/run_tests/tests.sh | 8 ++++---- tools/run_tests/travis.sh | 7 +++++-- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b5e26f9a..b1d0c682 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -36,6 +36,7 @@ RUN apt-get update && apt-get install -y \ autotools-dev \ build-essential \ bzip2 \ + ccache \ curl \ gcc \ git \ @@ -53,5 +54,13 @@ RUN apt-get update && apt-get install -y \ wget \ zip && apt-get clean +# Prepare ccache +RUN ln -s /usr/bin/ccache /usr/local/bin/gcc +RUN ln -s /usr/bin/ccache /usr/local/bin/g++ +RUN ln -s /usr/bin/ccache /usr/local/bin/cc +RUN ln -s /usr/bin/ccache /usr/local/bin/c++ +RUN ln -s /usr/bin/ccache /usr/local/bin/clang +RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ + # Define the default command. CMD ["bash"] diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index 34a16829..b90c099f 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -5,9 +5,13 @@ BUILD_DIR=/tmp/protobuf source $MY_DIR/tests.sh +# Set value used in tests.sh. +PARALLELISM=-j8 + rm -rf $BUILD_DIR mkdir -p $BUILD_DIR cd $BUILD_DIR git clone /var/local/jenkins/protobuf cd protobuf + build_cpp diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index f1c7e969..a6ba1405 100644 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -4,7 +4,7 @@ # For when some other test needs the C++ main build, including protoc and # libprotobuf. internal_build_cpp() { - if [ $(uname -s) == "Linux" && "$TRAVIS" == "true" ]; then + if [[ $(uname -s) == "Linux" && "$TRAVIS" == "true" ]]; then # Install GCC 4.8 to replace the default GCC 4.6. We need 4.8 for more # decent C++ 11 support in order to compile conformance tests. sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y @@ -15,19 +15,19 @@ internal_build_cpp() { ./autogen.sh ./configure - make -j2 + make $PARALLELISM } build_cpp() { internal_build_cpp - make check -j2 + make check $PARALLELISM cd conformance && make test_cpp && cd .. } build_cpp_distcheck() { ./autogen.sh ./configure - make distcheck -j2 + make distcheck $PARALLELISM } build_csharp() { diff --git a/tools/run_tests/travis.sh b/tools/run_tests/travis.sh index 8c87a47b..f7045f1b 100755 --- a/tools/run_tests/travis.sh +++ b/tools/run_tests/travis.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash -my_dir="$(dirname "$0")" +MY_DIR="$(dirname "$0")" -source $my_dir/tests.sh +source $MY_DIR/tests.sh # Note: travis currently does not support testing more than one language so the # .travis.yml cheats and claims to only be cpp. If they add multiple language @@ -14,6 +14,9 @@ source $my_dir/tests.sh # -------- main -------- +# Set value used in tests.sh. +PARALLELISM=-j2 + if [ "$#" -ne 1 ]; then echo " Usage: $0 { cpp | From 738393b2c0690bcb92a6689f3a07d518289c4dde Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 18 Feb 2016 20:10:23 -0800 Subject: [PATCH 004/123] Try running multiple tests in a row. --- .travis.yml | 2 +- tools/run_tests/jenkins.sh | 12 +++++++--- tools/run_tests/tests.sh | 49 ++++++++++++++++++++++++++++++++++++-- tools/run_tests/travis.sh | 45 ---------------------------------- 4 files changed, 57 insertions(+), 51 deletions(-) mode change 100644 => 100755 tools/run_tests/tests.sh delete mode 100755 tools/run_tests/travis.sh diff --git a/.travis.yml b/.travis.yml index 4a295401..26b9dcaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ os: # The Objective C build needs Xcode 7.0 or later. osx_image: xcode7.2 script: - - ./tools/run_tests/travis.sh $CONFIG + - ./tools/run_tests/tests.sh $CONFIG env: - CONFIG=cpp - CONFIG=cpp_distcheck diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index b90c099f..e174a209 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -1,17 +1,23 @@ #!/bin/bash MY_DIR="$(dirname "$0")" +TEST_SCRIPT=$MY_DIR/tests.sh BUILD_DIR=/tmp/protobuf -source $MY_DIR/tests.sh - # Set value used in tests.sh. PARALLELISM=-j8 +set -x # display all commands + rm -rf $BUILD_DIR mkdir -p $BUILD_DIR cd $BUILD_DIR git clone /var/local/jenkins/protobuf cd protobuf -build_cpp +# If protoc fails to build, we can't test anything else. +$TEST_SCRIPT cpp || exit 1 + +# Other tests can fail and we keep on going. +$TEST_SCRIPT java_jdk6 +$TEST_SCRIPT java_jdk7 diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh old mode 100644 new mode 100755 index a6ba1405..718d6de9 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -1,9 +1,13 @@ -# This file is not intended to be executed directly. It is intended to be -# included in a larger shell script. +#!/bin/bash # For when some other test needs the C++ main build, including protoc and # libprotobuf. internal_build_cpp() { + if [ -f src/protoc ]; then + # Already built. + return + fi + if [[ $(uname -s) == "Linux" && "$TRAVIS" == "true" ]]; then # Install GCC 4.8 to replace the default GCC 4.6. We need 4.8 for more # decent C++ 11 support in order to compile conformance tests. @@ -277,3 +281,44 @@ build_javascript() { cd js && npm install && npm test && cd .. } +[ -n "${PARALLELISM}" ] && PARALLELISM=-j8 + +# Note: travis currently does not support testing more than one language so the +# .travis.yml cheats and claims to only be cpp. If they add multiple language +# support, this should probably get updated to install steps and/or +# rvm/gemfile/jdk/etc. entries rather than manually doing the work. + +# .travis.yml uses matrix.exclude to block the cases where app-get can't be +# use to install things. + +# -------- main -------- + +# Set value used in tests.sh. +PARALLELISM=-j2 + +if [ "$#" -ne 1 ]; then + echo " +Usage: $0 { cpp | + csharp | + java_jdk6 | + java_jdk7 | + java_oracle7 | + javanano_jdk6 | + javanano_jdk7 | + javanano_oracle7 | + objectivec_ios | + objectivec_osx | + python | + python_cpp | + ruby_19 | + ruby_20 | + ruby_21 | + ruby_22 | + jruby } +" + exit 1 +fi + +set -e # exit immediately on error +set -x # display all commands +eval "build_$1" diff --git a/tools/run_tests/travis.sh b/tools/run_tests/travis.sh deleted file mode 100755 index f7045f1b..00000000 --- a/tools/run_tests/travis.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bash - -MY_DIR="$(dirname "$0")" - -source $MY_DIR/tests.sh - -# Note: travis currently does not support testing more than one language so the -# .travis.yml cheats and claims to only be cpp. If they add multiple language -# support, this should probably get updated to install steps and/or -# rvm/gemfile/jdk/etc. entries rather than manually doing the work. - -# .travis.yml uses matrix.exclude to block the cases where app-get can't be -# use to install things. - -# -------- main -------- - -# Set value used in tests.sh. -PARALLELISM=-j2 - -if [ "$#" -ne 1 ]; then - echo " -Usage: $0 { cpp | - csharp | - java_jdk6 | - java_jdk7 | - java_oracle7 | - javanano_jdk6 | - javanano_jdk7 | - javanano_oracle7 | - objectivec_ios | - objectivec_osx | - python | - python_cpp | - ruby_19 | - ruby_20 | - ruby_21 | - ruby_22 | - jruby } -" - exit 1 -fi - -set -e # exit immediately on error -set -x # display all commands -eval "build_$1" From 0f8c25d1050b8d20ed73b72e5b36344fb9b497dc Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 19 Feb 2016 09:11:38 -0800 Subject: [PATCH 005/123] Properly add JDK deps in the Docker image. --- tools/docker/Dockerfile | 12 ++++++++++-- tools/run_tests/jenkins.sh | 2 +- tools/run_tests/tests.sh | 10 ++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b1d0c682..8770d16e 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -30,7 +30,8 @@ # Base Dockerfile for gRPC dev images FROM debian:latest -# Install Git. +# Install dependencies. We start with the basic ones require to build protoc +# and the C++ build RUN apt-get update && apt-get install -y \ autoconf \ autotools-dev \ @@ -52,7 +53,14 @@ RUN apt-get update && apt-get install -y \ telnet \ unzip \ wget \ - zip && apt-get clean + zip \ + # For all Java builds \ + maven \ + # For java_jdk6 \ + # oops! not in Jessie. Too old? openjdk-6-jdk \ + # For java_jdk7 \ + openjdk-7-jdk \ + && apt-get clean # Prepare ccache RUN ln -s /usr/bin/ccache /usr/local/bin/gcc diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index e174a209..bbca3389 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -19,5 +19,5 @@ cd protobuf $TEST_SCRIPT cpp || exit 1 # Other tests can fail and we keep on going. -$TEST_SCRIPT java_jdk6 +#$TEST_SCRIPT java_jdk6 $TEST_SCRIPT java_jdk7 diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index 718d6de9..db499755 100755 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -1,5 +1,11 @@ #!/bin/bash +on_travis() { + if [ "$TRAVIS" == "true" ]; then + "$@" + fi +} + # For when some other test needs the C++ main build, including protoc and # libprotobuf. internal_build_cpp() { @@ -75,11 +81,11 @@ use_java() { version=$1 case "$version" in jdk6) - sudo apt-get install openjdk-6-jdk + on_travis sudo apt-get install openjdk-6-jdk export PATH=/usr/lib/jvm/java-6-openjdk-amd64/bin:$PATH ;; jdk7) - sudo apt-get install openjdk-7-jdk + on_travis sudo apt-get install openjdk-7-jdk export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH ;; oracle7) From 0b931bcd53897954cf96cd8075bb6fc16651559d Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 19 Feb 2016 12:33:17 -0800 Subject: [PATCH 006/123] Add another test (javanano), but run it in parallel. --- tools/docker/Dockerfile | 1 + tools/run_tests/jenkins.sh | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 8770d16e..7d9def05 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -47,6 +47,7 @@ RUN apt-get update && apt-get install -y \ libgtest-dev \ libtool \ make \ + parallel \ strace \ python-dev \ python-setuptools \ diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index bbca3389..c0d02ddc 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -7,6 +7,7 @@ BUILD_DIR=/tmp/protobuf # Set value used in tests.sh. PARALLELISM=-j8 +set -e # exit immediately on error set -x # display all commands rm -rf $BUILD_DIR @@ -15,9 +16,15 @@ cd $BUILD_DIR git clone /var/local/jenkins/protobuf cd protobuf -# If protoc fails to build, we can't test anything else. -$TEST_SCRIPT cpp || exit 1 +OUTPUT_DIR=`mktemp -d` +mkdir -p $OUTPUT_DIR/1 -# Other tests can fail and we keep on going. -#$TEST_SCRIPT java_jdk6 -$TEST_SCRIPT java_jdk7 +# cpp build needs to run first, non-parallelized, so that protoc is available +# for other builds. +$TEST_SCRIPT cpp | tee $OUTPUT_DIR/1/cpp + +# Other tests are run in parallel. The overall run fails if any one of them +# fails. + +# java_jdk6 +parallel $TEST_SCRIPT ::: java_jdk7 javanano_jdk7 From 483533d3a21a9d689aafb4c259301aa44cef75ed Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 19 Feb 2016 12:48:33 -0800 Subject: [PATCH 007/123] Install Python deps in Docker image. --- tools/docker/Dockerfile | 26 +++++++++++++++----------- tools/run_tests/jenkins.sh | 9 +++++++-- tools/run_tests/tests.sh | 3 +++ 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 7d9def05..b5b712fa 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -30,6 +30,10 @@ # Base Dockerfile for gRPC dev images FROM debian:latest +RUN echo 'deb http://ppa.launchpad.net/fkrull/deadsnakes/ubuntu trusty main' > /etc/apt/sources.list.d/deadsnakes.list && \ + gpg --keyserver keyserver.ubuntu.com --recv-keys DB82666C && \ + gpg --export DB82666C | apt-key add - + # Install dependencies. We start with the basic ones require to build protoc # and the C++ build RUN apt-get update && apt-get install -y \ @@ -48,19 +52,19 @@ RUN apt-get update && apt-get install -y \ libtool \ make \ parallel \ - strace \ - python-dev \ - python-setuptools \ - telnet \ - unzip \ - wget \ - zip \ - # For all Java builds \ + # -- For all Java builds -- \ maven \ - # For java_jdk6 \ - # oops! not in Jessie. Too old? openjdk-6-jdk \ - # For java_jdk7 \ + # -- For java_jdk6 -- \ + # oops! not in jessie. too old? openjdk-6-jdk \ + # -- For java_jdk7 -- \ openjdk-7-jdk \ + # -- For python / python_cpp -- \ + python-setuptools \ + python-tox \ + python-dev \ + python2.6-dev \ + python3.3-dev \ + python3.4-dev \ && apt-get clean # Prepare ccache diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index c0d02ddc..1d192aa4 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -26,5 +26,10 @@ $TEST_SCRIPT cpp | tee $OUTPUT_DIR/1/cpp # Other tests are run in parallel. The overall run fails if any one of them # fails. -# java_jdk6 -parallel $TEST_SCRIPT ::: java_jdk7 javanano_jdk7 +parallel $TEST_SCRIPT ::: \ + java_jdk7 \ + javanano_jdk7 \ + python \ + python_cpp + +# java_jdk6 \ diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index db499755..5281cd20 100755 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -152,6 +152,9 @@ build_javanano_oracle7() { } internal_install_python_deps() { + if [ "$TRAVIS" != "true" ]; then + return; + fi # Install tox (OS X doesn't have pip). if [ $(uname -s) == "Darwin" ]; then sudo easy_install tox From d08c39c21884b73d9bd2a0cfd0e6b8851444d391 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Sat, 20 Feb 2016 12:03:39 -0800 Subject: [PATCH 008/123] Put Maven in batch mode to avoid spamming the logs. --- tools/run_tests/tests.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index 5281cd20..7ada81f8 100755 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -102,19 +102,22 @@ use_java() { java -version } +# --batch-mode supresses download progress output that spams the logs. +MVN=mvn --batch-mode + build_java() { # Java build needs `protoc`. internal_build_cpp - cd java && mvn test && mvn install - cd util && mvn test + cd java && $MVN test && $MVN install + cd util && $MVN test cd ../.. } build_java_with_conformance_tests() { # Java build needs `protoc`. internal_build_cpp - cd java && mvn test && mvn install - cd util && mvn test && mvn assembly:single + cd java && $MVN test && $MVN install + cd util && $MVN test && $MVN assembly:single cd ../.. cd conformance && make test_java && cd .. } From b28b3f60a105af9b7ea05637b367429a3b6852c9 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Sat, 20 Feb 2016 12:17:10 -0800 Subject: [PATCH 009/123] Configure ccache directory. --- tools/jenkins/build_and_run_docker.sh | 6 ++++++ tools/run_tests/tests.sh | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/jenkins/build_and_run_docker.sh index e77ffd61..448b00c0 100755 --- a/tools/jenkins/build_and_run_docker.sh +++ b/tools/jenkins/build_and_run_docker.sh @@ -52,12 +52,18 @@ docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR # Choose random name for docker container CONTAINER_NAME="build_and_run_docker_$(uuidgen)" +# Ensure existence of ccache directory +CCACHE_DIR=/tmp/protobuf-ccache +mkdir -p $CCACHE_DIR + # Run command inside docker docker run \ "$@" \ + -e CCACHE_DIR=$CCACHE_DIR \ -e EXTERNAL_GIT_ROOT="/var/local/jenkins/protobuf" \ -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \ -v "$git_root:/var/local/jenkins/protobuf:ro" \ + -v $CCACHE_DIR:$CCACHE_DIR \ -w /var/local/git/protobuf \ --name=$CONTAINER_NAME \ $DOCKER_IMAGE_NAME \ diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index 7ada81f8..353ce62d 100755 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -103,7 +103,7 @@ use_java() { } # --batch-mode supresses download progress output that spams the logs. -MVN=mvn --batch-mode +MVN="mvn --batch-mode" build_java() { # Java build needs `protoc`. @@ -125,7 +125,7 @@ build_java_with_conformance_tests() { build_javanano() { # Java build needs `protoc`. internal_build_cpp - cd javanano && mvn test && cd .. + cd javanano && $MVN test && cd .. } build_java_jdk6() { From f6153b540a71475b1af8cc6818a28d1145763e83 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Sat, 20 Feb 2016 12:50:27 -0800 Subject: [PATCH 010/123] Work around tox bug. --- python/tox.ini | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/python/tox.ini b/python/tox.ini index cf8d5401..f663b538 100644 --- a/python/tox.ini +++ b/python/tox.ini @@ -6,6 +6,10 @@ envlist = usedevelop=true passenv = CC setenv = + # Dummy entry works around bug where tox fails for empty "setenv" section + # (since cpp lines aren't used for py builds). + # https://bitbucket.org/hpk42/tox/issues/190/generative-setenv-fails-if-there-s-only + DUMMY=dummy cpp: LD_LIBRARY_PATH={toxinidir}/../src/.libs cpp: DYLD_LIBRARY_PATH={toxinidir}/../src/.libs cpp: PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp From 78f9b68600c32492100ad61eb6b53ffa1f74263b Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Mon, 22 Feb 2016 14:26:21 -0800 Subject: [PATCH 011/123] Upgrade Python packages using pip. --- tools/docker/Dockerfile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b5b712fa..2a451321 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -60,13 +60,19 @@ RUN apt-get update && apt-get install -y \ openjdk-7-jdk \ # -- For python / python_cpp -- \ python-setuptools \ - python-tox \ + python-pip \ python-dev \ python2.6-dev \ python3.3-dev \ python3.4-dev \ && apt-get clean +# These packages exist in apt-get, but their versions are too old, so we have +# to get updates from pip. + +RUN pip install pip --upgrade +RUN pip install virtualenv tox + # Prepare ccache RUN ln -s /usr/bin/ccache /usr/local/bin/gcc RUN ln -s /usr/bin/ccache /usr/local/bin/g++ From ffc811804f4067c39f53d89fcbcaff1680d8e1fd Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Mon, 22 Feb 2016 15:39:29 -0800 Subject: [PATCH 012/123] Added Ruby 2.1, Oracle Java, and C#. --- tools/docker/Dockerfile | 47 ++++++++++++++++++++++++++++++++++++-- tools/run_tests/jenkins.sh | 10 ++++++-- tools/run_tests/tests.sh | 40 ++++++++++++++++++-------------- 3 files changed, 76 insertions(+), 21 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 2a451321..57830565 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -30,9 +30,19 @@ # Base Dockerfile for gRPC dev images FROM debian:latest +# Apt source for old Python versions. RUN echo 'deb http://ppa.launchpad.net/fkrull/deadsnakes/ubuntu trusty main' > /etc/apt/sources.list.d/deadsnakes.list && \ - gpg --keyserver keyserver.ubuntu.com --recv-keys DB82666C && \ - gpg --export DB82666C | apt-key add - + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys DB82666C + +# Apt source for Oracle Java. +run echo 'deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' > /etc/apt/sources.list.d/webupd8team-java-trusty.list && \ + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys EEA14886 && \ + echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | debconf-set-selections + +# Apt source for Mono +run echo "deb http://download.mono-project.com/repo/debian wheezy main" | tee /etc/apt/sources.list.d/mono-xamarin.list && \ + echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | tee -a /etc/apt/sources.list.d/mono-xamarin.list && \ + apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF # Install dependencies. We start with the basic ones require to build protoc # and the C++ build @@ -52,12 +62,19 @@ RUN apt-get update && apt-get install -y \ libtool \ make \ parallel \ + wget \ + # -- For csharp -- + mono-devel \ + referenceassemblies-pcl \ + nunit \ # -- For all Java builds -- \ maven \ # -- For java_jdk6 -- \ # oops! not in jessie. too old? openjdk-6-jdk \ # -- For java_jdk7 -- \ openjdk-7-jdk \ + # -- For java_oracle7 -- \ + oracle-java7-installer \ # -- For python / python_cpp -- \ python-setuptools \ python-pip \ @@ -65,14 +82,40 @@ RUN apt-get update && apt-get install -y \ python2.6-dev \ python3.3-dev \ python3.4-dev \ + # -- For Ruby -- + ruby \ && apt-get clean +################## +# C# dependencies + +RUN wget www.nuget.org/NuGet.exe -O /usr/local/bin/nuget.exe + +################## +# Python dependencies + # These packages exist in apt-get, but their versions are too old, so we have # to get updates from pip. RUN pip install pip --upgrade RUN pip install virtualenv tox + +################## +# Ruby dependencies + +# Install rvm +RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 +RUN \curl -sSL https://get.rvm.io | bash -s stable + +# Install Ruby 2.1 +RUN /bin/bash -l -c "rvm install ruby-2.1" +RUN /bin/bash -l -c "rvm use --default ruby-2.1" +RUN /bin/bash -l -c "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" +RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc" +RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc" +RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc" + # Prepare ccache RUN ln -s /usr/bin/ccache /usr/local/bin/gcc RUN ln -s /usr/bin/ccache /usr/local/bin/g++ diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index 1d192aa4..620c2116 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -26,10 +26,16 @@ $TEST_SCRIPT cpp | tee $OUTPUT_DIR/1/cpp # Other tests are run in parallel. The overall run fails if any one of them # fails. -parallel $TEST_SCRIPT ::: \ +parallel --results $OUTPUT_DIR $TEST_SCRIPT ::: \ + csharp \ java_jdk7 \ javanano_jdk7 \ + java_oracle7 \ + javanano_oracle7 \ python \ - python_cpp + python_cpp \ + ruby21 # java_jdk6 \ + +find $OUTPUT_DIR diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index 353ce62d..623cf96c 100755 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -45,16 +45,20 @@ build_csharp() { # need to really build protoc, but it's simplest to keep with the # conventions of the other builds. internal_build_cpp + NUGET=/usr/local/bin/nuget.exe - # Install latest version of Mono - sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF - echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list - echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list - sudo apt-get update -qq - sudo apt-get install -qq mono-devel referenceassemblies-pcl nunit - wget www.nuget.org/NuGet.exe -O nuget.exe + if [ "$TRAVIS" == "true" ]; then + # Install latest version of Mono + sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF + echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list + echo "deb http://download.mono-project.com/repo/debian wheezy-libtiff-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list + sudo apt-get update -qq + sudo apt-get install -qq mono-devel referenceassemblies-pcl nunit + wget www.nuget.org/NuGet.exe -O nuget.exe + NUGET=../../nuget.exe + fi - (cd csharp/src; mono ../../nuget.exe restore) + (cd csharp/src; mono $NUGET restore) csharp/buildall.sh cd conformance && make test_csharp && cd .. } @@ -89,11 +93,13 @@ use_java() { export PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH ;; oracle7) - sudo apt-get install python-software-properties # for apt-add-repository - echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | \ - sudo debconf-set-selections - yes | sudo apt-add-repository ppa:webupd8team/java - yes | sudo apt-get install oracle-java7-installer + if [ "$TRAVIS" == "true" ]; then + sudo apt-get install python-software-properties # for apt-add-repository + echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 select true" | \ + sudo debconf-set-selections + yes | sudo apt-add-repository ppa:webupd8team/java + yes | sudo apt-get install oracle-java7-installer + fi; export PATH=/usr/lib/jvm/java-7-oracle/bin:$PATH ;; esac @@ -322,10 +328,10 @@ Usage: $0 { cpp | objectivec_osx | python | python_cpp | - ruby_19 | - ruby_20 | - ruby_21 | - ruby_22 | + ruby19 | + ruby20 | + ruby21 | + ruby22 | jruby } " exit 1 From 38bc15552de259fa99c8e9654bed0ff8433902eb Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 23 Feb 2016 14:28:02 -0800 Subject: [PATCH 013/123] Added code to generate XML output file for more granular results. --- python/tox.ini | 4 -- tools/docker/Dockerfile | 2 +- tools/jenkins/make_test_output.py | 90 +++++++++++++++++++++++++++++++ tools/jenkins/pull_request.sh | 1 + tools/run_tests/jenkins.sh | 36 ++++++++++--- 5 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 tools/jenkins/make_test_output.py diff --git a/python/tox.ini b/python/tox.ini index f663b538..cf8d5401 100644 --- a/python/tox.ini +++ b/python/tox.ini @@ -6,10 +6,6 @@ envlist = usedevelop=true passenv = CC setenv = - # Dummy entry works around bug where tox fails for empty "setenv" section - # (since cpp lines aren't used for py builds). - # https://bitbucket.org/hpk42/tox/issues/190/generative-setenv-fails-if-there-s-only - DUMMY=dummy cpp: LD_LIBRARY_PATH={toxinidir}/../src/.libs cpp: DYLD_LIBRARY_PATH={toxinidir}/../src/.libs cpp: PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 57830565..bceb6044 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -98,7 +98,7 @@ RUN wget www.nuget.org/NuGet.exe -O /usr/local/bin/nuget.exe # to get updates from pip. RUN pip install pip --upgrade -RUN pip install virtualenv tox +RUN pip install virtualenv tox yattag ################## diff --git a/tools/jenkins/make_test_output.py b/tools/jenkins/make_test_output.py new file mode 100644 index 00000000..0ba5db3b --- /dev/null +++ b/tools/jenkins/make_test_output.py @@ -0,0 +1,90 @@ +"""Gather output from test runs and create an XML file in JUnit format. + +The output files from the individual tests have been written in a directory +structure like: + + $DIR/joblog (--joblog from "parallel") + $DIR/logs/1/cpp/stdout + $DIR/logs/1/cpp/stderr + $DIR/logs/1/csharp/stdout + $DIR/logs/1/csharp/stderr + $DIR/logs/1/java_jdk7/stdout + $DIR/logs/1/java_jdk7/stderr + etc. + +This script bundles them into a single output XML file so Jenkins can show +detailed test results. +""" + +import os; +import sys; +from yattag import Doc +from collections import defaultdict + +def readtests(basedir): + tests = defaultdict(dict) + + # Sample input (note: separators are tabs). + # + # Seq Host Starttime Runtime Send Receive Exitval Signal Command + # 1 : 1456263838.313 0.005 0 0 0 0 echo A + with open(basedir + "/joblog") as jobs: + firstline = next(jobs) + for line in jobs: + values = line.split("\t") + + name = values[8].split()[-1] + test = tests[name] + test["name"] = name + test["time"] = values[3] + + exitval = values[6] + if int(exitval): + # We don't have a more specific message. User should look at stderr. + test["failure"] = "TEST FAILURE" + else: + test["failure"] = False + + for testname in os.listdir(basedir + "/logs/1"): + test = tests[testname] + + with open(basedir + "/logs/1/" + testname + "/stdout") as f: + test["stdout"] = f.read() + + with open(basedir + "/logs/1/" + testname + "/stderr") as f: + test["stderr"] = f.read() + + # The cpp test is special since it doesn't run under parallel so doesn't show + # up in the job log. + tests["cpp"]["name"] = "cpp" + + # TODO + tests["cpp"]["time"] = "0" + tests["cpp"]["failure"] = False + + ret = tests.values() + ret.sort(key=lambda x: x["name"]) + + return ret + +def genxml(tests): + doc, tag, text = Doc().tagtext() + + with tag("testsuites"): + with tag("testsuite", name="Protobuf Tests"): + for test in tests: + with tag("testcase", name=test["name"], classname=test["name"], + time=test["time"]): + with tag("system-out"): + text(test["stdout"]) + with tag("system-err"): + text(test["stderr"]) + if test["failure"]: + with tag("failure"): + text(test["failure"]) + + return doc.getvalue() + +sys.stderr.write("make_test_output.py: writing XML from directory: " + + sys.argv[1] + "\n"); +print genxml(readtests(sys.argv[1])) diff --git a/tools/jenkins/pull_request.sh b/tools/jenkins/pull_request.sh index cb0f4072..00538b9c 100755 --- a/tools/jenkins/pull_request.sh +++ b/tools/jenkins/pull_request.sh @@ -3,4 +3,5 @@ export DOCKERFILE_DIR=tools/docker export DOCKER_RUN_SCRIPT=tools/run_tests/jenkins.sh +export OUTPUT_DIR=testoutput ./tools/jenkins/build_and_run_docker.sh diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index 620c2116..32050d25 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -1,5 +1,6 @@ #!/bin/bash +WORKSPACE_BASE=`pwd` MY_DIR="$(dirname "$0")" TEST_SCRIPT=$MY_DIR/tests.sh BUILD_DIR=/tmp/protobuf @@ -17,16 +18,30 @@ git clone /var/local/jenkins/protobuf cd protobuf OUTPUT_DIR=`mktemp -d` -mkdir -p $OUTPUT_DIR/1 +LOG_OUTPUT_DIR=$OUTPUT_DIR/logs +mkdir -p $LOG_OUTPUT_DIR/1/cpp +################################################################################ # cpp build needs to run first, non-parallelized, so that protoc is available # for other builds. -$TEST_SCRIPT cpp | tee $OUTPUT_DIR/1/cpp + +# Output filenames to follow the overall scheme used by parallel, ie: +# $DIR/logs/1/cpp/stdout +# $DIR/logs/1/cpp/stderr +# $DIR/logs/1/csharp/stdout +# $DIR/logs/1/csharp/stderr +# $DIR/logs/1/java_jdk7/stdout +# $DIR/logs/1/java_jdk7/stderr +CPP_STDOUT=$LOG_OUTPUT_DIR/1/cpp/stdout +CPP_STDERR=$LOG_OUTPUT_DIR/1/cpp/stderr +$TEST_SCRIPT cpp > >(tee $CPP_STDOUT) 2> >(tee $CPP_STDERR >&2) # Other tests are run in parallel. The overall run fails if any one of them # fails. -parallel --results $OUTPUT_DIR $TEST_SCRIPT ::: \ +FAILED=false + +parallel --results $LOG_OUTPUT_DIR --joblog $OUTPUT_DIR/joblog $TEST_SCRIPT ::: \ csharp \ java_jdk7 \ javanano_jdk7 \ @@ -34,8 +49,17 @@ parallel --results $OUTPUT_DIR $TEST_SCRIPT ::: \ javanano_oracle7 \ python \ python_cpp \ - ruby21 + ruby21 \ + || true # Process test results even if tests fail. +# The directory that is copied from Docker back into the Jenkins workspace. +COPY_FROM_DOCKER=/var/local/git/protobuf/testoutput +mkdir -p $COPY_FROM_DOCKER +TESTOUTPUT_XML_FILE=$COPY_FROM_DOCKER/testresults.xml + +python $MY_DIR/../jenkins/make_test_output.py $OUTPUT_DIR > $TESTOUTPUT_XML_FILE + +ls -l $TESTOUTPUT_XML_FILE + +### disabled tests # java_jdk6 \ - -find $OUTPUT_DIR From 2f3f1de16debdff284792367245d5ba0e9310b35 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 1 Mar 2016 15:37:17 -0800 Subject: [PATCH 014/123] Make Java copy into separate directories so the tests can run concurrently. --- tools/run_tests/tests.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index 623cf96c..4b2aef77 100755 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -112,18 +112,22 @@ use_java() { MVN="mvn --batch-mode" build_java() { + version=$1 + dir=java_$version # Java build needs `protoc`. internal_build_cpp - cd java && $MVN test && $MVN install - cd util && $MVN test + cp -r java $dir + cd $dir && $MVN clean && $MVN test cd ../.. } +# The conformance tests are hard-coded to work with the $ROOT/java directory. +# So this can't run in parallel with two different sets of tests. build_java_with_conformance_tests() { # Java build needs `protoc`. internal_build_cpp cd java && $MVN test && $MVN install - cd util && $MVN test && $MVN assembly:single + cd util && $MVN package assembly:single cd ../.. cd conformance && make test_java && cd .. } @@ -136,7 +140,7 @@ build_javanano() { build_java_jdk6() { use_java jdk6 - build_java + build_java jdk6 } build_java_jdk7() { use_java jdk7 @@ -144,7 +148,7 @@ build_java_jdk7() { } build_java_oracle7() { use_java oracle7 - build_java + build_java oracle7 } build_javanano_jdk6() { From b5a35b441107c40e53584cf655dd558a05f40e79 Mon Sep 17 00:00:00 2001 From: Sergio Campama Date: Thu, 3 Mar 2016 16:45:15 -0300 Subject: [PATCH 015/123] Adds more information to Objective C error when the expected objc_class_prefix option is missing. --- src/google/protobuf/compiler/objectivec/objectivec_helpers.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index 77a378c8..3e7ccb43 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -968,7 +968,8 @@ bool ValidateObjCClassPrefix(const FileDescriptor* file, } else { // ...it didn't match! *out_error = "error: Expected 'option objc_class_prefix = \"" + - package_match->second + "\";' in '" + file->name() + "'"; + package_match->second + "\";' for package '" + package + + "' in '" + file->name() + "'"; if (prefix.length()) { *out_error += "; but found '" + prefix + "' instead"; } From 1ee0fda556b252944e7dd140ad0cd7b8949eb496 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 3 Mar 2016 16:02:55 -0800 Subject: [PATCH 016/123] Use a local Maven repository to avoid network fetches during tests. --- tools/docker/Dockerfile | 26 ++++++++++++++++++++++++++ tools/run_tests/tests.sh | 5 +++++ 2 files changed, 31 insertions(+) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index bceb6044..b7621f67 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -116,7 +116,11 @@ RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc" RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc" RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc" +################## # Prepare ccache + +# We do this BEFORE the Java dependency step below, so the build of protoc +# can benefit from it. RUN ln -s /usr/bin/ccache /usr/local/bin/gcc RUN ln -s /usr/bin/ccache /usr/local/bin/g++ RUN ln -s /usr/bin/ccache /usr/local/bin/cc @@ -124,5 +128,27 @@ RUN ln -s /usr/bin/ccache /usr/local/bin/c++ RUN ln -s /usr/bin/ccache /usr/local/bin/clang RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ + +################## +# Java dependencies + +# This step requires compiling protoc. :( + +ENV MAVEN_REPO /var/maven_local_repository +ENV MVN mvn --batch-mode + +RUN cd /tmp && \ + git clone https://github.com/google/protobuf.git && \ + cd protobuf && \ + ./autogen.sh && \ + ./configure && \ + make -j6 && \ + cd java && \ + $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO -P lite && \ + $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO && \ + cd ../javanano && \ + $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO + + # Define the default command. CMD ["bash"] diff --git a/tools/run_tests/tests.sh b/tools/run_tests/tests.sh index 4b2aef77..c28a5daa 100755 --- a/tools/run_tests/tests.sh +++ b/tools/run_tests/tests.sh @@ -104,6 +104,11 @@ use_java() { ;; esac + if [ "$TRAVIS" != "true" ]; then + MAVEN_LOCAL_REPOSITORY=/var/maven_local_repository + MVN="$MVN -e -X --offline -Dmaven.repo.local=$MAVEN_LOCAL_REPOSITORY" + fi; + which java java -version } From 2bda98f79ca9f43091d2033cf02c9732a0515a7a Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 3 Mar 2016 17:04:36 -0800 Subject: [PATCH 017/123] Properly report C++ build time. --- tools/jenkins/build_and_run_docker.sh | 14 ++++++++------ tools/jenkins/make_test_output.py | 4 ++-- tools/run_tests/jenkins.sh | 7 ++++++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/jenkins/build_and_run_docker.sh index 448b00c0..18b910a7 100755 --- a/tools/jenkins/build_and_run_docker.sh +++ b/tools/jenkins/build_and_run_docker.sh @@ -46,16 +46,18 @@ cd - # Use image name based on Dockerfile location checksum DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ ) -# Make sure docker image has been built. Should be instantaneous if so. -docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR - -# Choose random name for docker container -CONTAINER_NAME="build_and_run_docker_$(uuidgen)" - # Ensure existence of ccache directory CCACHE_DIR=/tmp/protobuf-ccache mkdir -p $CCACHE_DIR +# Make sure docker image has been built. Should be instantaneous if so. +docker build \ + -v $CCACHE_DIR:$CCACHE_DIR \ + -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR + +# Choose random name for docker container +CONTAINER_NAME="build_and_run_docker_$(uuidgen)" + # Run command inside docker docker run \ "$@" \ diff --git a/tools/jenkins/make_test_output.py b/tools/jenkins/make_test_output.py index 0ba5db3b..986d1979 100644 --- a/tools/jenkins/make_test_output.py +++ b/tools/jenkins/make_test_output.py @@ -58,8 +58,8 @@ def readtests(basedir): # up in the job log. tests["cpp"]["name"] = "cpp" - # TODO - tests["cpp"]["time"] = "0" + with open(basedir + '/logs/1/cpp/build_time', 'r') as f: + tests["cpp"]["time"] = f.read().strip() tests["cpp"]["failure"] = False ret = tests.values() diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index 32050d25..0bd9ffe5 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -34,7 +34,12 @@ mkdir -p $LOG_OUTPUT_DIR/1/cpp # $DIR/logs/1/java_jdk7/stderr CPP_STDOUT=$LOG_OUTPUT_DIR/1/cpp/stdout CPP_STDERR=$LOG_OUTPUT_DIR/1/cpp/stderr -$TEST_SCRIPT cpp > >(tee $CPP_STDOUT) 2> >(tee $CPP_STDERR >&2) + +# It's important that we get /usr/bin/time (which supports -f and -o) and not +# the bash builtin "time" which doesn't. +TIME_CMD="/usr/bin/time -f %e -o $LOG_OUTPUT_DIR/1/cpp/build_time" + +$TIME_CMD $TEST_SCRIPT cpp > >(tee $CPP_STDOUT) 2> >(tee $CPP_STDERR >&2) # Other tests are run in parallel. The overall run fails if any one of them # fails. From 7d793c167f51d5afff18e13b1dc1c0b060b3aae4 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 3 Mar 2016 17:08:37 -0800 Subject: [PATCH 018/123] Disable attempt to use ccache for docker build. --- tools/docker/Dockerfile | 23 ++++++++++------------- tools/jenkins/build_and_run_docker.sh | 8 +++----- tools/run_tests/jenkins.sh | 2 -- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index b7621f67..5136ee6b 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -62,6 +62,7 @@ RUN apt-get update && apt-get install -y \ libtool \ make \ parallel \ + time \ wget \ # -- For csharp -- mono-devel \ @@ -116,19 +117,6 @@ RUN /bin/bash -l -c "echo 'export PATH=/usr/local/rvm/bin:$PATH' >> ~/.bashrc" RUN /bin/bash -l -c "echo 'rvm --default use ruby-2.1' >> ~/.bashrc" RUN /bin/bash -l -c "gem install bundler --no-ri --no-rdoc" -################## -# Prepare ccache - -# We do this BEFORE the Java dependency step below, so the build of protoc -# can benefit from it. -RUN ln -s /usr/bin/ccache /usr/local/bin/gcc -RUN ln -s /usr/bin/ccache /usr/local/bin/g++ -RUN ln -s /usr/bin/ccache /usr/local/bin/cc -RUN ln -s /usr/bin/ccache /usr/local/bin/c++ -RUN ln -s /usr/bin/ccache /usr/local/bin/clang -RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ - - ################## # Java dependencies @@ -149,6 +137,15 @@ RUN cd /tmp && \ cd ../javanano && \ $MVN install dependency:go-offline -Dmaven.repo.local=$MAVEN_REPO +################## +# Prepare ccache + +RUN ln -s /usr/bin/ccache /usr/local/bin/gcc +RUN ln -s /usr/bin/ccache /usr/local/bin/g++ +RUN ln -s /usr/bin/ccache /usr/local/bin/cc +RUN ln -s /usr/bin/ccache /usr/local/bin/c++ +RUN ln -s /usr/bin/ccache /usr/local/bin/clang +RUN ln -s /usr/bin/ccache /usr/local/bin/clang++ # Define the default command. CMD ["bash"] diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/jenkins/build_and_run_docker.sh index 18b910a7..ad1075fa 100755 --- a/tools/jenkins/build_and_run_docker.sh +++ b/tools/jenkins/build_and_run_docker.sh @@ -46,15 +46,13 @@ cd - # Use image name based on Dockerfile location checksum DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ ) +# Make sure docker image has been built. Should be instantaneous if so. +docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR + # Ensure existence of ccache directory CCACHE_DIR=/tmp/protobuf-ccache mkdir -p $CCACHE_DIR -# Make sure docker image has been built. Should be instantaneous if so. -docker build \ - -v $CCACHE_DIR:$CCACHE_DIR \ - -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR - # Choose random name for docker container CONTAINER_NAME="build_and_run_docker_$(uuidgen)" diff --git a/tools/run_tests/jenkins.sh b/tools/run_tests/jenkins.sh index 0bd9ffe5..ea67345b 100755 --- a/tools/run_tests/jenkins.sh +++ b/tools/run_tests/jenkins.sh @@ -44,8 +44,6 @@ $TIME_CMD $TEST_SCRIPT cpp > >(tee $CPP_STDOUT) 2> >(tee $CPP_STDERR >&2) # Other tests are run in parallel. The overall run fails if any one of them # fails. -FAILED=false - parallel --results $LOG_OUTPUT_DIR --joblog $OUTPUT_DIR/joblog $TEST_SCRIPT ::: \ csharp \ java_jdk7 \ From 67c727cd411a339eb4233c84d9a1afadd8c20566 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 4 Mar 2016 14:21:18 -0800 Subject: [PATCH 019/123] Rearranged and commented files for running under Jenkins. --- .travis.yml | 2 +- jenkins/README.md | 6 ++ jenkins/build_and_run_docker.sh | 56 +++++++++++++ jenkins/buildcmds/README.md | 6 ++ jenkins/buildcmds/pull_request.sh | 15 ++++ {tools => jenkins}/docker/Dockerfile | 33 ++------ .../jenkins => jenkins}/make_test_output.py | 7 +- .../pull_request_in_docker.sh | 24 +++--- tools/run_tests/tests.sh => tests.sh | 15 ++-- tools/jenkins/build_and_run_docker.sh | 84 ------------------- tools/jenkins/pull_request.sh | 7 -- 11 files changed, 115 insertions(+), 140 deletions(-) create mode 100644 jenkins/README.md create mode 100755 jenkins/build_and_run_docker.sh create mode 100644 jenkins/buildcmds/README.md create mode 100755 jenkins/buildcmds/pull_request.sh rename {tools => jenkins}/docker/Dockerfile (70%) rename {tools/jenkins => jenkins}/make_test_output.py (91%) rename tools/run_tests/jenkins.sh => jenkins/pull_request_in_docker.sh (69%) rename tools/run_tests/tests.sh => tests.sh (97%) delete mode 100755 tools/jenkins/build_and_run_docker.sh delete mode 100755 tools/jenkins/pull_request.sh diff --git a/.travis.yml b/.travis.yml index 26b9dcaf..f8d2347c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ os: # The Objective C build needs Xcode 7.0 or later. osx_image: xcode7.2 script: - - ./tools/run_tests/tests.sh $CONFIG + - ./tests.sh $CONFIG env: - CONFIG=cpp - CONFIG=cpp_distcheck diff --git a/jenkins/README.md b/jenkins/README.md new file mode 100644 index 00000000..29f664f2 --- /dev/null +++ b/jenkins/README.md @@ -0,0 +1,6 @@ + +Jenkins Infrastructure +---------------------- + +The scripts in this directory serve as plumbing for running the protobuf +tests under Jenkins. diff --git a/jenkins/build_and_run_docker.sh b/jenkins/build_and_run_docker.sh new file mode 100755 index 00000000..abc6f055 --- /dev/null +++ b/jenkins/build_and_run_docker.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Builds docker image and runs a command under it. +# This is a generic script that is configured with the following variables: +# +# DOCKERFILE_DIR - Directory in which Dockerfile file is located. +# DOCKER_RUN_SCRIPT - Script to run under docker (relative to protobuf repo root) +# OUTPUT_DIR - Directory that will be copied from inside docker after finishing. +# $@ - Extra args to pass to docker run + + +set -ex + +cd $(dirname $0)/.. +git_root=$(pwd) +cd - + +# Use image name based on Dockerfile location checksum +DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ ) + +# Make sure docker image has been built. Should be instantaneous if so. +docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR + +# Ensure existence of ccache directory +CCACHE_DIR=/tmp/protobuf-ccache +mkdir -p $CCACHE_DIR + +# Choose random name for docker container +CONTAINER_NAME="build_and_run_docker_$(uuidgen)" + +# Run command inside docker +docker run \ + "$@" \ + -e CCACHE_DIR=$CCACHE_DIR \ + -e EXTERNAL_GIT_ROOT="/var/local/jenkins/protobuf" \ + -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \ + -v "$git_root:/var/local/jenkins/protobuf:ro" \ + -v $CCACHE_DIR:$CCACHE_DIR \ + -w /var/local/git/protobuf \ + --name=$CONTAINER_NAME \ + $DOCKER_IMAGE_NAME \ + bash -l "/var/local/jenkins/protobuf/$DOCKER_RUN_SCRIPT" || FAILED="true" + +# Copy output artifacts +if [ "$OUTPUT_DIR" != "" ] +then + docker cp "$CONTAINER_NAME:/var/local/git/protobuf/$OUTPUT_DIR" "$git_root" || FAILED="true" +fi + +# remove the container, possibly killing it first +docker rm -f $CONTAINER_NAME || true + +if [ "$FAILED" != "" ] +then + exit 1 +fi diff --git a/jenkins/buildcmds/README.md b/jenkins/buildcmds/README.md new file mode 100644 index 00000000..7a48f2d5 --- /dev/null +++ b/jenkins/buildcmds/README.md @@ -0,0 +1,6 @@ + +Jenkins Build Commands +---------------------- + +The scripts in this directory are designed to be top-level entry points for +Jenkins projects. diff --git a/jenkins/buildcmds/pull_request.sh b/jenkins/buildcmds/pull_request.sh new file mode 100755 index 00000000..01fda798 --- /dev/null +++ b/jenkins/buildcmds/pull_request.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# +# This is the top-level script we give to Jenkins as the entry point for +# running the "pull request" project: +# +# https://grpc-testing.appspot.com/view/Protocol%20Buffers/job/protobuf_pull_request/ +# +# This script selects a specific Dockerfile (for building a Docker image) and +# a script to run inside that image. Then we delegate to the general +# build_and_run_docker.sh script. + +export DOCKERFILE_DIR=jenkins/docker +export DOCKER_RUN_SCRIPT=jenkins/pull_request_in_docker.sh +export OUTPUT_DIR=testoutput +./jenkins/build_and_run_docker.sh diff --git a/tools/docker/Dockerfile b/jenkins/docker/Dockerfile similarity index 70% rename from tools/docker/Dockerfile rename to jenkins/docker/Dockerfile index 5136ee6b..8467aeff 100644 --- a/tools/docker/Dockerfile +++ b/jenkins/docker/Dockerfile @@ -1,31 +1,10 @@ -# Copyright 2015, Google Inc. -# All rights reserved. +# This Dockerfile specifies the recipe for creating an image for the tests +# to run in. # -# 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. +# We install as many test dependencies here as we can, because these setup +# steps can be cached. They do *not* run every time we run the build. +# The Docker image is only rebuilt when the Dockerfile (ie. this file) +# changes. # Base Dockerfile for gRPC dev images FROM debian:latest diff --git a/tools/jenkins/make_test_output.py b/jenkins/make_test_output.py similarity index 91% rename from tools/jenkins/make_test_output.py rename to jenkins/make_test_output.py index 986d1979..b1f2e2c0 100644 --- a/tools/jenkins/make_test_output.py +++ b/jenkins/make_test_output.py @@ -1,9 +1,9 @@ -"""Gather output from test runs and create an XML file in JUnit format. +"""Gathers output from test runs and create an XML file in JUnit format. The output files from the individual tests have been written in a directory structure like: - $DIR/joblog (--joblog from "parallel") + $DIR/joblog (output from "parallel --joblog joblog") $DIR/logs/1/cpp/stdout $DIR/logs/1/cpp/stderr $DIR/logs/1/csharp/stdout @@ -13,7 +13,8 @@ structure like: etc. This script bundles them into a single output XML file so Jenkins can show -detailed test results. +detailed test results. It runs as the last step before the Jenkins build +finishes. """ import os; diff --git a/tools/run_tests/jenkins.sh b/jenkins/pull_request_in_docker.sh similarity index 69% rename from tools/run_tests/jenkins.sh rename to jenkins/pull_request_in_docker.sh index ea67345b..887f97c5 100755 --- a/tools/run_tests/jenkins.sh +++ b/jenkins/pull_request_in_docker.sh @@ -1,22 +1,25 @@ #!/bin/bash +# +# This is the script that runs inside Docker, once the image has been built, +# to execute all tests for the "pull request" project. WORKSPACE_BASE=`pwd` MY_DIR="$(dirname "$0")" -TEST_SCRIPT=$MY_DIR/tests.sh +TEST_SCRIPT=$MY_DIR/../tests.sh BUILD_DIR=/tmp/protobuf -# Set value used in tests.sh. -PARALLELISM=-j8 - set -e # exit immediately on error set -x # display all commands +# The protobuf repository is mounted into our Docker image, but read-only. +# We clone into a directory inside Docker (this is faster than cp). rm -rf $BUILD_DIR mkdir -p $BUILD_DIR cd $BUILD_DIR git clone /var/local/jenkins/protobuf cd protobuf +# Set up the directory where our test output is going to go. OUTPUT_DIR=`mktemp -d` LOG_OUTPUT_DIR=$OUTPUT_DIR/logs mkdir -p $LOG_OUTPUT_DIR/1/cpp @@ -35,14 +38,14 @@ mkdir -p $LOG_OUTPUT_DIR/1/cpp CPP_STDOUT=$LOG_OUTPUT_DIR/1/cpp/stdout CPP_STDERR=$LOG_OUTPUT_DIR/1/cpp/stderr +# Time the C++ build, so we can put this info in the test output. # It's important that we get /usr/bin/time (which supports -f and -o) and not # the bash builtin "time" which doesn't. TIME_CMD="/usr/bin/time -f %e -o $LOG_OUTPUT_DIR/1/cpp/build_time" $TIME_CMD $TEST_SCRIPT cpp > >(tee $CPP_STDOUT) 2> >(tee $CPP_STDERR >&2) -# Other tests are run in parallel. The overall run fails if any one of them -# fails. +# Other tests are run in parallel. parallel --results $LOG_OUTPUT_DIR --joblog $OUTPUT_DIR/joblog $TEST_SCRIPT ::: \ csharp \ @@ -55,14 +58,15 @@ parallel --results $LOG_OUTPUT_DIR --joblog $OUTPUT_DIR/joblog $TEST_SCRIPT ::: ruby21 \ || true # Process test results even if tests fail. +cat $OUTPUT_DIR/joblog + # The directory that is copied from Docker back into the Jenkins workspace. COPY_FROM_DOCKER=/var/local/git/protobuf/testoutput mkdir -p $COPY_FROM_DOCKER TESTOUTPUT_XML_FILE=$COPY_FROM_DOCKER/testresults.xml -python $MY_DIR/../jenkins/make_test_output.py $OUTPUT_DIR > $TESTOUTPUT_XML_FILE +# Process all the output files from "parallel" and package them into a single +# .xml file with detailed, broken-down test output. +python $MY_DIR/make_test_output.py $OUTPUT_DIR > $TESTOUTPUT_XML_FILE ls -l $TESTOUTPUT_XML_FILE - -### disabled tests -# java_jdk6 \ diff --git a/tools/run_tests/tests.sh b/tests.sh similarity index 97% rename from tools/run_tests/tests.sh rename to tests.sh index c28a5daa..a4624c0c 100755 --- a/tools/run_tests/tests.sh +++ b/tests.sh @@ -1,4 +1,8 @@ #!/bin/bash +# +# Build and runs tests for the protobuf project. The tests as written here are +# used by both Jenkins and Travis, though some specialized logic is required to +# handle the differences between them. on_travis() { if [ "$TRAVIS" == "true" ]; then @@ -25,19 +29,19 @@ internal_build_cpp() { ./autogen.sh ./configure - make $PARALLELISM + make -j2 } build_cpp() { internal_build_cpp - make check $PARALLELISM + make check -j2 cd conformance && make test_cpp && cd .. } build_cpp_distcheck() { ./autogen.sh ./configure - make distcheck $PARALLELISM + make distcheck -j2 } build_csharp() { @@ -308,8 +312,6 @@ build_javascript() { cd js && npm install && npm test && cd .. } -[ -n "${PARALLELISM}" ] && PARALLELISM=-j8 - # Note: travis currently does not support testing more than one language so the # .travis.yml cheats and claims to only be cpp. If they add multiple language # support, this should probably get updated to install steps and/or @@ -320,9 +322,6 @@ build_javascript() { # -------- main -------- -# Set value used in tests.sh. -PARALLELISM=-j2 - if [ "$#" -ne 1 ]; then echo " Usage: $0 { cpp | diff --git a/tools/jenkins/build_and_run_docker.sh b/tools/jenkins/build_and_run_docker.sh deleted file mode 100755 index ad1075fa..00000000 --- a/tools/jenkins/build_and_run_docker.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/bin/bash -# Copyright 2016, Google Inc. -# All rights reserved. -# -# 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. -# -# Builds docker image and runs a command under it. -# You should never need to call this script on your own. - -set -ex - -cd $(dirname $0)/../.. -git_root=$(pwd) -cd - - -# Inputs -# DOCKERFILE_DIR - Directory in which Dockerfile file is located. -# DOCKER_RUN_SCRIPT - Script to run under docker (relative to protobuf repo root) -# OUTPUT_DIR - Directory that will be copied from inside docker after finishing. -# $@ - Extra args to pass to docker run - -# Use image name based on Dockerfile location checksum -DOCKER_IMAGE_NAME=$(basename $DOCKERFILE_DIR)_$(sha1sum $DOCKERFILE_DIR/Dockerfile | cut -f1 -d\ ) - -# Make sure docker image has been built. Should be instantaneous if so. -docker build -t $DOCKER_IMAGE_NAME $DOCKERFILE_DIR - -# Ensure existence of ccache directory -CCACHE_DIR=/tmp/protobuf-ccache -mkdir -p $CCACHE_DIR - -# Choose random name for docker container -CONTAINER_NAME="build_and_run_docker_$(uuidgen)" - -# Run command inside docker -docker run \ - "$@" \ - -e CCACHE_DIR=$CCACHE_DIR \ - -e EXTERNAL_GIT_ROOT="/var/local/jenkins/protobuf" \ - -e THIS_IS_REALLY_NEEDED='see https://github.com/docker/docker/issues/14203 for why docker is awful' \ - -v "$git_root:/var/local/jenkins/protobuf:ro" \ - -v $CCACHE_DIR:$CCACHE_DIR \ - -w /var/local/git/protobuf \ - --name=$CONTAINER_NAME \ - $DOCKER_IMAGE_NAME \ - bash -l "/var/local/jenkins/protobuf/$DOCKER_RUN_SCRIPT" || FAILED="true" - -# Copy output artifacts -if [ "$OUTPUT_DIR" != "" ] -then - docker cp "$CONTAINER_NAME:/var/local/git/protobuf/$OUTPUT_DIR" "$git_root" || FAILED="true" -fi - -# remove the container, possibly killing it first -docker rm -f $CONTAINER_NAME || true - -if [ "$FAILED" != "" ] -then - exit 1 -fi diff --git a/tools/jenkins/pull_request.sh b/tools/jenkins/pull_request.sh deleted file mode 100755 index 00538b9c..00000000 --- a/tools/jenkins/pull_request.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - - -export DOCKERFILE_DIR=tools/docker -export DOCKER_RUN_SCRIPT=tools/run_tests/jenkins.sh -export OUTPUT_DIR=testoutput -./tools/jenkins/build_and_run_docker.sh From f0c1a8637218a03a083901493c9b3acdb6e5db57 Mon Sep 17 00:00:00 2001 From: Pete Warden Date: Wed, 9 Mar 2016 13:03:52 -0800 Subject: [PATCH 020/123] Added iOS settings to Bazel build --- BUILD | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/BUILD b/BUILD index 8667cc48..39ba0d94 100644 --- a/BUILD +++ b/BUILD @@ -27,10 +27,22 @@ load( ) config_setting( - name = "ios_arm", + name = "ios_armv7", values = { "ios_cpu": "armv7", + }, +) + +config_setting( + name = "ios_armv7s", + values = { "ios_cpu": "armv7s", + }, +) + +config_setting( + name = "ios_arm64", + values = { "ios_cpu": "arm64", }, ) @@ -75,7 +87,9 @@ cc_library( ], hdrs = glob(["src/google/protobuf/**/*.h"]), copts = select({ - ":ios_arm": IOS_ARM_COPTS, + ":ios_armv7": IOS_ARM_COPTS, + ":ios_armv7s": IOS_ARM_COPTS, + ":ios_arm64": IOS_ARM_COPTS, "//conditions:default": COPTS, }), includes = ["src/"], @@ -143,7 +157,9 @@ cc_library( ], hdrs = glob(["src/**/*.h"]), copts = select({ - ":ios_arm": IOS_ARM_COPTS, + ":ios_armv7": IOS_ARM_COPTS, + ":ios_armv7s": IOS_ARM_COPTS, + ":ios_arm64": IOS_ARM_COPTS, "//conditions:default": COPTS, }), includes = ["src/"], From ea1886661e1ad607e7cac03f0e720c9ab337686e Mon Sep 17 00:00:00 2001 From: Steven Parkes Date: Thu, 25 Feb 2016 07:53:19 -0800 Subject: [PATCH 021/123] pass correct args to protoc for java wellknown protos when used as an external repository --- BUILD | 11 ++--------- protobuf.bzl | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/BUILD b/BUILD index 9cbddd5b..32fd669f 100644 --- a/BUILD +++ b/BUILD @@ -22,6 +22,7 @@ load( "protobuf", "cc_proto_library", "py_proto_library", + "internal_gen_well_known_protos_java", "internal_protobuf_py_tests", ) @@ -457,16 +458,8 @@ cc_test( ################################################################################ # Java support ################################################################################ -genrule( - name = "gen_well_known_protos_java", +internal_gen_well_known_protos_java( srcs = WELL_KNOWN_PROTOS, - outs = [ - "wellknown.srcjar", - ], - cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" + - " -Isrc $(SRCS) " + - " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar", - tools = [":protoc"], ) java_library( diff --git a/protobuf.bzl b/protobuf.bzl index 71eaba22..fbcae0b3 100644 --- a/protobuf.bzl +++ b/protobuf.bzl @@ -199,6 +199,31 @@ def cc_proto_library( includes=includes, **kargs) + +def internal_gen_well_known_protos_java(srcs): + """Bazel rule to generate the gen_well_known_protos_java genrule + + Args: + srcs: the well known protos + """ + root = Label("%s//protobuf_java" % (REPOSITORY_NAME)).workspace_root + if root == "": + include = " -Isrc " + else: + include = " -I%s/src " % root + native.genrule( + name = "gen_well_known_protos_java", + srcs = srcs, + outs = [ + "wellknown.srcjar", + ], + cmd = "$(location :protoc) --java_out=$(@D)/wellknown.jar" + + " %s $(SRCS) " % include + + " && mv $(@D)/wellknown.jar $(@D)/wellknown.srcjar", + tools = [":protoc"], + ) + + def py_proto_library( name, srcs=[], From 58f07644eab25f68973ecab4bdc43fc318c26131 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Fri, 11 Mar 2016 09:19:58 -0800 Subject: [PATCH 022/123] Fixing compilation error when building with emscripten. This change was previously done in //third_party in CL 108656107 but never made it to the open source project and was overwritten in an update. --- src/google/protobuf/map.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 37e19b0a..83199380 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -545,7 +545,9 @@ class Map { } #if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \ - !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID) + !defined(GOOGLE_PROTOBUF_OS_NACL) && \ + !defined(GOOGLE_PROTOBUF_OS_ANDROID) && \ + !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN) template void construct(NodeType* p, Args&&... args) { // Clang 3.6 doesn't compile static casting to void* directly. (Issue #1266) From a9244ca0dfea15b024df5a81b948d09907fa3970 Mon Sep 17 00:00:00 2001 From: Steven Parkes Date: Thu, 10 Mar 2016 17:50:25 -0800 Subject: [PATCH 023/123] add java/util support based on java/util/pom.xml --- BUILD | 13 +++++++++++++ WORKSPACE | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/BUILD b/BUILD index 32fd669f..cc699c8b 100644 --- a/BUILD +++ b/BUILD @@ -472,6 +472,19 @@ java_library( visibility = ["//visibility:public"], ) +java_library( + name = "protobuf_java_util", + srcs = glob([ + "java/util/src/main/java/com/google/protobuf/util/*.java", + ]), + deps = [ + "protobuf_java", + "//external:gson", + "//external:guava", + ], + visibility = ["//visibility:public"], +) + ################################################################################ # Python support ################################################################################ diff --git a/WORKSPACE b/WORKSPACE index 1e8e0a7f..065dc819 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -31,3 +31,23 @@ bind( name = "six", actual = "@six_archive//:six", ) + +maven_jar( + name = "guava_maven", + artifact = "com.google.guava:guava:18.0", +) + +bind( + name = "guava", + actual = "@guava_maven//jar", +) + +maven_jar( + name = "gson_maven", + artifact = "com.google.code.gson:gson:2.3", +) + +bind( + name = "gson", + actual = "@gson_maven//jar", +) From 79a23c435c4862d0c7af3c2740662104c77171dc Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Thu, 17 Mar 2016 10:04:21 -0400 Subject: [PATCH 024/123] Shrink ObjC overhead (generated size and some runtime sizes) NOTE: This is a binary breaking change as structure sizes have changed size and/or order. - Drop capturing field options, no other options were captured and other mobile targeted languages don't try to capture this sort information (saved 8 bytes for every field defined (in static data and again in field descriptor instance size data). - No longer generate/compile in the messages/enums in descriptor.proto. If developers need it, they should generate it and compile it in. Reduced the overhead of the core library. - Compute the number of has_bits actually needs to avoid over reserving. - Let the boolean single fields store via a has_bit to avoid storage, makes the common cases of the instance size smaller. - Reorder some flags and down size the enums to contain the bits needed. - Reorder the items in the structures to manually ensure they are are packed better (especially when generating 64bit code - 8 bytes for every field, 16 bytes for every extension, instance sizes 8 bytes also). - Split off the structure initialization so when the default is zero, the generated static storage doesn't need to reserve the space. This is batched at the message level, so all the fields for the message have to have zero defaults to get the saves. By definition all proto3 syntax files fall into this case but it also saves space for the proto2 that use the standard defaults. (saves 8 bytes of static data for every field that had a zero default) - Don't track the enums defined by a message. Nothing in the runtime needs it and it was just generation and runtime overhead. (saves 8 bytes per enum) - Ensure EnumDescriptors are started up threadsafe in all cases. - Split some of the Descriptor initialization into multiple methods so the generated code isn't padded with lots of zero/nil args. - Change how oneof info is feed to the runtime enabling us to generate less static data (8 bytes saved per oneof for 64bit). - Change how enum value informat is capture to pack the data and only decode it if it ends up being needed. Avoids padding issues causing bloat of 64bit, and removes the needs for extra pointers in addition to the data (just the data and one pointer now). --- Makefile.am | 4 +- Protobuf.podspec | 1 - generate_descriptor_proto.sh | 4 +- objectivec/DevTools/compile_testing_protos.sh | 65 +- objectivec/DevTools/full_mac_build.sh | 4 +- objectivec/GPBBootstrap.h | 9 +- objectivec/GPBDescriptor.h | 11 +- objectivec/GPBDescriptor.m | 360 ++- objectivec/GPBDescriptor_PackagePrivate.h | 189 +- objectivec/GPBMessage.m | 22 +- objectivec/GPBProtocolBuffers.m | 2 - objectivec/GPBRuntimeTypes.h | 4 +- objectivec/GPBUtilities.m | 64 +- objectivec/GPBUtilities_PackagePrivate.h | 2 +- .../project.pbxproj | 10 - .../project.pbxproj | 10 - objectivec/Tests/GPBARCUnittestProtos.m | 5 + objectivec/Tests/GPBDescriptorTests.m | 13 - objectivec/Tests/GPBUnittestProtos.m | 5 + ..._proto.sh => generate_well_known_types.sh} | 7 +- objectivec/google/protobuf/Any.pbobjc.h | 2 +- objectivec/google/protobuf/Any.pbobjc.m | 33 +- objectivec/google/protobuf/Api.pbobjc.h | 2 +- objectivec/google/protobuf/Api.pbobjc.m | 151 +- .../google/protobuf/Descriptor.pbobjc.h | 1279 -------- .../google/protobuf/Descriptor.pbobjc.m | 2594 ----------------- objectivec/google/protobuf/Duration.pbobjc.h | 2 +- objectivec/google/protobuf/Duration.pbobjc.m | 22 +- objectivec/google/protobuf/Empty.pbobjc.h | 2 +- objectivec/google/protobuf/Empty.pbobjc.m | 10 +- objectivec/google/protobuf/FieldMask.pbobjc.h | 2 +- objectivec/google/protobuf/FieldMask.pbobjc.m | 16 +- .../google/protobuf/SourceContext.pbobjc.h | 2 +- .../google/protobuf/SourceContext.pbobjc.m | 16 +- objectivec/google/protobuf/Struct.pbobjc.h | 2 +- objectivec/google/protobuf/Struct.pbobjc.m | 112 +- objectivec/google/protobuf/Timestamp.pbobjc.h | 2 +- objectivec/google/protobuf/Timestamp.pbobjc.m | 22 +- objectivec/google/protobuf/Type.pbobjc.h | 2 +- objectivec/google/protobuf/Type.pbobjc.m | 337 +-- objectivec/google/protobuf/Wrappers.pbobjc.h | 2 +- objectivec/google/protobuf/Wrappers.pbobjc.m | 145 +- .../compiler/objectivec/objectivec_enum.cc | 65 +- .../objectivec/objectivec_enum_field.cc | 17 +- .../objectivec/objectivec_enum_field.h | 2 - .../objectivec/objectivec_extension.cc | 10 +- .../compiler/objectivec/objectivec_field.cc | 144 +- .../compiler/objectivec/objectivec_field.h | 20 +- .../compiler/objectivec/objectivec_file.cc | 2 +- .../compiler/objectivec/objectivec_helpers.cc | 56 +- .../compiler/objectivec/objectivec_helpers.h | 4 + .../objectivec/objectivec_map_field.cc | 14 +- .../objectivec/objectivec_map_field.h | 1 - .../compiler/objectivec/objectivec_message.cc | 260 +- .../compiler/objectivec/objectivec_oneof.cc | 15 +- .../compiler/objectivec/objectivec_oneof.h | 4 +- .../objectivec/objectivec_primitive_field.cc | 26 + .../objectivec/objectivec_primitive_field.h | 5 + 58 files changed, 1024 insertions(+), 5169 deletions(-) rename objectivec/{generate_descriptors_proto.sh => generate_well_known_types.sh} (85%) delete mode 100644 objectivec/google/protobuf/Descriptor.pbobjc.h delete mode 100644 objectivec/google/protobuf/Descriptor.pbobjc.m diff --git a/Makefile.am b/Makefile.am index 064efdfb..4b5a44ff 100644 --- a/Makefile.am +++ b/Makefile.am @@ -381,13 +381,11 @@ objectivec_EXTRA_DIST= \ objectivec/DevTools/full_mac_build.sh \ objectivec/DevTools/pddm.py \ objectivec/DevTools/pddm_tests.py \ - objectivec/generate_descriptors_proto.sh \ + objectivec/generate_well_known_types.sh \ objectivec/google/protobuf/Any.pbobjc.h \ objectivec/google/protobuf/Any.pbobjc.m \ objectivec/google/protobuf/Api.pbobjc.h \ objectivec/google/protobuf/Api.pbobjc.m \ - objectivec/google/protobuf/Descriptor.pbobjc.h \ - objectivec/google/protobuf/Descriptor.pbobjc.m \ objectivec/google/protobuf/Duration.pbobjc.h \ objectivec/google/protobuf/Duration.pbobjc.m \ objectivec/google/protobuf/Empty.pbobjc.h \ diff --git a/Protobuf.podspec b/Protobuf.podspec index 02c83723..0bbd06df 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -17,7 +17,6 @@ Pod::Spec.new do |s| s.source_files = 'objectivec/*.{h,m}', 'objectivec/google/protobuf/Any.pbobjc.{h,m}', 'objectivec/google/protobuf/Api.pbobjc.{h,m}', - 'objectivec/google/protobuf/Descriptor.pbobjc.{h,m}', 'objectivec/google/protobuf/Duration.pbobjc.h', 'objectivec/google/protobuf/Empty.pbobjc.{h,m}', 'objectivec/google/protobuf/FieldMask.pbobjc.{h,m}', diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh index 81b8a0d6..1690d0da 100755 --- a/generate_descriptor_proto.sh +++ b/generate_descriptor_proto.sh @@ -92,9 +92,9 @@ do done cd .. -if test -x objectivec/generate_descriptors_proto.sh; then +if test -x objectivec/generate_well_known_types.sh; then echo "Generating messages for objc." - objectivec/generate_descriptors_proto.sh $@ + objectivec/generate_well_known_types.sh $@ fi if test -x csharp/generate_protos.sh; then diff --git a/objectivec/DevTools/compile_testing_protos.sh b/objectivec/DevTools/compile_testing_protos.sh index e9c5fe61..82953130 100755 --- a/objectivec/DevTools/compile_testing_protos.sh +++ b/objectivec/DevTools/compile_testing_protos.sh @@ -67,29 +67,36 @@ fi # Ensure the output dir exists mkdir -p "${OUTPUT_DIR}/google/protobuf" -CORE_PROTO_FILES=( \ - src/google/protobuf/unittest_arena.proto \ - src/google/protobuf/unittest_custom_options.proto \ - src/google/protobuf/unittest_enormous_descriptor.proto \ - src/google/protobuf/unittest_embed_optimize_for.proto \ - src/google/protobuf/unittest_empty.proto \ - src/google/protobuf/unittest_import.proto \ - src/google/protobuf/unittest_import_lite.proto \ - src/google/protobuf/unittest_lite.proto \ - src/google/protobuf/unittest_mset.proto \ - src/google/protobuf/unittest_mset_wire_format.proto \ - src/google/protobuf/unittest_no_arena.proto \ - src/google/protobuf/unittest_no_arena_import.proto \ - src/google/protobuf/unittest_no_generic_services.proto \ - src/google/protobuf/unittest_optimize_for.proto \ - src/google/protobuf/unittest.proto \ - src/google/protobuf/unittest_import_public.proto \ - src/google/protobuf/unittest_import_public_lite.proto \ - src/google/protobuf/unittest_drop_unknown_fields.proto \ - src/google/protobuf/unittest_preserve_unknown_enum.proto \ - src/google/protobuf/map_lite_unittest.proto \ - src/google/protobuf/map_proto2_unittest.proto \ - src/google/protobuf/map_unittest.proto \ +CORE_PROTO_FILES=( + src/google/protobuf/unittest_arena.proto + src/google/protobuf/unittest_custom_options.proto + src/google/protobuf/unittest_enormous_descriptor.proto + src/google/protobuf/unittest_embed_optimize_for.proto + src/google/protobuf/unittest_empty.proto + src/google/protobuf/unittest_import.proto + src/google/protobuf/unittest_import_lite.proto + src/google/protobuf/unittest_lite.proto + src/google/protobuf/unittest_mset.proto + src/google/protobuf/unittest_mset_wire_format.proto + src/google/protobuf/unittest_no_arena.proto + src/google/protobuf/unittest_no_arena_import.proto + src/google/protobuf/unittest_no_generic_services.proto + src/google/protobuf/unittest_optimize_for.proto + src/google/protobuf/unittest.proto + src/google/protobuf/unittest_import_public.proto + src/google/protobuf/unittest_import_public_lite.proto + src/google/protobuf/unittest_drop_unknown_fields.proto + src/google/protobuf/unittest_preserve_unknown_enum.proto + src/google/protobuf/map_lite_unittest.proto + src/google/protobuf/map_proto2_unittest.proto + src/google/protobuf/map_unittest.proto +) + +# The unittest_custom_options.proto extends the messages in descriptor.proto +# so we build it in to test extending in general. The library doesn't provide +# a descriptor as it doesn't use the classes/enums. +CORE_PROTO_FILES+=( + src/google/protobuf/descriptor.proto ) compile_proto() { @@ -104,12 +111,12 @@ for a_proto in "${CORE_PROTO_FILES[@]}" ; do compile_proto "${a_proto}" done -OBJC_PROTO_FILES=( \ - objectivec/Tests/unittest_cycle.proto \ - objectivec/Tests/unittest_runtime_proto2.proto \ - objectivec/Tests/unittest_runtime_proto3.proto \ - objectivec/Tests/unittest_objc.proto \ - objectivec/Tests/unittest_objc_startup.proto \ +OBJC_PROTO_FILES=( + objectivec/Tests/unittest_cycle.proto + objectivec/Tests/unittest_runtime_proto2.proto + objectivec/Tests/unittest_runtime_proto3.proto + objectivec/Tests/unittest_objc.proto + objectivec/Tests/unittest_objc_startup.proto ) for a_proto in "${OBJC_PROTO_FILES[@]}" ; do diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh index c8681e26..b382779e 100755 --- a/objectivec/DevTools/full_mac_build.sh +++ b/objectivec/DevTools/full_mac_build.sh @@ -190,7 +190,7 @@ header "Ensuring the ObjC descriptors are current." readonly NewestInput=$(find \ src/google/protobuf/*.proto \ src/.libs src/*.la src/protoc \ - objectivec/generate_descriptors_proto.sh \ + objectivec/generate_well_known_types.sh \ -type f -print0 \ | xargs -0 stat -f "%m %N" \ | sort -n | tail -n1 | cut -f2- -d" ") @@ -203,7 +203,7 @@ readonly OldestOutput=$(find \ # If the newest input is newer than the oldest output, regenerate. if [[ "${NewestInput}" -nt "${OldestOutput}" ]] ; then echo ">> Newest input is newer than oldest output, regenerating." - objectivec/generate_descriptors_proto.sh -j "${NUM_MAKE_JOBS}" + objectivec/generate_well_known_types.sh -j "${NUM_MAKE_JOBS}" else echo ">> Newest input is older than oldest output, no need to regenerating." fi diff --git a/objectivec/GPBBootstrap.h b/objectivec/GPBBootstrap.h index c49c7e20..ffefa770 100644 --- a/objectivec/GPBBootstrap.h +++ b/objectivec/GPBBootstrap.h @@ -37,13 +37,6 @@ #define GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS 0 #endif -// Most uses of protocol buffers don't need field options, by default the -// static data will be compiled out, define this to 1 to include it. The only -// time you need this is if you are doing introspection of the protocol buffers. -#ifndef GPBOBJC_INCLUDE_FIELD_OPTIONS -#define GPBOBJC_INCLUDE_FIELD_OPTIONS 0 -#endif - // Used in the generated code to give sizes to enums. int32_t was chosen based // on the fact that Protocol Buffers enums are limited to this range. #if !__has_feature(objc_fixed_enum) @@ -89,4 +82,4 @@ // generated Objective C sources. In general we don't want to change the // runtime interfaces (or this version) as it means everything has to be // regenerated. -#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30000 +#define GOOGLE_PROTOBUF_OBJC_GEN_VERSION 30001 diff --git a/objectivec/GPBDescriptor.h b/objectivec/GPBDescriptor.h index 8d8e9754..a6eff0fb 100644 --- a/objectivec/GPBDescriptor.h +++ b/objectivec/GPBDescriptor.h @@ -34,19 +34,18 @@ @class GPBEnumDescriptor; @class GPBFieldDescriptor; -@class GPBFieldOptions; @class GPBFileDescriptor; @class GPBOneofDescriptor; NS_ASSUME_NONNULL_BEGIN -typedef NS_ENUM(NSInteger, GPBFileSyntax) { +typedef NS_ENUM(uint8_t, GPBFileSyntax) { GPBFileSyntaxUnknown = 0, GPBFileSyntaxProto2 = 2, GPBFileSyntaxProto3 = 3, }; -typedef NS_ENUM(NSInteger, GPBFieldType) { +typedef NS_ENUM(uint8_t, GPBFieldType) { GPBFieldTypeSingle, // optional/required GPBFieldTypeRepeated, // repeated GPBFieldTypeMap, // map @@ -57,9 +56,8 @@ typedef NS_ENUM(NSInteger, GPBFieldType) { @property(nonatomic, readonly, copy) NSString *name; @property(nonatomic, readonly, strong, nullable) NSArray *fields; @property(nonatomic, readonly, strong, nullable) NSArray *oneofs; -@property(nonatomic, readonly, strong, nullable) NSArray *enums; @property(nonatomic, readonly, nullable) const GPBExtensionRange *extensionRanges; -@property(nonatomic, readonly) NSUInteger extensionRangesCount; +@property(nonatomic, readonly) uint32_t extensionRangesCount; @property(nonatomic, readonly, assign) GPBFileDescriptor *file; @property(nonatomic, readonly, getter=isWireFormat) BOOL wireFormat; @@ -68,7 +66,6 @@ typedef NS_ENUM(NSInteger, GPBFieldType) { - (nullable GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber; - (nullable GPBFieldDescriptor *)fieldWithName:(NSString *)name; - (nullable GPBOneofDescriptor *)oneofWithName:(NSString *)name; -- (nullable GPBEnumDescriptor *)enumWithName:(NSString *)name; @end @@ -103,8 +100,6 @@ typedef NS_ENUM(NSInteger, GPBFieldType) { @property(nonatomic, readonly, assign, nullable) GPBOneofDescriptor *containingOneof; -@property(nonatomic, readonly, nullable) GPBFieldOptions *fieldOptions; - // Message properties @property(nonatomic, readonly, assign, nullable) Class msgClass; diff --git a/objectivec/GPBDescriptor.m b/objectivec/GPBDescriptor.m index bae9187e..2709737c 100644 --- a/objectivec/GPBDescriptor.m +++ b/objectivec/GPBDescriptor.m @@ -35,7 +35,6 @@ #import "GPBUtilities_PackagePrivate.h" #import "GPBWireFormat.h" #import "GPBMessage_PackagePrivate.h" -#import "google/protobuf/Descriptor.pbobjc.h" // The address of this variable is used as a key for obj_getAssociatedObject. static const char kTextFormatExtraValueKey = 0; @@ -92,7 +91,6 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, @implementation GPBDescriptor { Class messageClass_; - NSArray *enums_; GPBFileDescriptor *file_; BOOL wireFormat_; } @@ -100,7 +98,6 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, @synthesize messageClass = messageClass_; @synthesize fields = fields_; @synthesize oneofs = oneofs_; -@synthesize enums = enums_; @synthesize extensionRanges = extensionRanges_; @synthesize extensionRangesCount = extensionRangesCount_; @synthesize file = file_; @@ -110,130 +107,58 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, allocDescriptorForClass:(Class)messageClass rootClass:(Class)rootClass file:(GPBFileDescriptor *)file - fields:(GPBMessageFieldDescription *)fieldDescriptions - fieldCount:(NSUInteger)fieldCount - oneofs:(GPBMessageOneofDescription *)oneofDescriptions - oneofCount:(NSUInteger)oneofCount - enums:(GPBMessageEnumDescription *)enumDescriptions - enumCount:(NSUInteger)enumCount - ranges:(const GPBExtensionRange *)ranges - rangeCount:(NSUInteger)rangeCount - storageSize:(size_t)storageSize - wireFormat:(BOOL)wireFormat { + fields:(void *)fieldDescriptions + fieldCount:(uint32_t)fieldCount + storageSize:(uint32_t)storageSize + flags:(GPBDescriptorInitializationFlags)flags { + // The rootClass is no longer used, but it is passed in to ensure it + // was started up during initialization also. + (void)rootClass; NSMutableArray *fields = nil; - NSMutableArray *oneofs = nil; - NSMutableArray *enums = nil; - NSMutableArray *extensionRanges = nil; GPBFileSyntax syntax = file.syntax; - for (NSUInteger i = 0; i < fieldCount; ++i) { + BOOL fieldsIncludeDefault = + (flags & GPBDescriptorInitializationFlag_FieldsWithDefault) != 0; + + void *desc; + for (uint32_t i = 0; i < fieldCount; ++i) { if (fields == nil) { fields = [[NSMutableArray alloc] initWithCapacity:fieldCount]; } - GPBFieldDescriptor *fieldDescriptor = [[GPBFieldDescriptor alloc] - initWithFieldDescription:&fieldDescriptions[i] - rootClass:rootClass - syntax:syntax]; + // Need correctly typed pointer for array indexing below to work. + if (fieldsIncludeDefault) { + GPBMessageFieldDescriptionWithDefault *fieldDescWithDefault = fieldDescriptions; + desc = &(fieldDescWithDefault[i]); + } else { + GPBMessageFieldDescription *fieldDesc = fieldDescriptions; + desc = &(fieldDesc[i]); + } + GPBFieldDescriptor *fieldDescriptor = + [[GPBFieldDescriptor alloc] initWithFieldDescription:desc + includesDefault:fieldsIncludeDefault + syntax:syntax]; [fields addObject:fieldDescriptor]; [fieldDescriptor release]; } - for (NSUInteger i = 0; i < oneofCount; ++i) { - if (oneofs == nil) { - oneofs = [[NSMutableArray alloc] initWithCapacity:oneofCount]; - } - GPBMessageOneofDescription *oneofDescription = &oneofDescriptions[i]; - NSArray *fieldsForOneof = - NewFieldsArrayForHasIndex(oneofDescription->index, fields); - GPBOneofDescriptor *oneofDescriptor = - [[GPBOneofDescriptor alloc] initWithOneofDescription:oneofDescription - fields:fieldsForOneof]; - [oneofs addObject:oneofDescriptor]; - [oneofDescriptor release]; - [fieldsForOneof release]; - } - for (NSUInteger i = 0; i < enumCount; ++i) { - if (enums == nil) { - enums = [[NSMutableArray alloc] initWithCapacity:enumCount]; - } - GPBEnumDescriptor *enumDescriptor = - enumDescriptions[i].enumDescriptorFunc(); - [enums addObject:enumDescriptor]; - } + BOOL wireFormat = (flags & GPBDescriptorInitializationFlag_WireFormat) != 0; GPBDescriptor *descriptor = [[self alloc] initWithClass:messageClass file:file fields:fields - oneofs:oneofs - enums:enums - extensionRanges:ranges - extensionRangesCount:rangeCount storageSize:storageSize wireFormat:wireFormat]; [fields release]; - [oneofs release]; - [enums release]; - [extensionRanges release]; - return descriptor; -} - -+ (instancetype) - allocDescriptorForClass:(Class)messageClass - rootClass:(Class)rootClass - file:(GPBFileDescriptor *)file - fields:(GPBMessageFieldDescription *)fieldDescriptions - fieldCount:(NSUInteger)fieldCount - oneofs:(GPBMessageOneofDescription *)oneofDescriptions - oneofCount:(NSUInteger)oneofCount - enums:(GPBMessageEnumDescription *)enumDescriptions - enumCount:(NSUInteger)enumCount - ranges:(const GPBExtensionRange *)ranges - rangeCount:(NSUInteger)rangeCount - storageSize:(size_t)storageSize - wireFormat:(BOOL)wireFormat - extraTextFormatInfo:(const char *)extraTextFormatInfo { - GPBDescriptor *descriptor = [self allocDescriptorForClass:messageClass - rootClass:rootClass - file:file - fields:fieldDescriptions - fieldCount:fieldCount - oneofs:oneofDescriptions - oneofCount:oneofCount - enums:enumDescriptions - enumCount:enumCount - ranges:ranges - rangeCount:rangeCount - storageSize:storageSize - wireFormat:wireFormat]; - // Extra info is a compile time option, so skip the work if not needed. - if (extraTextFormatInfo) { - NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo]; - for (GPBFieldDescriptor *fieldDescriptor in descriptor->fields_) { - if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) { - objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey, - extraInfoValue, - OBJC_ASSOCIATION_RETAIN_NONATOMIC); - } - } - } return descriptor; } - (instancetype)initWithClass:(Class)messageClass file:(GPBFileDescriptor *)file fields:(NSArray *)fields - oneofs:(NSArray *)oneofs - enums:(NSArray *)enums - extensionRanges:(const GPBExtensionRange *)extensionRanges - extensionRangesCount:(NSUInteger)extensionRangesCount - storageSize:(size_t)storageSize + storageSize:(uint32_t)storageSize wireFormat:(BOOL)wireFormat { if ((self = [super init])) { messageClass_ = messageClass; file_ = file; fields_ = [fields retain]; - oneofs_ = [oneofs retain]; - enums_ = [enums retain]; - extensionRanges_ = extensionRanges; - extensionRangesCount_ = extensionRangesCount; storageSize_ = storageSize; wireFormat_ = wireFormat; } @@ -243,10 +168,47 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, - (void)dealloc { [fields_ release]; [oneofs_ release]; - [enums_ release]; [super dealloc]; } +- (void)setupOneofs:(const char **)oneofNames + count:(uint32_t)count + firstHasIndex:(int32_t)firstHasIndex { + NSCAssert(firstHasIndex < 0, @"Should always be <0"); + NSMutableArray *oneofs = [[NSMutableArray alloc] initWithCapacity:count]; + for (uint32_t i = 0, hasIndex = firstHasIndex; i < count; ++i, --hasIndex) { + const char *name = oneofNames[i]; + NSArray *fieldsForOneof = NewFieldsArrayForHasIndex(hasIndex, fields_); + NSCAssert(fieldsForOneof.count > 0, + @"No fields for this oneof? (%s:%d)", name, hasIndex); + GPBOneofDescriptor *oneofDescriptor = + [[GPBOneofDescriptor alloc] initWithName:name fields:fieldsForOneof]; + [oneofs addObject:oneofDescriptor]; + [oneofDescriptor release]; + [fieldsForOneof release]; + } + oneofs_ = oneofs; +} + +- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo { + // Extra info is a compile time option, so skip the work if not needed. + if (extraTextFormatInfo) { + NSValue *extraInfoValue = [NSValue valueWithPointer:extraTextFormatInfo]; + for (GPBFieldDescriptor *fieldDescriptor in fields_) { + if (fieldDescriptor->description_->flags & GPBFieldTextFormatNameCustom) { + objc_setAssociatedObject(fieldDescriptor, &kTextFormatExtraValueKey, + extraInfoValue, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + } + } + } +} + +- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count { + extensionRanges_ = ranges; + extensionRangesCount_ = count; +} + - (NSString *)name { return NSStringFromClass(messageClass_); } @@ -283,15 +245,6 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, return nil; } -- (GPBEnumDescriptor *)enumWithName:(NSString *)name { - for (GPBEnumDescriptor *descriptor in enums_) { - if ([descriptor.name isEqual:name]) { - return descriptor; - } - } - return nil; -} - @end @implementation GPBFileDescriptor { @@ -318,19 +271,16 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, @synthesize fields = fields_; -- (instancetype)initWithOneofDescription: - (GPBMessageOneofDescription *)oneofDescription - fields:(NSArray *)fields { +- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields { self = [super init]; if (self) { - NSAssert(oneofDescription->index < 0, @"Should always be <0"); - oneofDescription_ = oneofDescription; + name_ = name; fields_ = [fields retain]; for (GPBFieldDescriptor *fieldDesc in fields) { fieldDesc->containingOneof_ = self; } - caseSel_ = SelFromStrings(NULL, oneofDescription->name, "OneOfCase", NO); + caseSel_ = SelFromStrings(NULL, name, "OneOfCase", NO); } return self; } @@ -341,7 +291,7 @@ static NSArray *NewFieldsArrayForHasIndex(int hasIndex, } - (NSString *)name { - return @(oneofDescription_->name); + return @(name_); } - (GPBFieldDescriptor *)fieldWithNumber:(uint32_t)fieldNumber { @@ -389,7 +339,6 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { @implementation GPBFieldDescriptor { GPBGenericValue defaultValue_; - GPBFieldOptions *fieldOptions_; // Message ivars Class msgClass_; @@ -403,7 +352,6 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { } enumHandling_; } -@synthesize fieldOptions = fieldOptions_; @synthesize msgClass = msgClass_; @synthesize containingOneof = containingOneof_; @@ -417,16 +365,21 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { return self; } -- (instancetype)initWithFieldDescription: - (GPBMessageFieldDescription *)description - rootClass:(Class)rootClass +- (instancetype)initWithFieldDescription:(void *)description + includesDefault:(BOOL)includesDefault syntax:(GPBFileSyntax)syntax { if ((self = [super init])) { - description_ = description; - getSel_ = sel_getUid(description->name); - setSel_ = SelFromStrings("set", description->name, NULL, YES); + GPBMessageFieldDescription *coreDesc; + if (includesDefault) { + coreDesc = &(((GPBMessageFieldDescriptionWithDefault *)description)->core); + } else { + coreDesc = description; + } + description_ = coreDesc; + getSel_ = sel_getUid(coreDesc->name); + setSel_ = SelFromStrings("set", coreDesc->name, NULL, YES); - GPBDataType dataType = description->dataType; + GPBDataType dataType = coreDesc->dataType; BOOL isMessage = GPBDataTypeIsMessage(dataType); BOOL isMapOrArray = GPBFieldIsMapOrArray(self); @@ -434,39 +387,39 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { // map<>/repeated fields get a *Count property (inplace of a has*) to // support checking if there are any entries without triggering // autocreation. - hasOrCountSel_ = SelFromStrings(NULL, description->name, "_Count", NO); + hasOrCountSel_ = SelFromStrings(NULL, coreDesc->name, "_Count", NO); } else { // If there is a positive hasIndex, then: // - All fields types for proto2 messages get has* selectors. // - Only message fields for proto3 messages get has* selectors. // Note: the positive check is to handle oneOfs, we can't check // containingOneof_ because it isn't set until after initialization. - if ((description->hasIndex >= 0) && - (description->hasIndex != GPBNoHasBit) && + if ((coreDesc->hasIndex >= 0) && + (coreDesc->hasIndex != GPBNoHasBit) && ((syntax != GPBFileSyntaxProto3) || isMessage)) { - hasOrCountSel_ = SelFromStrings("has", description->name, NULL, NO); - setHasSel_ = SelFromStrings("setHas", description->name, NULL, YES); + hasOrCountSel_ = SelFromStrings("has", coreDesc->name, NULL, NO); + setHasSel_ = SelFromStrings("setHas", coreDesc->name, NULL, YES); } } // Extra type specific data. if (isMessage) { - const char *className = description->dataTypeSpecific.className; + const char *className = coreDesc->dataTypeSpecific.className; msgClass_ = objc_getClass(className); NSAssert(msgClass_, @"Class %s not defined", className); } else if (dataType == GPBDataTypeEnum) { - if ((description_->flags & GPBFieldHasEnumDescriptor) != 0) { + if ((coreDesc->flags & GPBFieldHasEnumDescriptor) != 0) { enumHandling_.enumDescriptor_ = - description->dataTypeSpecific.enumDescFunc(); + coreDesc->dataTypeSpecific.enumDescFunc(); } else { enumHandling_.enumVerifier_ = - description->dataTypeSpecific.enumVerifier; + coreDesc->dataTypeSpecific.enumVerifier; } } - // Non map<>/repeated fields can have defaults. - if (!isMapOrArray) { - defaultValue_ = description->defaultValue; + // Non map<>/repeated fields can have defaults in proto2 syntax. + if (!isMapOrArray && includesDefault) { + defaultValue_ = ((GPBMessageFieldDescriptionWithDefault *)description)->defaultValue; if (dataType == GPBDataTypeBytes) { // Data stored as a length prefixed (network byte order) c-string in // descriptor structure. @@ -480,24 +433,6 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { } } } - - // FieldOptions stored as a length prefixed (network byte order) c-escaped - // string in descriptor records. - if (description->fieldOptions) { - uint8_t *optionsBytes = (uint8_t *)description->fieldOptions; - uint32_t optionsLength = *((uint32_t *)optionsBytes); - optionsLength = ntohl(optionsLength); - if (optionsLength > 0) { - optionsBytes += sizeof(optionsLength); - NSData *optionsData = [NSData dataWithBytesNoCopy:optionsBytes - length:optionsLength - freeWhenDone:NO]; - GPBExtensionRegistry *registry = [rootClass extensionRegistry]; - fieldOptions_ = [[GPBFieldOptions parseFromData:optionsData - extensionRegistry:registry - error:NULL] retain]; - } - } } return self; } @@ -666,7 +601,7 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { } else { // Undo the CamelCase. NSMutableString *result = [NSMutableString stringWithCapacity:len]; - for (NSUInteger i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { unichar c = [name characterAtIndex:i]; if (c >= 'A' && c <= 'Z') { if (i > 0) { @@ -686,10 +621,16 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { @implementation GPBEnumDescriptor { NSString *name_; - GPBMessageEnumValueDescription *valueDescriptions_; - NSUInteger valueDescriptionsCount_; + // valueNames_ is a single c string with all of the value names appended + // together, each null terminated. -calcValueNameOffsets fills in + // nameOffsets_ with the offsets to allow quicker access to the individual + // names. + const char *valueNames_; + const int32_t *values_; GPBEnumValidationFunc enumVerifier_; const uint8_t *extraTextFormatInfo_; + uint32_t *nameOffsets_; + uint32_t valueCount_; } @synthesize name = name_; @@ -697,26 +638,30 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { + (instancetype) allocDescriptorForName:(NSString *)name - values:(GPBMessageEnumValueDescription *)valueDescriptions - valueCount:(NSUInteger)valueCount + valueNames:(const char *)valueNames + values:(const int32_t *)values + count:(uint32_t)valueCount enumVerifier:(GPBEnumValidationFunc)enumVerifier { GPBEnumDescriptor *descriptor = [[self alloc] initWithName:name - values:valueDescriptions - valueCount:valueCount + valueNames:valueNames + values:values + count:valueCount enumVerifier:enumVerifier]; return descriptor; } + (instancetype) allocDescriptorForName:(NSString *)name - values:(GPBMessageEnumValueDescription *)valueDescriptions - valueCount:(NSUInteger)valueCount + valueNames:(const char *)valueNames + values:(const int32_t *)values + count:(uint32_t)valueCount enumVerifier:(GPBEnumValidationFunc)enumVerifier extraTextFormatInfo:(const char *)extraTextFormatInfo { // Call the common case. GPBEnumDescriptor *descriptor = [self allocDescriptorForName:name - values:valueDescriptions - valueCount:valueCount + valueNames:valueNames + values:values + count:valueCount enumVerifier:enumVerifier]; // Set the extra info. descriptor->extraTextFormatInfo_ = (const uint8_t *)extraTextFormatInfo; @@ -724,24 +669,49 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { } - (instancetype)initWithName:(NSString *)name - values:(GPBMessageEnumValueDescription *)valueDescriptions - valueCount:(NSUInteger)valueCount + valueNames:(const char *)valueNames + values:(const int32_t *)values + count:(uint32_t)valueCount enumVerifier:(GPBEnumValidationFunc)enumVerifier { if ((self = [super init])) { name_ = [name copy]; - valueDescriptions_ = valueDescriptions; - valueDescriptionsCount_ = valueCount; + valueNames_ = valueNames; + values_ = values; + valueCount_ = valueCount; enumVerifier_ = enumVerifier; } return self; } +- (void)dealloc { + [name_ release]; + if (nameOffsets_) free(nameOffsets_); + [super dealloc]; +} + +- (void)calcValueNameOffsets { + @synchronized(self) { + if (nameOffsets_ != NULL) { + return; + } + uint32_t *offsets = malloc(valueCount_ * sizeof(uint32_t)); + const char *scan = valueNames_; + for (uint32_t i = 0; i < valueCount_; ++i) { + offsets[i] = (uint32_t)(scan - valueNames_); + while (*scan != '\0') ++scan; + ++scan; // Step over the null. + } + nameOffsets_ = offsets; + } +} + - (NSString *)enumNameForValue:(int32_t)number { - for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) { - GPBMessageEnumValueDescription *scan = &valueDescriptions_[i]; - if ((scan->number == number) && (scan->name != NULL)) { - NSString *fullName = - [NSString stringWithFormat:@"%@_%s", name_, scan->name]; + if (nameOffsets_ == NULL) [self calcValueNameOffsets]; + + for (uint32_t i = 0; i < valueCount_; ++i) { + if (values_[i] == number) { + const char *valueName = valueNames_ + nameOffsets_[i]; + NSString *fullName = [NSString stringWithFormat:@"%@_%s", name_, valueName]; return fullName; } } @@ -760,12 +730,14 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { const char *nameAsCStr = [name UTF8String]; nameAsCStr += prefixLen; + if (nameOffsets_ == NULL) [self calcValueNameOffsets]; + // Find it. - for (NSUInteger i = 0; i < valueDescriptionsCount_; ++i) { - GPBMessageEnumValueDescription *scan = &valueDescriptions_[i]; - if ((scan->name != NULL) && (strcmp(nameAsCStr, scan->name) == 0)) { + for (uint32_t i = 0; i < valueCount_; ++i) { + const char *valueName = valueNames_ + nameOffsets_[i]; + if (strcmp(nameAsCStr, valueName) == 0) { if (outValue) { - *outValue = scan->number; + *outValue = values_[i]; } return YES; } @@ -773,34 +745,28 @@ uint32_t GPBFieldAlternateTag(GPBFieldDescriptor *self) { return NO; } -- (void)dealloc { - [name_ release]; - [super dealloc]; -} - - (NSString *)textFormatNameForValue:(int32_t)number { + if (nameOffsets_ == NULL) [self calcValueNameOffsets]; + // Find the EnumValue descriptor and its index. - GPBMessageEnumValueDescription *valueDescriptor = NULL; - NSUInteger valueDescriptorIndex; - for (valueDescriptorIndex = 0; valueDescriptorIndex < valueDescriptionsCount_; + BOOL foundIt = NO; + uint32_t valueDescriptorIndex; + for (valueDescriptorIndex = 0; valueDescriptorIndex < valueCount_; ++valueDescriptorIndex) { - GPBMessageEnumValueDescription *scan = - &valueDescriptions_[valueDescriptorIndex]; - if (scan->number == number) { - valueDescriptor = scan; + if (values_[valueDescriptorIndex] == number) { + foundIt = YES; break; } } - // If we didn't find it, or names were disable at proto compile time, nothing - // we can do. - if (!valueDescriptor || !valueDescriptor->name) { + if (!foundIt) { return nil; } NSString *result = nil; // Naming adds an underscore between enum name and value name, skip that also. - NSString *shortName = @(valueDescriptor->name); + const char *valueName = valueNames_ + nameOffsets_[valueDescriptorIndex]; + NSString *shortName = @(valueName); // See if it is in the map of special format handling. if (extraTextFormatInfo_) { diff --git a/objectivec/GPBDescriptor_PackagePrivate.h b/objectivec/GPBDescriptor_PackagePrivate.h index 7987d928..e3d0a80f 100644 --- a/objectivec/GPBDescriptor_PackagePrivate.h +++ b/objectivec/GPBDescriptor_PackagePrivate.h @@ -36,7 +36,7 @@ #import "GPBWireFormat.h" // Describes attributes of the field. -typedef NS_OPTIONS(uint32_t, GPBFieldFlags) { +typedef NS_OPTIONS(uint16_t, GPBFieldFlags) { // These map to standard protobuf concepts. GPBFieldRequired = 1 << 0, GPBFieldRepeated = 1 << 1, @@ -44,6 +44,12 @@ typedef NS_OPTIONS(uint32_t, GPBFieldFlags) { GPBFieldOptional = 1 << 3, GPBFieldHasDefaultValue = 1 << 4, + // Indicates the field needs custom handling for the TextFormat name, if not + // set, the name can be derived from the ObjC name. + GPBFieldTextFormatNameCustom = 1 << 6, + // Indicates the field has an enum descriptor. + GPBFieldHasEnumDescriptor = 1 << 7, + // These are not standard protobuf concepts, they are specific to the // Objective C runtime. @@ -62,35 +68,16 @@ typedef NS_OPTIONS(uint32_t, GPBFieldFlags) { GPBFieldMapKeySFixed64 = 10 << 8, GPBFieldMapKeyBool = 11 << 8, GPBFieldMapKeyString = 12 << 8, - - // Indicates the field needs custom handling for the TextFormat name, if not - // set, the name can be derived from the ObjC name. - GPBFieldTextFormatNameCustom = 1 << 16, - // Indicates the field has an enum descriptor. - GPBFieldHasEnumDescriptor = 1 << 17, }; +// NOTE: The structures defined here have their members ordered to minimize +// their size. This directly impacts the size of apps since these exist per +// field/extension. + // Describes a single field in a protobuf as it is represented as an ivar. typedef struct GPBMessageFieldDescription { // Name of ivar. const char *name; - // The field number for the ivar. - uint32_t number; - // The index (in bits) into _has_storage_. - // > 0: the bit to use for a value being set. - // = 0: no storage used. - // < 0: in a oneOf, use a full int32 to record the field active. - int32_t hasIndex; - // Field flags. Use accessor functions below. - GPBFieldFlags flags; - // Data type of the ivar. - GPBDataType dataType; - // Offset of the variable into it's structure struct. - size_t offset; - // FieldOptions protobuf, serialized as string. - const char *fieldOptions; - - GPBGenericValue defaultValue; // Default value for the ivar. union { const char *className; // Name for message class. // For enums only: If EnumDescriptors are compiled in, it will be that, @@ -98,31 +85,32 @@ typedef struct GPBMessageFieldDescription { GPBEnumDescriptorFunc enumDescFunc; GPBEnumValidationFunc enumVerifier; } dataTypeSpecific; + // The field number for the ivar. + uint32_t number; + // The index (in bits) into _has_storage_. + // >= 0: the bit to use for a value being set. + // = GPBNoHasBit(INT32_MAX): no storage used. + // < 0: in a oneOf, use a full int32 to record the field active. + int32_t hasIndex; + // Offset of the variable into it's structure struct. + uint32_t offset; + // Field flags. Use accessor functions below. + GPBFieldFlags flags; + // Data type of the ivar. + GPBDataType dataType; } GPBMessageFieldDescription; -// Describes a oneof. -typedef struct GPBMessageOneofDescription { - // Name of this enum oneof. - const char *name; - // The index of this oneof in the has_storage. - int32_t index; -} GPBMessageOneofDescription; +// Fields in messages defined in a 'proto2' syntax file can provide a default +// value. This struct provides the default along with the field info. +typedef struct GPBMessageFieldDescriptionWithDefault { + // Default value for the ivar. + GPBGenericValue defaultValue; -// Describes an enum type defined in a .proto file. -typedef struct GPBMessageEnumDescription { - GPBEnumDescriptorFunc enumDescriptorFunc; -} GPBMessageEnumDescription; - -// Describes an individual enum constant of a particular type. -typedef struct GPBMessageEnumValueDescription { - // Name of this enum constant. - const char *name; - // Numeric value of this enum constant. - int32_t number; -} GPBMessageEnumValueDescription; + GPBMessageFieldDescription core; +} GPBMessageFieldDescriptionWithDefault; // Describes attributes of the extension. -typedef NS_OPTIONS(uint32_t, GPBExtensionOptions) { +typedef NS_OPTIONS(uint8_t, GPBExtensionOptions) { // These map to standard protobuf concepts. GPBExtensionRepeated = 1 << 0, GPBExtensionPacked = 1 << 1, @@ -131,65 +119,53 @@ typedef NS_OPTIONS(uint32_t, GPBExtensionOptions) { // An extension typedef struct GPBExtensionDescription { - const char *singletonName; - GPBDataType dataType; - const char *extendedClass; - int32_t fieldNumber; GPBGenericValue defaultValue; + const char *singletonName; + const char *extendedClass; const char *messageOrGroupClassName; - GPBExtensionOptions options; GPBEnumDescriptorFunc enumDescriptorFunc; + int32_t fieldNumber; + GPBDataType dataType; + GPBExtensionOptions options; } GPBExtensionDescription; +typedef NS_OPTIONS(uint32_t, GPBDescriptorInitializationFlags) { + GPBDescriptorInitializationFlag_FieldsWithDefault = 1 << 0, + GPBDescriptorInitializationFlag_WireFormat = 1 << 1, +}; + @interface GPBDescriptor () { @package NSArray *fields_; NSArray *oneofs_; - size_t storageSize_; + uint32_t storageSize_; } -// fieldDescriptions, enumDescriptions, rangeDescriptions, and -// extraTextFormatInfo have to be long lived, they are held as raw pointers. +// fieldDescriptions have to be long lived, they are held as raw pointers. + (instancetype) allocDescriptorForClass:(Class)messageClass rootClass:(Class)rootClass file:(GPBFileDescriptor *)file - fields:(GPBMessageFieldDescription *)fieldDescriptions - fieldCount:(NSUInteger)fieldCount - oneofs:(GPBMessageOneofDescription *)oneofDescriptions - oneofCount:(NSUInteger)oneofCount - enums:(GPBMessageEnumDescription *)enumDescriptions - enumCount:(NSUInteger)enumCount - ranges:(const GPBExtensionRange *)ranges - rangeCount:(NSUInteger)rangeCount - storageSize:(size_t)storageSize - wireFormat:(BOOL)wireFormat; -+ (instancetype) - allocDescriptorForClass:(Class)messageClass - rootClass:(Class)rootClass - file:(GPBFileDescriptor *)file - fields:(GPBMessageFieldDescription *)fieldDescriptions - fieldCount:(NSUInteger)fieldCount - oneofs:(GPBMessageOneofDescription *)oneofDescriptions - oneofCount:(NSUInteger)oneofCount - enums:(GPBMessageEnumDescription *)enumDescriptions - enumCount:(NSUInteger)enumCount - ranges:(const GPBExtensionRange *)ranges - rangeCount:(NSUInteger)rangeCount - storageSize:(size_t)storageSize - wireFormat:(BOOL)wireFormat - extraTextFormatInfo:(const char *)extraTextFormatInfo; + fields:(void *)fieldDescriptions + fieldCount:(uint32_t)fieldCount + storageSize:(uint32_t)storageSize + flags:(GPBDescriptorInitializationFlags)flags; - (instancetype)initWithClass:(Class)messageClass file:(GPBFileDescriptor *)file fields:(NSArray *)fields - oneofs:(NSArray *)oneofs - enums:(NSArray *)enums - extensionRanges:(const GPBExtensionRange *)ranges - extensionRangesCount:(NSUInteger)rangeCount - storageSize:(size_t)storage + storageSize:(uint32_t)storage wireFormat:(BOOL)wireFormat; +// Called right after init to provide extra information to avoid init having +// an explosion of args. These pointers are recorded, so they are expected +// to live for the lifetime of the app. +- (void)setupOneofs:(const char **)oneofNames + count:(uint32_t)count + firstHasIndex:(int32_t)firstHasIndex; +- (void)setupExtraTextInfo:(const char *)extraTextFormatInfo; +- (void)setupExtensionRanges:(const GPBExtensionRange *)ranges count:(int32_t)count; + @end @interface GPBFileDescriptor () @@ -199,14 +175,12 @@ typedef struct GPBExtensionDescription { @interface GPBOneofDescriptor () { @package - GPBMessageOneofDescription *oneofDescription_; + const char *name_; NSArray *fields_; - SEL caseSel_; } -- (instancetype)initWithOneofDescription: - (GPBMessageOneofDescription *)oneofDescription - fields:(NSArray *)fields; +// name must be long lived. +- (instancetype)initWithName:(const char *)name fields:(NSArray *)fields; @end @interface GPBFieldDescriptor () { @@ -222,30 +196,32 @@ typedef struct GPBExtensionDescription { // Single initializer // description has to be long lived, it is held as a raw pointer. -- (instancetype)initWithFieldDescription: - (GPBMessageFieldDescription *)description - rootClass:(Class)rootClass +- (instancetype)initWithFieldDescription:(void *)description + includesDefault:(BOOL)includesDefault syntax:(GPBFileSyntax)syntax; @end @interface GPBEnumDescriptor () -// valueDescriptions and extraTextFormatInfo have to be long lived, they are +// valueNames, values and extraTextFormatInfo have to be long lived, they are // held as raw pointers. + (instancetype) allocDescriptorForName:(NSString *)name - values:(GPBMessageEnumValueDescription *)valueDescriptions - valueCount:(NSUInteger)valueCount + valueNames:(const char *)valueNames + values:(const int32_t *)values + count:(uint32_t)valueCount enumVerifier:(GPBEnumValidationFunc)enumVerifier; + (instancetype) allocDescriptorForName:(NSString *)name - values:(GPBMessageEnumValueDescription *)valueDescriptions - valueCount:(NSUInteger)valueCount + valueNames:(const char *)valueNames + values:(const int32_t *)values + count:(uint32_t)valueCount enumVerifier:(GPBEnumValidationFunc)enumVerifier extraTextFormatInfo:(const char *)extraTextFormatInfo; - (instancetype)initWithName:(NSString *)name - values:(GPBMessageEnumValueDescription *)valueDescriptions - valueCount:(NSUInteger)valueCount + valueNames:(const char *)valueNames + values:(const int32_t *)values + count:(uint32_t)valueCount enumVerifier:(GPBEnumValidationFunc)enumVerifier; @end @@ -314,5 +290,24 @@ GPB_INLINE BOOL GPBExtensionIsWireFormat(GPBExtensionDescription *description) { return (description->options & GPBExtensionSetWireFormat) != 0; } +// Helper for compile time assets. +#ifndef _GPBCompileAssert + #if __has_feature(c_static_assert) || __has_extension(c_static_assert) + #define _GPBCompileAssert(test, msg) _Static_assert((test), #msg) + #else + // Pre-Xcode 7 support. + #define _GPBCompileAssertSymbolInner(line, msg) _GPBCompileAssert ## line ## __ ## msg + #define _GPBCompileAssertSymbol(line, msg) _GPBCompileAssertSymbolInner(line, msg) + #define _GPBCompileAssert(test, msg) \ + typedef char _GPBCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] + #endif // __has_feature(c_static_assert) || __has_extension(c_static_assert) +#endif // _GPBCompileAssert + +// Sanity check that there isn't padding between the field description +// structures with and without a default. +_GPBCompileAssert(sizeof(GPBMessageFieldDescriptionWithDefault) == + (sizeof(GPBGenericValue) + + sizeof(GPBMessageFieldDescription)), + DescriptionsWithDefault_different_size_than_expected); CF_EXTERN_C_END diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index d5e8d37b..94d179be 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -54,18 +54,6 @@ NSString *const GPBExceptionMessageKey = static NSString *const kGPBDataCoderKey = @"GPBData"; -#ifndef _GPBCompileAssert - #if __has_feature(c_static_assert) || __has_extension(c_static_assert) - #define _GPBCompileAssert(test, msg) _Static_assert((test), #msg) - #else - // Pre-Xcode 7 support. - #define _GPBCompileAssertSymbolInner(line, msg) _GPBCompileAssert ## line ## __ ## msg - #define _GPBCompileAssertSymbol(line, msg) _GPBCompileAssertSymbolInner(line, msg) - #define _GPBCompileAssert(test, msg) \ - typedef char _GPBCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] - #endif // __has_feature(c_static_assert) || __has_extension(c_static_assert) -#endif // _GPBCompileAssert - // // PLEASE REMEMBER: // @@ -789,14 +777,8 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { file:fileDescriptor fields:NULL fieldCount:0 - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 storageSize:0 - wireFormat:NO]; + flags:0]; } return descriptor; } @@ -3096,7 +3078,7 @@ static void ResolveIvarSet(GPBFieldDescriptor *field, } else { GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof && (sel == oneof->caseSel_)) { - int32_t index = oneof->oneofDescription_->index; + int32_t index = GPBFieldHasIndex(field); result.impToAdd = imp_implementationWithBlock(^(id obj) { return GPBGetHasOneof(obj, index); }); diff --git a/objectivec/GPBProtocolBuffers.m b/objectivec/GPBProtocolBuffers.m index e9cbfb42..8512af7e 100644 --- a/objectivec/GPBProtocolBuffers.m +++ b/objectivec/GPBProtocolBuffers.m @@ -46,8 +46,6 @@ #import "GPBWellKnownTypes.m" #import "GPBWireFormat.m" -#import "google/protobuf/Descriptor.pbobjc.m" - // Duration and Timestamp are #imported into GPBWellKnownTypes.m to the // Objective C categories added will always be linked in with the classes. #import "google/protobuf/Any.pbobjc.m" diff --git a/objectivec/GPBRuntimeTypes.h b/objectivec/GPBRuntimeTypes.h index e91d86a6..0a38b110 100644 --- a/objectivec/GPBRuntimeTypes.h +++ b/objectivec/GPBRuntimeTypes.h @@ -67,7 +67,7 @@ typedef union { // Do not change the order of this enum (or add things to it) without thinking // about it very carefully. There are several things that depend on the order. -typedef enum { +typedef NS_ENUM(uint8_t, GPBDataType) { GPBDataTypeBool = 0, GPBDataTypeFixed32, GPBDataTypeSFixed32, @@ -86,7 +86,7 @@ typedef enum { GPBDataTypeMessage, GPBDataTypeGroup, GPBDataTypeEnum, -} GPBDataType; +}; enum { // A count of the number of types in GPBDataType. Separated out from the diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m index d4d6471f..3e9d11c0 100644 --- a/objectivec/GPBUtilities.m +++ b/objectivec/GPBUtilities.m @@ -145,9 +145,8 @@ void GPBSetHasIvar(GPBMessage *self, int32_t idx, uint32_t fieldNumber, } void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, - uint32_t fieldNumberNotToClear) { - int32_t hasIndex = oneof->oneofDescription_->index; - uint32_t fieldNumberSet = GPBGetHasOneof(self, hasIndex); + int32_t oneofHasIndex, uint32_t fieldNumberNotToClear) { + uint32_t fieldNumberSet = GPBGetHasOneof(self, oneofHasIndex); if ((fieldNumberSet == fieldNumberNotToClear) || (fieldNumberSet == 0)) { // Do nothing/nothing set in the oneof. return; @@ -168,7 +167,7 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, // Set to nothing stored in the oneof. // (field number doesn't matter since setting to nothing). - GPBSetHasIvar(self, hasIndex, 1, NO); + GPBSetHasIvar(self, oneofHasIndex, 1, NO); } #pragma mark - IVar accessors @@ -200,7 +199,8 @@ void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, //% NAME$S GPBFileSyntax syntax) { //% GPBOneofDescriptor *oneof = field->containingOneof_; //% if (oneof) { -//% GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); +//% GPBMessageFieldDescription *fieldDesc = field->description_; +//% GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); //% } //% NSCAssert(self->messageStorage_ != NULL, //% @"%@: All messages should have storage (from init)", @@ -321,7 +321,8 @@ void GPBSetRetainedObjectIvarWithFieldInternal(GPBMessage *self, // oneof. GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } // Clear "has" if they are being set to nil. BOOL setHasValue = (value != nil); @@ -476,15 +477,15 @@ void GPBSetMessageRawEnumField(GPBMessage *self, GPBFieldDescriptor *field, GPBSetInt32IvarWithFieldInternal(self, field, value, syntax); } -//%PDDM-EXPAND IVAR_POD_ACCESSORS_DEFN(Bool, BOOL) -// This block of code is generated, do not edit it directly. - BOOL GPBGetMessageBoolField(GPBMessage *self, GPBFieldDescriptor *field) { if (GPBGetHasIvarField(self, field)) { - uint8_t *storage = (uint8_t *)self->messageStorage_; - BOOL *typePtr = (BOOL *)&storage[field->description_->offset]; - return *typePtr; + // Bools are stored in the has bits to avoid needing explicit space in the + // storage structure. + // (the field number passed to the HasIvar helper doesn't really matter + // since the offset is never negative) + GPBMessageFieldDescription *fieldDesc = field->description_; + return GPBGetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number); } else { return field.defaultValue.valueBool; } @@ -503,19 +504,18 @@ void GPBSetBoolIvarWithFieldInternal(GPBMessage *self, GPBFieldDescriptor *field, BOOL value, GPBFileSyntax syntax) { + GPBMessageFieldDescription *fieldDesc = field->description_; GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } - NSCAssert(self->messageStorage_ != NULL, - @"%@: All messages should have storage (from init)", - [self class]); -#if defined(__clang_analyzer__) - if (self->messageStorage_ == NULL) return; -#endif - uint8_t *storage = (uint8_t *)self->messageStorage_; - BOOL *typePtr = (BOOL *)&storage[field->description_->offset]; - *typePtr = value; + + // Bools are stored in the has bits to avoid needing explicit space in the + // storage structure. + // (the field number passed to the HasIvar helper doesn't really matter since + // the offset is never negative) + GPBSetHasIvar(self, (int32_t)(fieldDesc->offset), fieldDesc->number, value); + // proto2: any value counts as having been set; proto3, it // has to be a non zero value. BOOL hasValue = @@ -553,7 +553,8 @@ void GPBSetInt32IvarWithFieldInternal(GPBMessage *self, GPBFileSyntax syntax) { GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", @@ -601,7 +602,8 @@ void GPBSetUInt32IvarWithFieldInternal(GPBMessage *self, GPBFileSyntax syntax) { GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", @@ -649,7 +651,8 @@ void GPBSetInt64IvarWithFieldInternal(GPBMessage *self, GPBFileSyntax syntax) { GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", @@ -697,7 +700,8 @@ void GPBSetUInt64IvarWithFieldInternal(GPBMessage *self, GPBFileSyntax syntax) { GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", @@ -745,7 +749,8 @@ void GPBSetFloatIvarWithFieldInternal(GPBMessage *self, GPBFileSyntax syntax) { GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", @@ -793,7 +798,8 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self, GPBFileSyntax syntax) { GPBOneofDescriptor *oneof = field->containingOneof_; if (oneof) { - GPBMaybeClearOneof(self, oneof, GPBFieldNumber(field)); + GPBMessageFieldDescription *fieldDesc = field->description_; + GPBMaybeClearOneof(self, oneof, fieldDesc->hasIndex, fieldDesc->number); } NSCAssert(self->messageStorage_ != NULL, @"%@: All messages should have storage (from init)", @@ -812,7 +818,7 @@ void GPBSetDoubleIvarWithFieldInternal(GPBMessage *self, GPBBecomeVisibleToAutocreator(self); } -//%PDDM-EXPAND-END (7 expansions) +//%PDDM-EXPAND-END (6 expansions) // Aliases are function calls that are virtually the same. diff --git a/objectivec/GPBUtilities_PackagePrivate.h b/objectivec/GPBUtilities_PackagePrivate.h index cac551f6..a6b6c84d 100644 --- a/objectivec/GPBUtilities_PackagePrivate.h +++ b/objectivec/GPBUtilities_PackagePrivate.h @@ -185,7 +185,7 @@ GPB_INLINE void GPBSetHasIvarField(GPBMessage *self, GPBFieldDescriptor *field, } void GPBMaybeClearOneof(GPBMessage *self, GPBOneofDescriptor *oneof, - uint32_t fieldNumberNotToClear); + int32_t oneofHasIndex, uint32_t fieldNumberNotToClear); //%PDDM-DEFINE GPB_IVAR_SET_DECL(NAME, TYPE) //%void GPBSet##NAME##IvarWithFieldInternal(GPBMessage *self, diff --git a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj index 78c3f9ba..30934254 100644 --- a/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_OSX.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */; }; 7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */; }; @@ -27,7 +26,6 @@ 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; }; 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; }; - 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; 8BBEA4A9147C727D00C4ADB7 /* GPBCodedInputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69B0F94FDF800A0C422 /* GPBCodedInputStreamTests.m */; }; 8BBEA4AA147C727D00C4ADB7 /* GPBCodedOuputStreamTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B69D0F94FDF800A0C422 /* GPBCodedOuputStreamTests.m */; }; 8BBEA4AC147C727D00C4ADB7 /* GPBMessageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B6A30F94FDF800A0C422 /* GPBMessageTests.m */; }; @@ -140,10 +138,8 @@ 8B4248D51A92826400BC1EC6 /* Timestamp.pbobjc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Timestamp.pbobjc.h; path = google/protobuf/Timestamp.pbobjc.h; sourceTree = ""; }; 8B4248D61A92826400BC1EC6 /* Timestamp.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Timestamp.pbobjc.m; path = google/protobuf/Timestamp.pbobjc.m; sourceTree = ""; }; 8B4248DB1A92933A00BC1EC6 /* GPBWellKnownTypesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypesTest.m; sourceTree = ""; }; - 8B42494B1A92A16600BC1EC6 /* descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = descriptor.proto; path = ../src/google/protobuf/descriptor.proto; sourceTree = ""; }; 8B42494C1A92A16600BC1EC6 /* duration.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = duration.proto; path = ../src/google/protobuf/duration.proto; sourceTree = ""; }; 8B42494D1A92A16600BC1EC6 /* timestamp.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = timestamp.proto; path = ../src/google/protobuf/timestamp.proto; sourceTree = ""; }; - 8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Descriptor.pbobjc.h; path = google/protobuf/Descriptor.pbobjc.h; sourceTree = SOURCE_ROOT; }; 8B79657814992E3E002FFBFC /* GPBRootObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBRootObject.h; sourceTree = ""; }; 8B79657914992E3E002FFBFC /* GPBRootObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBRootObject.m; sourceTree = ""; }; 8B7E6A7414893DBA00F8884A /* unittest_custom_options.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_custom_options.proto; path = ../../src/google/protobuf/unittest_custom_options.proto; sourceTree = ""; }; @@ -162,7 +158,6 @@ 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = ""; }; 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = ""; }; 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = ""; }; - 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Descriptor.pbobjc.m; path = google/protobuf/Descriptor.pbobjc.m; sourceTree = SOURCE_ROOT; }; 8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRuntimeTypes.h; sourceTree = ""; }; F401DC2A1A8D444600FCC765 /* GPBArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBArray.h; sourceTree = ""; }; F401DC2B1A8D444600FCC765 /* GPBArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArray.m; sourceTree = ""; }; @@ -300,9 +295,6 @@ F4E675881B21D0000054530B /* Api.pbobjc.h */, F4E675891B21D0000054530B /* Api.pbobjc.m */, F4E675A71B21D05C0054530B /* api.proto */, - 8B54585814DCC34E003D7338 /* Descriptor.pbobjc.h */, - 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */, - 8B42494B1A92A16600BC1EC6 /* descriptor.proto */, 8B4248D31A92826400BC1EC6 /* Duration.pbobjc.h */, 8B4248D41A92826400BC1EC6 /* Duration.pbobjc.m */, 8B42494C1A92A16600BC1EC6 /* duration.proto */, @@ -634,7 +626,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */, 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */, F4E6759B1B21D0000054530B /* Empty.pbobjc.m in Sources */, 7461B53D0F94FB4E00A0C422 /* GPBCodedOutputStream.m in Sources */, @@ -696,7 +687,6 @@ 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */, 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */, F4E675B11B21D0A70054530B /* FieldMask.pbobjc.m in Sources */, - 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */, 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */, F4E675AF1B21D0A70054530B /* Api.pbobjc.m in Sources */, ); diff --git a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj index 5d96c05f..b6221819 100644 --- a/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj +++ b/objectivec/ProtocolBuffers_iOS.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; 5102DABC1891A073002037B6 /* GPBConcurrencyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5102DABB1891A052002037B6 /* GPBConcurrencyTests.m */; }; 7461B5360F94FB4600A0C422 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 7461B48F0F94F99000A0C422 /* GPBCodedInputStream.m */; }; @@ -27,7 +26,6 @@ 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B79657914992E3E002FFBFC /* GPBRootObject.m */; }; 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B8B615C17DF7056002EE618 /* GPBARCUnittestProtos.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 8B96157414C8C38C00A2AC0B /* GPBDescriptor.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B96157314C8C38C00A2AC0B /* GPBDescriptor.m */; }; - 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */ = {isa = PBXBuildFile; fileRef = 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */; }; 8B9742331A89D19F00DCE92C /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8B9742321A89D19F00DCE92C /* LaunchScreen.xib */; }; 8B9742431A8AAA7800DCE92C /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B9742421A8AAA7800DCE92C /* CoreGraphics.framework */; }; 8B9A5EA61831993600A9D33B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; @@ -155,7 +153,6 @@ 8B4248E21A929C8900BC1EC6 /* GPBWellKnownTypes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypes.m; sourceTree = ""; }; 8B4248E51A929C9900BC1EC6 /* GPBWellKnownTypesTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBWellKnownTypesTest.m; sourceTree = ""; }; 8B4249481A92A02300BC1EC6 /* timestamp.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = timestamp.proto; path = ../src/google/protobuf/timestamp.proto; sourceTree = ""; }; - 8B4249491A92A0BA00BC1EC6 /* descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = descriptor.proto; path = ../src/google/protobuf/descriptor.proto; sourceTree = ""; }; 8B42494A1A92A0BA00BC1EC6 /* duration.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = duration.proto; path = ../src/google/protobuf/duration.proto; sourceTree = ""; }; 8B79657814992E3E002FFBFC /* GPBRootObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GPBRootObject.h; sourceTree = ""; }; 8B79657914992E3E002FFBFC /* GPBRootObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBRootObject.m; sourceTree = ""; }; @@ -183,7 +180,6 @@ 8BCF338814ED799900BC5317 /* GPBProtocolBuffers.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GPBProtocolBuffers.m; sourceTree = ""; }; 8BD3981D14BE54220081D629 /* unittest_enormous_descriptor.proto */ = {isa = PBXFileReference; lastKnownFileType = text; name = unittest_enormous_descriptor.proto; path = ../../src/google/protobuf/unittest_enormous_descriptor.proto; sourceTree = ""; }; 8BD3981E14BE59D70081D629 /* GPBUnittestProtos.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBUnittestProtos.m; sourceTree = ""; }; - 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Descriptor.pbobjc.m; path = google/protobuf/Descriptor.pbobjc.m; sourceTree = SOURCE_ROOT; }; 8BEB5AE01498033E0078BF9D /* GPBRuntimeTypes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPBRuntimeTypes.h; sourceTree = ""; }; F401DC341A8E5C6F00FCC765 /* GPBArrayTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBArrayTests.m; sourceTree = ""; }; F41C175C1833D3310064ED4D /* GPBPerfTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GPBPerfTests.m; sourceTree = ""; }; @@ -224,7 +220,6 @@ F4E675B71B21D1440054530B /* Any.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Any.pbobjc.m; path = google/protobuf/Any.pbobjc.m; sourceTree = ""; }; F4E675B81B21D1440054530B /* Api.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Api.pbobjc.h; path = google/protobuf/Api.pbobjc.h; sourceTree = ""; }; F4E675B91B21D1440054530B /* Api.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Api.pbobjc.m; path = google/protobuf/Api.pbobjc.m; sourceTree = ""; }; - F4E675BA1B21D1440054530B /* Descriptor.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Descriptor.pbobjc.h; path = google/protobuf/Descriptor.pbobjc.h; sourceTree = ""; }; F4E675BB1B21D1440054530B /* Empty.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Empty.pbobjc.h; path = google/protobuf/Empty.pbobjc.h; sourceTree = ""; }; F4E675BC1B21D1440054530B /* Empty.pbobjc.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Empty.pbobjc.m; path = google/protobuf/Empty.pbobjc.m; sourceTree = ""; }; F4E675BD1B21D1440054530B /* FieldMask.pbobjc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FieldMask.pbobjc.h; path = google/protobuf/FieldMask.pbobjc.h; sourceTree = ""; }; @@ -335,9 +330,6 @@ F4E675B81B21D1440054530B /* Api.pbobjc.h */, F4E675B91B21D1440054530B /* Api.pbobjc.m */, F4E675D91B21D1DE0054530B /* api.proto */, - F4E675BA1B21D1440054530B /* Descriptor.pbobjc.h */, - 8BD3982214BE5B0C0081D629 /* Descriptor.pbobjc.m */, - 8B4249491A92A0BA00BC1EC6 /* descriptor.proto */, 8B4248DD1A929C7D00BC1EC6 /* Duration.pbobjc.h */, 8B4248DE1A929C7D00BC1EC6 /* Duration.pbobjc.m */, 8B42494A1A92A0BA00BC1EC6 /* duration.proto */, @@ -722,7 +714,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 2CFB390415C718CE00CBF84D /* Descriptor.pbobjc.m in Sources */, 7461B53C0F94FB4E00A0C422 /* GPBCodedInputStream.m in Sources */, F4E675D21B21D1620054530B /* Empty.pbobjc.m in Sources */, F4487C731A9F906200531423 /* GPBArray.m in Sources */, @@ -792,7 +783,6 @@ 8B79657D14992E3F002FFBFC /* GPBRootObject.m in Sources */, 8BD3981F14BE59D70081D629 /* GPBUnittestProtos.m in Sources */, F4E675CB1B21D1610054530B /* FieldMask.pbobjc.m in Sources */, - 8B96157514CA019D00A2AC0B /* Descriptor.pbobjc.m in Sources */, 8B8B615D17DF7056002EE618 /* GPBARCUnittestProtos.m in Sources */, F4E675C91B21D1610054530B /* Api.pbobjc.m in Sources */, ); diff --git a/objectivec/Tests/GPBARCUnittestProtos.m b/objectivec/Tests/GPBARCUnittestProtos.m index d0408869..28d2396c 100644 --- a/objectivec/Tests/GPBARCUnittestProtos.m +++ b/objectivec/Tests/GPBARCUnittestProtos.m @@ -34,6 +34,11 @@ // Makes sure all the generated headers compile with ARC on. +// The unittest_custom_options.proto extends the messages in descriptor.proto +// so we build it in to test extending in general. The library doesn't provide +// a descriptor as it doesn't use the classes/enums. +#import "google/protobuf/Descriptor.pbobjc.h" + #import "google/protobuf/Unittest.pbobjc.h" #import "google/protobuf/UnittestCustomOptions.pbobjc.h" #import "google/protobuf/UnittestCycle.pbobjc.h" diff --git a/objectivec/Tests/GPBDescriptorTests.m b/objectivec/Tests/GPBDescriptorTests.m index ccdbb645..a1923c9c 100644 --- a/objectivec/Tests/GPBDescriptorTests.m +++ b/objectivec/Tests/GPBDescriptorTests.m @@ -153,19 +153,6 @@ XCTAssertFalse([fieldDescriptor isValidEnumValue:-2]); } -- (void)testEnumDescriptorLookup { - GPBDescriptor *descriptor = [TestAllTypes descriptor]; - GPBEnumDescriptor *enumDescriptor = - [descriptor enumWithName:@"TestAllTypes_NestedEnum"]; - XCTAssertNotNil(enumDescriptor); - - // Descriptor cannot find foreign or imported enums. - enumDescriptor = [descriptor enumWithName:@"ForeignEnumEnum"]; - XCTAssertNil(enumDescriptor); - enumDescriptor = [descriptor enumWithName:@"ImportEnumEnum"]; - XCTAssertNil(enumDescriptor); -} - - (void)testOneofDescriptor { GPBDescriptor *descriptor = [TestOneof2 descriptor]; diff --git a/objectivec/Tests/GPBUnittestProtos.m b/objectivec/Tests/GPBUnittestProtos.m index 50c4dfa9..d19beee9 100644 --- a/objectivec/Tests/GPBUnittestProtos.m +++ b/objectivec/Tests/GPBUnittestProtos.m @@ -31,6 +31,11 @@ // Collects all the compiled protos into one file and compiles them to make sure // the compiler is generating valid code. +// The unittest_custom_options.proto extends the messages in descriptor.proto +// so we build it in to test extending in general. The library doesn't provide +// a descriptor as it doesn't use the classes/enums. +#import "google/protobuf/Descriptor.pbobjc.m" + #import "google/protobuf/MapProto2Unittest.pbobjc.m" #import "google/protobuf/MapUnittest.pbobjc.m" #import "google/protobuf/Unittest.pbobjc.m" diff --git a/objectivec/generate_descriptors_proto.sh b/objectivec/generate_well_known_types.sh similarity index 85% rename from objectivec/generate_descriptors_proto.sh rename to objectivec/generate_well_known_types.sh index 84ba0738..be9b38a5 100755 --- a/objectivec/generate_descriptors_proto.sh +++ b/objectivec/generate_well_known_types.sh @@ -1,9 +1,9 @@ #!/bin/bash -# Run this script to regenerate descriptor.pbobjc.{h,m} after the protocol -# compiler changes. +# Run this script to regenerate *.pbobjc.{h,m} for the well known types after +# the protocol compiler changes. -# HINT: Flags passed to generate_descriptor_proto.sh will be passed directly +# HINT: Flags passed to generate_well_known_types.sh will be passed directly # to make when building protoc. This is particularly useful for passing # -j4 to run 4 jobs simultaneously. @@ -37,7 +37,6 @@ make $@ protoc declare -a RUNTIME_PROTO_FILES=( \ google/protobuf/any.proto \ google/protobuf/api.proto \ - google/protobuf/descriptor.proto \ google/protobuf/duration.proto \ google/protobuf/empty.proto \ google/protobuf/field_mask.proto \ diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h index a204ae9a..79ec0fb7 100644 --- a/objectivec/google/protobuf/Any.pbobjc.h +++ b/objectivec/google/protobuf/Any.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m index b41102a4..7cbf0def 100644 --- a/objectivec/google/protobuf/Any.pbobjc.m +++ b/objectivec/google/protobuf/Any.pbobjc.m @@ -46,47 +46,36 @@ typedef struct GPBAny__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "typeURL", + .dataTypeSpecific.className = NULL, .number = GPBAny_FieldNumber_TypeURL, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBAny__storage_, typeURL), .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, .dataType = GPBDataTypeString, - .offset = offsetof(GPBAny__storage_, typeURL), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBAny_FieldNumber_Value, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBAny__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeBytes, - .offset = offsetof(GPBAny__storage_, value), - .defaultValue.valueData = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; -#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - const char *extraTextFormatInfo = NULL; -#else - static const char *extraTextFormatInfo = "\001\001\004\241!!\000"; -#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS GPBDescriptor *localDescriptor = [GPBDescriptor allocDescriptorForClass:[GPBAny class] rootClass:[GPBAnyRoot class] file:GPBAnyRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBAny__storage_) - wireFormat:NO - extraTextFormatInfo:extraTextFormatInfo]; + flags:0]; +#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + static const char *extraTextFormatInfo = + "\001\001\004\241!!\000"; + [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; +#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h index 271a166f..3f7e99c6 100644 --- a/objectivec/google/protobuf/Api.pbobjc.h +++ b/objectivec/google/protobuf/Api.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m index d964ff41..2b2f62ea 100644 --- a/objectivec/google/protobuf/Api.pbobjc.m +++ b/objectivec/google/protobuf/Api.pbobjc.m @@ -71,80 +71,66 @@ typedef struct GPBApi__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBApi_FieldNumber_Name, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBApi__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBApi__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "methodsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBMethod), .number = GPBApi_FieldNumber_MethodsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBApi__storage_, methodsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBApi__storage_, methodsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBMethod), - .fieldOptions = NULL, }, { .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), .number = GPBApi_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBApi__storage_, optionsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBApi__storage_, optionsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .fieldOptions = NULL, }, { .name = "version", + .dataTypeSpecific.className = NULL, .number = GPBApi_FieldNumber_Version, - .hasIndex = 3, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBApi__storage_, version), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBApi__storage_, version), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "sourceContext", + .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), .number = GPBApi_FieldNumber_SourceContext, - .hasIndex = 4, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBApi__storage_, sourceContext), .flags = GPBFieldOptional, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBApi__storage_, sourceContext), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), - .fieldOptions = NULL, }, { .name = "mixinsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBMixin), .number = GPBApi_FieldNumber_MixinsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBApi__storage_, mixinsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBApi__storage_, mixinsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBMixin), - .fieldOptions = NULL, }, { .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, .number = GPBApi_FieldNumber_Syntax, - .hasIndex = 6, + .hasIndex = 3, + .offset = (uint32_t)offsetof(GPBApi__storage_, syntax), .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBApi__storage_, syntax), - .defaultValue.valueEnum = GPBSyntax_SyntaxProto2, - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -152,15 +138,9 @@ typedef struct GPBApi__storage_ { rootClass:[GPBApiRoot class] file:GPBApiRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBApi__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -195,8 +175,6 @@ void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value) { typedef struct GPBMethod__storage_ { uint32_t _has_storage_[1]; - BOOL requestStreaming; - BOOL responseStreaming; GPBSyntax syntax; NSString *name; NSString *requestTypeURL; @@ -212,102 +190,81 @@ typedef struct GPBMethod__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBMethod_FieldNumber_Name, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBMethod__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBMethod__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "requestTypeURL", + .dataTypeSpecific.className = NULL, .number = GPBMethod_FieldNumber_RequestTypeURL, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBMethod__storage_, requestTypeURL), .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, .dataType = GPBDataTypeString, - .offset = offsetof(GPBMethod__storage_, requestTypeURL), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "requestStreaming", + .dataTypeSpecific.className = NULL, .number = GPBMethod_FieldNumber_RequestStreaming, .hasIndex = 2, + .offset = 3, // Stored in _has_storage_ to save space. .flags = GPBFieldOptional, .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMethod__storage_, requestStreaming), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "responseTypeURL", + .dataTypeSpecific.className = NULL, .number = GPBMethod_FieldNumber_ResponseTypeURL, - .hasIndex = 3, + .hasIndex = 4, + .offset = (uint32_t)offsetof(GPBMethod__storage_, responseTypeURL), .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, .dataType = GPBDataTypeString, - .offset = offsetof(GPBMethod__storage_, responseTypeURL), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "responseStreaming", + .dataTypeSpecific.className = NULL, .number = GPBMethod_FieldNumber_ResponseStreaming, - .hasIndex = 4, + .hasIndex = 5, + .offset = 6, // Stored in _has_storage_ to save space. .flags = GPBFieldOptional, .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMethod__storage_, responseStreaming), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), .number = GPBMethod_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBMethod__storage_, optionsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBMethod__storage_, optionsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .fieldOptions = NULL, }, { .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, .number = GPBMethod_FieldNumber_Syntax, - .hasIndex = 6, + .hasIndex = 7, + .offset = (uint32_t)offsetof(GPBMethod__storage_, syntax), .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBMethod__storage_, syntax), - .defaultValue.valueEnum = GPBSyntax_SyntaxProto2, - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .fieldOptions = NULL, }, }; -#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - const char *extraTextFormatInfo = NULL; -#else - static const char *extraTextFormatInfo = "\002\002\007\244\241!!\000\004\010\244\241!!\000"; -#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS GPBDescriptor *localDescriptor = [GPBDescriptor allocDescriptorForClass:[GPBMethod class] rootClass:[GPBApiRoot class] file:GPBApiRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBMethod__storage_) - wireFormat:NO - extraTextFormatInfo:extraTextFormatInfo]; + flags:0]; +#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + static const char *extraTextFormatInfo = + "\002\002\007\244\241!!\000\004\010\244\241!!\000"; + [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; +#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -349,25 +306,21 @@ typedef struct GPBMixin__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBMixin_FieldNumber_Name, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBMixin__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBMixin__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "root", + .dataTypeSpecific.className = NULL, .number = GPBMixin_FieldNumber_Root, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBMixin__storage_, root), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBMixin__storage_, root), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -375,15 +328,9 @@ typedef struct GPBMixin__storage_ { rootClass:[GPBApiRoot class] file:GPBApiRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBMixin__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.h b/objectivec/google/protobuf/Descriptor.pbobjc.h deleted file mode 100644 index 109711c7..00000000 --- a/objectivec/google/protobuf/Descriptor.pbobjc.h +++ /dev/null @@ -1,1279 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/descriptor.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -CF_EXTERN_C_BEGIN - -@class GPBDescriptorProto; -@class GPBDescriptorProto_ExtensionRange; -@class GPBDescriptorProto_ReservedRange; -@class GPBEnumDescriptorProto; -@class GPBEnumOptions; -@class GPBEnumValueDescriptorProto; -@class GPBEnumValueOptions; -@class GPBFieldDescriptorProto; -@class GPBFieldOptions; -@class GPBFileDescriptorProto; -@class GPBFileOptions; -@class GPBGeneratedCodeInfo_Annotation; -@class GPBMessageOptions; -@class GPBMethodDescriptorProto; -@class GPBMethodOptions; -@class GPBOneofDescriptorProto; -@class GPBServiceDescriptorProto; -@class GPBServiceOptions; -@class GPBSourceCodeInfo; -@class GPBSourceCodeInfo_Location; -@class GPBUninterpretedOption; -@class GPBUninterpretedOption_NamePart; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Enum GPBFieldDescriptorProto_Type - -typedef GPB_ENUM(GPBFieldDescriptorProto_Type) { - /// 0 is reserved for errors. - /// Order is weird for historical reasons. - GPBFieldDescriptorProto_Type_TypeDouble = 1, - GPBFieldDescriptorProto_Type_TypeFloat = 2, - - /// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - /// negative values are likely. - GPBFieldDescriptorProto_Type_TypeInt64 = 3, - GPBFieldDescriptorProto_Type_TypeUint64 = 4, - - /// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - /// negative values are likely. - GPBFieldDescriptorProto_Type_TypeInt32 = 5, - GPBFieldDescriptorProto_Type_TypeFixed64 = 6, - GPBFieldDescriptorProto_Type_TypeFixed32 = 7, - GPBFieldDescriptorProto_Type_TypeBool = 8, - GPBFieldDescriptorProto_Type_TypeString = 9, - - /// Tag-delimited aggregate. - GPBFieldDescriptorProto_Type_TypeGroup = 10, - - /// Length-delimited aggregate. - GPBFieldDescriptorProto_Type_TypeMessage = 11, - - /// New in version 2. - GPBFieldDescriptorProto_Type_TypeBytes = 12, - GPBFieldDescriptorProto_Type_TypeUint32 = 13, - GPBFieldDescriptorProto_Type_TypeEnum = 14, - GPBFieldDescriptorProto_Type_TypeSfixed32 = 15, - GPBFieldDescriptorProto_Type_TypeSfixed64 = 16, - - /// Uses ZigZag encoding. - GPBFieldDescriptorProto_Type_TypeSint32 = 17, - - /// Uses ZigZag encoding. - GPBFieldDescriptorProto_Type_TypeSint64 = 18, -}; - -GPBEnumDescriptor *GPBFieldDescriptorProto_Type_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBFieldDescriptorProto_Type_IsValidValue(int32_t value); - -#pragma mark - Enum GPBFieldDescriptorProto_Label - -typedef GPB_ENUM(GPBFieldDescriptorProto_Label) { - /// 0 is reserved for errors - GPBFieldDescriptorProto_Label_LabelOptional = 1, - GPBFieldDescriptorProto_Label_LabelRequired = 2, - - /// TODO(sanjay): Should we add LABEL_MAP? - GPBFieldDescriptorProto_Label_LabelRepeated = 3, -}; - -GPBEnumDescriptor *GPBFieldDescriptorProto_Label_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBFieldDescriptorProto_Label_IsValidValue(int32_t value); - -#pragma mark - Enum GPBFileOptions_OptimizeMode - -/// Generated classes can be optimized for speed or code size. -typedef GPB_ENUM(GPBFileOptions_OptimizeMode) { - /// Generate complete code for parsing, serialization, - GPBFileOptions_OptimizeMode_Speed = 1, - - /// etc. - GPBFileOptions_OptimizeMode_CodeSize = 2, - - /// Generate code using MessageLite and the lite runtime. - GPBFileOptions_OptimizeMode_LiteRuntime = 3, -}; - -GPBEnumDescriptor *GPBFileOptions_OptimizeMode_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBFileOptions_OptimizeMode_IsValidValue(int32_t value); - -#pragma mark - Enum GPBFieldOptions_CType - -typedef GPB_ENUM(GPBFieldOptions_CType) { - /// Default mode. - GPBFieldOptions_CType_String = 0, - GPBFieldOptions_CType_Cord = 1, - GPBFieldOptions_CType_StringPiece = 2, -}; - -GPBEnumDescriptor *GPBFieldOptions_CType_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBFieldOptions_CType_IsValidValue(int32_t value); - -#pragma mark - Enum GPBFieldOptions_JSType - -typedef GPB_ENUM(GPBFieldOptions_JSType) { - /// Use the default type. - GPBFieldOptions_JSType_JsNormal = 0, - - /// Use JavaScript strings. - GPBFieldOptions_JSType_JsString = 1, - - /// Use JavaScript numbers. - GPBFieldOptions_JSType_JsNumber = 2, -}; - -GPBEnumDescriptor *GPBFieldOptions_JSType_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBFieldOptions_JSType_IsValidValue(int32_t value); - -#pragma mark - GPBDescriptorRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBDescriptorRoot : GPBRootObject -@end - -#pragma mark - GPBFileDescriptorSet - -typedef GPB_ENUM(GPBFileDescriptorSet_FieldNumber) { - GPBFileDescriptorSet_FieldNumber_FileArray = 1, -}; - -/// The protocol compiler can output a FileDescriptorSet containing the .proto -/// files it parses. -@interface GPBFileDescriptorSet : GPBMessage - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fileArray; -/// The number of items in @c fileArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger fileArray_Count; - -@end - -#pragma mark - GPBFileDescriptorProto - -typedef GPB_ENUM(GPBFileDescriptorProto_FieldNumber) { - GPBFileDescriptorProto_FieldNumber_Name = 1, - GPBFileDescriptorProto_FieldNumber_Package = 2, - GPBFileDescriptorProto_FieldNumber_DependencyArray = 3, - GPBFileDescriptorProto_FieldNumber_MessageTypeArray = 4, - GPBFileDescriptorProto_FieldNumber_EnumTypeArray = 5, - GPBFileDescriptorProto_FieldNumber_ServiceArray = 6, - GPBFileDescriptorProto_FieldNumber_ExtensionArray = 7, - GPBFileDescriptorProto_FieldNumber_Options = 8, - GPBFileDescriptorProto_FieldNumber_SourceCodeInfo = 9, - GPBFileDescriptorProto_FieldNumber_PublicDependencyArray = 10, - GPBFileDescriptorProto_FieldNumber_WeakDependencyArray = 11, - GPBFileDescriptorProto_FieldNumber_Syntax = 12, -}; - -/// Describes a complete .proto file. -@interface GPBFileDescriptorProto : GPBMessage - -/// file name, relative to root of source tree -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -/// e.g. "foo", "foo.bar", etc. -@property(nonatomic, readwrite, copy, null_resettable) NSString *package; -/// Test to see if @c package has been set. -@property(nonatomic, readwrite) BOOL hasPackage; - -/// Names of files imported by this file. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *dependencyArray; -/// The number of items in @c dependencyArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger dependencyArray_Count; - -/// Indexes of the public imported files in the dependency list above. -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *publicDependencyArray; -/// The number of items in @c publicDependencyArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger publicDependencyArray_Count; - -/// Indexes of the weak imported files in the dependency list. -/// For Google-internal migration only. Do not use. -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *weakDependencyArray; -/// The number of items in @c weakDependencyArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger weakDependencyArray_Count; - -/// All top-level definitions in this file. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *messageTypeArray; -/// The number of items in @c messageTypeArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger messageTypeArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumTypeArray; -/// The number of items in @c enumTypeArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger enumTypeArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *serviceArray; -/// The number of items in @c serviceArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger serviceArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionArray; -/// The number of items in @c extensionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger extensionArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) GPBFileOptions *options; -/// Test to see if @c options has been set. -@property(nonatomic, readwrite) BOOL hasOptions; - -/// This field contains optional information about the original source code. -/// You may safely remove this entire field without harming runtime -/// functionality of the descriptors -- the information is needed only by -/// development tools. -@property(nonatomic, readwrite, strong, null_resettable) GPBSourceCodeInfo *sourceCodeInfo; -/// Test to see if @c sourceCodeInfo has been set. -@property(nonatomic, readwrite) BOOL hasSourceCodeInfo; - -/// The syntax of the proto file. -/// The supported values are "proto2" and "proto3". -@property(nonatomic, readwrite, copy, null_resettable) NSString *syntax; -/// Test to see if @c syntax has been set. -@property(nonatomic, readwrite) BOOL hasSyntax; - -@end - -#pragma mark - GPBDescriptorProto - -typedef GPB_ENUM(GPBDescriptorProto_FieldNumber) { - GPBDescriptorProto_FieldNumber_Name = 1, - GPBDescriptorProto_FieldNumber_FieldArray = 2, - GPBDescriptorProto_FieldNumber_NestedTypeArray = 3, - GPBDescriptorProto_FieldNumber_EnumTypeArray = 4, - GPBDescriptorProto_FieldNumber_ExtensionRangeArray = 5, - GPBDescriptorProto_FieldNumber_ExtensionArray = 6, - GPBDescriptorProto_FieldNumber_Options = 7, - GPBDescriptorProto_FieldNumber_OneofDeclArray = 8, - GPBDescriptorProto_FieldNumber_ReservedRangeArray = 9, - GPBDescriptorProto_FieldNumber_ReservedNameArray = 10, -}; - -/// Describes a message type. -@interface GPBDescriptorProto : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldArray; -/// The number of items in @c fieldArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger fieldArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionArray; -/// The number of items in @c extensionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger extensionArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nestedTypeArray; -/// The number of items in @c nestedTypeArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger nestedTypeArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumTypeArray; -/// The number of items in @c enumTypeArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger enumTypeArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *extensionRangeArray; -/// The number of items in @c extensionRangeArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger extensionRangeArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *oneofDeclArray; -/// The number of items in @c oneofDeclArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger oneofDeclArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) GPBMessageOptions *options; -/// Test to see if @c options has been set. -@property(nonatomic, readwrite) BOOL hasOptions; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *reservedRangeArray; -/// The number of items in @c reservedRangeArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger reservedRangeArray_Count; - -/// Reserved field names, which may not be used by fields in the same message. -/// A given name may only be reserved once. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *reservedNameArray; -/// The number of items in @c reservedNameArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger reservedNameArray_Count; - -@end - -#pragma mark - GPBDescriptorProto_ExtensionRange - -typedef GPB_ENUM(GPBDescriptorProto_ExtensionRange_FieldNumber) { - GPBDescriptorProto_ExtensionRange_FieldNumber_Start = 1, - GPBDescriptorProto_ExtensionRange_FieldNumber_End = 2, -}; - -@interface GPBDescriptorProto_ExtensionRange : GPBMessage - -@property(nonatomic, readwrite) int32_t start; - -@property(nonatomic, readwrite) BOOL hasStart; -@property(nonatomic, readwrite) int32_t end; - -@property(nonatomic, readwrite) BOOL hasEnd; -@end - -#pragma mark - GPBDescriptorProto_ReservedRange - -typedef GPB_ENUM(GPBDescriptorProto_ReservedRange_FieldNumber) { - GPBDescriptorProto_ReservedRange_FieldNumber_Start = 1, - GPBDescriptorProto_ReservedRange_FieldNumber_End = 2, -}; - -/// Range of reserved tag numbers. Reserved tag numbers may not be used by -/// fields or extension ranges in the same message. Reserved ranges may -/// not overlap. -@interface GPBDescriptorProto_ReservedRange : GPBMessage - -/// Inclusive. -@property(nonatomic, readwrite) int32_t start; - -@property(nonatomic, readwrite) BOOL hasStart; -/// Exclusive. -@property(nonatomic, readwrite) int32_t end; - -@property(nonatomic, readwrite) BOOL hasEnd; -@end - -#pragma mark - GPBFieldDescriptorProto - -typedef GPB_ENUM(GPBFieldDescriptorProto_FieldNumber) { - GPBFieldDescriptorProto_FieldNumber_Name = 1, - GPBFieldDescriptorProto_FieldNumber_Extendee = 2, - GPBFieldDescriptorProto_FieldNumber_Number = 3, - GPBFieldDescriptorProto_FieldNumber_Label = 4, - GPBFieldDescriptorProto_FieldNumber_Type = 5, - GPBFieldDescriptorProto_FieldNumber_TypeName = 6, - GPBFieldDescriptorProto_FieldNumber_DefaultValue = 7, - GPBFieldDescriptorProto_FieldNumber_Options = 8, - GPBFieldDescriptorProto_FieldNumber_OneofIndex = 9, - GPBFieldDescriptorProto_FieldNumber_JsonName = 10, -}; - -/// Describes a field within a message. -@interface GPBFieldDescriptorProto : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -@property(nonatomic, readwrite) int32_t number; - -@property(nonatomic, readwrite) BOOL hasNumber; -@property(nonatomic, readwrite) GPBFieldDescriptorProto_Label label; - -@property(nonatomic, readwrite) BOOL hasLabel; -/// If type_name is set, this need not be set. If both this and type_name -/// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. -@property(nonatomic, readwrite) GPBFieldDescriptorProto_Type type; - -@property(nonatomic, readwrite) BOOL hasType; -/// For message and enum types, this is the name of the type. If the name -/// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping -/// rules are used to find the type (i.e. first the nested types within this -/// message are searched, then within the parent, on up to the root -/// namespace). -@property(nonatomic, readwrite, copy, null_resettable) NSString *typeName; -/// Test to see if @c typeName has been set. -@property(nonatomic, readwrite) BOOL hasTypeName; - -/// For extensions, this is the name of the type being extended. It is -/// resolved in the same manner as type_name. -@property(nonatomic, readwrite, copy, null_resettable) NSString *extendee; -/// Test to see if @c extendee has been set. -@property(nonatomic, readwrite) BOOL hasExtendee; - -/// For numeric types, contains the original text representation of the value. -/// For booleans, "true" or "false". -/// For strings, contains the default text contents (not escaped in any way). -/// For bytes, contains the C escaped value. All bytes >= 128 are escaped. -/// TODO(kenton): Base-64 encode? -@property(nonatomic, readwrite, copy, null_resettable) NSString *defaultValue; -/// Test to see if @c defaultValue has been set. -@property(nonatomic, readwrite) BOOL hasDefaultValue; - -/// If set, gives the index of a oneof in the containing type's oneof_decl -/// list. This field is a member of that oneof. -@property(nonatomic, readwrite) int32_t oneofIndex; - -@property(nonatomic, readwrite) BOOL hasOneofIndex; -/// JSON name of this field. The value is set by protocol compiler. If the -/// user has set a "json_name" option on this field, that option's value -/// will be used. Otherwise, it's deduced from the field's name by converting -/// it to camelCase. -@property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName; -/// Test to see if @c jsonName has been set. -@property(nonatomic, readwrite) BOOL hasJsonName; - -@property(nonatomic, readwrite, strong, null_resettable) GPBFieldOptions *options; -/// Test to see if @c options has been set. -@property(nonatomic, readwrite) BOOL hasOptions; - -@end - -#pragma mark - GPBOneofDescriptorProto - -typedef GPB_ENUM(GPBOneofDescriptorProto_FieldNumber) { - GPBOneofDescriptorProto_FieldNumber_Name = 1, -}; - -/// Describes a oneof. -@interface GPBOneofDescriptorProto : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -@end - -#pragma mark - GPBEnumDescriptorProto - -typedef GPB_ENUM(GPBEnumDescriptorProto_FieldNumber) { - GPBEnumDescriptorProto_FieldNumber_Name = 1, - GPBEnumDescriptorProto_FieldNumber_ValueArray = 2, - GPBEnumDescriptorProto_FieldNumber_Options = 3, -}; - -/// Describes an enum type. -@interface GPBEnumDescriptorProto : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valueArray; -/// The number of items in @c valueArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger valueArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) GPBEnumOptions *options; -/// Test to see if @c options has been set. -@property(nonatomic, readwrite) BOOL hasOptions; - -@end - -#pragma mark - GPBEnumValueDescriptorProto - -typedef GPB_ENUM(GPBEnumValueDescriptorProto_FieldNumber) { - GPBEnumValueDescriptorProto_FieldNumber_Name = 1, - GPBEnumValueDescriptorProto_FieldNumber_Number = 2, - GPBEnumValueDescriptorProto_FieldNumber_Options = 3, -}; - -/// Describes a value within an enum. -@interface GPBEnumValueDescriptorProto : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -@property(nonatomic, readwrite) int32_t number; - -@property(nonatomic, readwrite) BOOL hasNumber; -@property(nonatomic, readwrite, strong, null_resettable) GPBEnumValueOptions *options; -/// Test to see if @c options has been set. -@property(nonatomic, readwrite) BOOL hasOptions; - -@end - -#pragma mark - GPBServiceDescriptorProto - -typedef GPB_ENUM(GPBServiceDescriptorProto_FieldNumber) { - GPBServiceDescriptorProto_FieldNumber_Name = 1, - GPBServiceDescriptorProto_FieldNumber_MethodArray = 2, - GPBServiceDescriptorProto_FieldNumber_Options = 3, -}; - -/// Describes a service. -@interface GPBServiceDescriptorProto : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *methodArray; -/// The number of items in @c methodArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger methodArray_Count; - -@property(nonatomic, readwrite, strong, null_resettable) GPBServiceOptions *options; -/// Test to see if @c options has been set. -@property(nonatomic, readwrite) BOOL hasOptions; - -@end - -#pragma mark - GPBMethodDescriptorProto - -typedef GPB_ENUM(GPBMethodDescriptorProto_FieldNumber) { - GPBMethodDescriptorProto_FieldNumber_Name = 1, - GPBMethodDescriptorProto_FieldNumber_InputType = 2, - GPBMethodDescriptorProto_FieldNumber_OutputType = 3, - GPBMethodDescriptorProto_FieldNumber_Options = 4, - GPBMethodDescriptorProto_FieldNumber_ClientStreaming = 5, - GPBMethodDescriptorProto_FieldNumber_ServerStreaming = 6, -}; - -/// Describes a method of a service. -@interface GPBMethodDescriptorProto : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; -/// Test to see if @c name has been set. -@property(nonatomic, readwrite) BOOL hasName; - -/// Input and output type names. These are resolved in the same way as -/// FieldDescriptorProto.type_name, but must refer to a message type. -@property(nonatomic, readwrite, copy, null_resettable) NSString *inputType; -/// Test to see if @c inputType has been set. -@property(nonatomic, readwrite) BOOL hasInputType; - -@property(nonatomic, readwrite, copy, null_resettable) NSString *outputType; -/// Test to see if @c outputType has been set. -@property(nonatomic, readwrite) BOOL hasOutputType; - -@property(nonatomic, readwrite, strong, null_resettable) GPBMethodOptions *options; -/// Test to see if @c options has been set. -@property(nonatomic, readwrite) BOOL hasOptions; - -/// Identifies if client streams multiple client messages -@property(nonatomic, readwrite) BOOL clientStreaming; - -@property(nonatomic, readwrite) BOOL hasClientStreaming; -/// Identifies if server streams multiple server messages -@property(nonatomic, readwrite) BOOL serverStreaming; - -@property(nonatomic, readwrite) BOOL hasServerStreaming; -@end - -#pragma mark - GPBFileOptions - -typedef GPB_ENUM(GPBFileOptions_FieldNumber) { - GPBFileOptions_FieldNumber_JavaPackage = 1, - GPBFileOptions_FieldNumber_JavaOuterClassname = 8, - GPBFileOptions_FieldNumber_OptimizeFor = 9, - GPBFileOptions_FieldNumber_JavaMultipleFiles = 10, - GPBFileOptions_FieldNumber_GoPackage = 11, - GPBFileOptions_FieldNumber_CcGenericServices = 16, - GPBFileOptions_FieldNumber_JavaGenericServices = 17, - GPBFileOptions_FieldNumber_PyGenericServices = 18, - GPBFileOptions_FieldNumber_JavaGenerateEqualsAndHash = 20, - GPBFileOptions_FieldNumber_Deprecated = 23, - GPBFileOptions_FieldNumber_JavaStringCheckUtf8 = 27, - GPBFileOptions_FieldNumber_CcEnableArenas = 31, - GPBFileOptions_FieldNumber_ObjcClassPrefix = 36, - GPBFileOptions_FieldNumber_CsharpNamespace = 37, - GPBFileOptions_FieldNumber_JavananoUseDeprecatedPackage = 38, - GPBFileOptions_FieldNumber_UninterpretedOptionArray = 999, -}; - -@interface GPBFileOptions : GPBMessage - -/// Sets the Java package where classes generated from this .proto will be -/// placed. By default, the proto package is used, but this is often -/// inappropriate because proto packages do not normally start with backwards -/// domain names. -@property(nonatomic, readwrite, copy, null_resettable) NSString *javaPackage; -/// Test to see if @c javaPackage has been set. -@property(nonatomic, readwrite) BOOL hasJavaPackage; - -/// If set, all the classes from the .proto file are wrapped in a single -/// outer class with the given name. This applies to both Proto1 -/// (equivalent to the old "--one_java_file" option) and Proto2 (where -/// a .proto always translates to a single class, but you may want to -/// explicitly choose the class name). -@property(nonatomic, readwrite, copy, null_resettable) NSString *javaOuterClassname; -/// Test to see if @c javaOuterClassname has been set. -@property(nonatomic, readwrite) BOOL hasJavaOuterClassname; - -/// If set true, then the Java code generator will generate a separate .java -/// file for each top-level message, enum, and service defined in the .proto -/// file. Thus, these types will *not* be nested inside the outer class -/// named by java_outer_classname. However, the outer class will still be -/// generated to contain the file's getDescriptor() method as well as any -/// top-level extensions defined in the file. -@property(nonatomic, readwrite) BOOL javaMultipleFiles; - -@property(nonatomic, readwrite) BOOL hasJavaMultipleFiles; -/// If set true, then the Java code generator will generate equals() and -/// hashCode() methods for all messages defined in the .proto file. -/// This increases generated code size, potentially substantially for large -/// protos, which may harm a memory-constrained application. -/// - In the full runtime this is a speed optimization, as the -/// AbstractMessage base class includes reflection-based implementations of -/// these methods. -/// - In the lite runtime, setting this option changes the semantics of -/// equals() and hashCode() to more closely match those of the full runtime; -/// the generated methods compute their results based on field values rather -/// than object identity. (Implementations should not assume that hashcodes -/// will be consistent across runtimes or versions of the protocol compiler.) -@property(nonatomic, readwrite) BOOL javaGenerateEqualsAndHash; - -@property(nonatomic, readwrite) BOOL hasJavaGenerateEqualsAndHash; -/// If set true, then the Java2 code generator will generate code that -/// throws an exception whenever an attempt is made to assign a non-UTF-8 -/// byte sequence to a string field. -/// Message reflection will do the same. -/// However, an extension field still accepts non-UTF-8 byte sequences. -/// This option has no effect on when used with the lite runtime. -@property(nonatomic, readwrite) BOOL javaStringCheckUtf8; - -@property(nonatomic, readwrite) BOOL hasJavaStringCheckUtf8; -@property(nonatomic, readwrite) GPBFileOptions_OptimizeMode optimizeFor; - -@property(nonatomic, readwrite) BOOL hasOptimizeFor; -/// Sets the Go package where structs generated from this .proto will be -/// placed. If omitted, the Go package will be derived from the following: -/// - The basename of the package import path, if provided. -/// - Otherwise, the package statement in the .proto file, if present. -/// - Otherwise, the basename of the .proto file, without extension. -@property(nonatomic, readwrite, copy, null_resettable) NSString *goPackage; -/// Test to see if @c goPackage has been set. -@property(nonatomic, readwrite) BOOL hasGoPackage; - -/// Should generic services be generated in each language? "Generic" services -/// are not specific to any particular RPC system. They are generated by the -/// main code generators in each language (without additional plugins). -/// Generic services were the only kind of service generation supported by -/// early versions of google.protobuf. -/// -/// Generic services are now considered deprecated in favor of using plugins -/// that generate code specific to your particular RPC system. Therefore, -/// these default to false. Old code which depends on generic services should -/// explicitly set them to true. -@property(nonatomic, readwrite) BOOL ccGenericServices; - -@property(nonatomic, readwrite) BOOL hasCcGenericServices; -@property(nonatomic, readwrite) BOOL javaGenericServices; - -@property(nonatomic, readwrite) BOOL hasJavaGenericServices; -@property(nonatomic, readwrite) BOOL pyGenericServices; - -@property(nonatomic, readwrite) BOOL hasPyGenericServices; -/// Is this file deprecated? -/// Depending on the target platform, this can emit Deprecated annotations -/// for everything in the file, or it will be completely ignored; in the very -/// least, this is a formalization for deprecating files. -@property(nonatomic, readwrite) BOOL deprecated; - -@property(nonatomic, readwrite) BOOL hasDeprecated; -/// Enables the use of arenas for the proto messages in this file. This applies -/// only to generated classes for C++. -@property(nonatomic, readwrite) BOOL ccEnableArenas; - -@property(nonatomic, readwrite) BOOL hasCcEnableArenas; -/// Sets the objective c class prefix which is prepended to all objective c -/// generated classes from this .proto. There is no default. -@property(nonatomic, readwrite, copy, null_resettable) NSString *objcClassPrefix; -/// Test to see if @c objcClassPrefix has been set. -@property(nonatomic, readwrite) BOOL hasObjcClassPrefix; - -/// Namespace for generated classes; defaults to the package. -@property(nonatomic, readwrite, copy, null_resettable) NSString *csharpNamespace; -/// Test to see if @c csharpNamespace has been set. -@property(nonatomic, readwrite) BOOL hasCsharpNamespace; - -/// Whether the nano proto compiler should generate in the deprecated non-nano -/// suffixed package. -@property(nonatomic, readwrite) BOOL javananoUseDeprecatedPackage; - -@property(nonatomic, readwrite) BOOL hasJavananoUseDeprecatedPackage; -/// The parser stores options it doesn't recognize here. See above. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray; -/// The number of items in @c uninterpretedOptionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count; - -@end - -#pragma mark - GPBMessageOptions - -typedef GPB_ENUM(GPBMessageOptions_FieldNumber) { - GPBMessageOptions_FieldNumber_MessageSetWireFormat = 1, - GPBMessageOptions_FieldNumber_NoStandardDescriptorAccessor = 2, - GPBMessageOptions_FieldNumber_Deprecated = 3, - GPBMessageOptions_FieldNumber_MapEntry = 7, - GPBMessageOptions_FieldNumber_UninterpretedOptionArray = 999, -}; - -@interface GPBMessageOptions : GPBMessage - -/// Set true to use the old proto1 MessageSet wire format for extensions. -/// This is provided for backwards-compatibility with the MessageSet wire -/// format. You should not use this for any other reason: It's less -/// efficient, has fewer features, and is more complicated. -/// -/// The message must be defined exactly as follows: -/// message Foo { -/// option message_set_wire_format = true; -/// extensions 4 to max; -/// } -/// Note that the message cannot have any defined fields; MessageSets only -/// have extensions. -/// -/// All extensions of your type must be singular messages; e.g. they cannot -/// be int32s, enums, or repeated messages. -/// -/// Because this is an option, the above two restrictions are not enforced by -/// the protocol compiler. -@property(nonatomic, readwrite) BOOL messageSetWireFormat; - -@property(nonatomic, readwrite) BOOL hasMessageSetWireFormat; -/// Disables the generation of the standard "descriptor()" accessor, which can -/// conflict with a field of the same name. This is meant to make migration -/// from proto1 easier; new code should avoid fields named "descriptor". -@property(nonatomic, readwrite) BOOL noStandardDescriptorAccessor; - -@property(nonatomic, readwrite) BOOL hasNoStandardDescriptorAccessor; -/// Is this message deprecated? -/// Depending on the target platform, this can emit Deprecated annotations -/// for the message, or it will be completely ignored; in the very least, -/// this is a formalization for deprecating messages. -@property(nonatomic, readwrite) BOOL deprecated; - -@property(nonatomic, readwrite) BOOL hasDeprecated; -/// Whether the message is an automatically generated map entry type for the -/// maps field. -/// -/// For maps fields: -/// map map_field = 1; -/// The parsed descriptor looks like: -/// message MapFieldEntry { -/// option map_entry = true; -/// optional KeyType key = 1; -/// optional ValueType value = 2; -/// } -/// repeated MapFieldEntry map_field = 1; -/// -/// Implementations may choose not to generate the map_entry=true message, but -/// use a native map in the target language to hold the keys and values. -/// The reflection APIs in such implementions still need to work as -/// if the field is a repeated message field. -/// -/// NOTE: Do not set the option in .proto files. Always use the maps syntax -/// instead. The option should only be implicitly set by the proto compiler -/// parser. -@property(nonatomic, readwrite) BOOL mapEntry; - -@property(nonatomic, readwrite) BOOL hasMapEntry; -/// The parser stores options it doesn't recognize here. See above. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray; -/// The number of items in @c uninterpretedOptionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count; - -@end - -#pragma mark - GPBFieldOptions - -typedef GPB_ENUM(GPBFieldOptions_FieldNumber) { - GPBFieldOptions_FieldNumber_Ctype = 1, - GPBFieldOptions_FieldNumber_Packed = 2, - GPBFieldOptions_FieldNumber_Deprecated = 3, - GPBFieldOptions_FieldNumber_Lazy = 5, - GPBFieldOptions_FieldNumber_Jstype = 6, - GPBFieldOptions_FieldNumber_Weak = 10, - GPBFieldOptions_FieldNumber_UninterpretedOptionArray = 999, -}; - -@interface GPBFieldOptions : GPBMessage - -/// The ctype option instructs the C++ code generator to use a different -/// representation of the field than it normally would. See the specific -/// options below. This option is not yet implemented in the open source -/// release -- sorry, we'll try to include it in a future version! -@property(nonatomic, readwrite) GPBFieldOptions_CType ctype; - -@property(nonatomic, readwrite) BOOL hasCtype; -/// The packed option can be enabled for repeated primitive fields to enable -/// a more efficient representation on the wire. Rather than repeatedly -/// writing the tag and type for each element, the entire array is encoded as -/// a single length-delimited blob. In proto3, only explicit setting it to -/// false will avoid using packed encoding. -@property(nonatomic, readwrite) BOOL packed; - -@property(nonatomic, readwrite) BOOL hasPacked; -/// The jstype option determines the JavaScript type used for values of the -/// field. The option is permitted only for 64 bit integral and fixed types -/// (int64, uint64, sint64, fixed64, sfixed64). By default these types are -/// represented as JavaScript strings. This avoids loss of precision that can -/// happen when a large value is converted to a floating point JavaScript -/// numbers. Specifying JS_NUMBER for the jstype causes the generated -/// JavaScript code to use the JavaScript "number" type instead of strings. -/// This option is an enum to permit additional types to be added, -/// e.g. goog.math.Integer. -@property(nonatomic, readwrite) GPBFieldOptions_JSType jstype; - -@property(nonatomic, readwrite) BOOL hasJstype; -/// Should this field be parsed lazily? Lazy applies only to message-type -/// fields. It means that when the outer message is initially parsed, the -/// inner message's contents will not be parsed but instead stored in encoded -/// form. The inner message will actually be parsed when it is first accessed. -/// -/// This is only a hint. Implementations are free to choose whether to use -/// eager or lazy parsing regardless of the value of this option. However, -/// setting this option true suggests that the protocol author believes that -/// using lazy parsing on this field is worth the additional bookkeeping -/// overhead typically needed to implement it. -/// -/// This option does not affect the public interface of any generated code; -/// all method signatures remain the same. Furthermore, thread-safety of the -/// interface is not affected by this option; const methods remain safe to -/// call from multiple threads concurrently, while non-const methods continue -/// to require exclusive access. -/// -/// -/// Note that implementations may choose not to check required fields within -/// a lazy sub-message. That is, calling IsInitialized() on the outher message -/// may return true even if the inner message has missing required fields. -/// This is necessary because otherwise the inner message would have to be -/// parsed in order to perform the check, defeating the purpose of lazy -/// parsing. An implementation which chooses not to check required fields -/// must be consistent about it. That is, for any particular sub-message, the -/// implementation must either *always* check its required fields, or *never* -/// check its required fields, regardless of whether or not the message has -/// been parsed. -@property(nonatomic, readwrite) BOOL lazy; - -@property(nonatomic, readwrite) BOOL hasLazy; -/// Is this field deprecated? -/// Depending on the target platform, this can emit Deprecated annotations -/// for accessors, or it will be completely ignored; in the very least, this -/// is a formalization for deprecating fields. -@property(nonatomic, readwrite) BOOL deprecated; - -@property(nonatomic, readwrite) BOOL hasDeprecated; -/// For Google-internal migration only. Do not use. -@property(nonatomic, readwrite) BOOL weak; - -@property(nonatomic, readwrite) BOOL hasWeak; -/// The parser stores options it doesn't recognize here. See above. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray; -/// The number of items in @c uninterpretedOptionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count; - -@end - -#pragma mark - GPBEnumOptions - -typedef GPB_ENUM(GPBEnumOptions_FieldNumber) { - GPBEnumOptions_FieldNumber_AllowAlias = 2, - GPBEnumOptions_FieldNumber_Deprecated = 3, - GPBEnumOptions_FieldNumber_UninterpretedOptionArray = 999, -}; - -@interface GPBEnumOptions : GPBMessage - -/// Set this option to true to allow mapping different tag names to the same -/// value. -@property(nonatomic, readwrite) BOOL allowAlias; - -@property(nonatomic, readwrite) BOOL hasAllowAlias; -/// Is this enum deprecated? -/// Depending on the target platform, this can emit Deprecated annotations -/// for the enum, or it will be completely ignored; in the very least, this -/// is a formalization for deprecating enums. -@property(nonatomic, readwrite) BOOL deprecated; - -@property(nonatomic, readwrite) BOOL hasDeprecated; -/// The parser stores options it doesn't recognize here. See above. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray; -/// The number of items in @c uninterpretedOptionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count; - -@end - -#pragma mark - GPBEnumValueOptions - -typedef GPB_ENUM(GPBEnumValueOptions_FieldNumber) { - GPBEnumValueOptions_FieldNumber_Deprecated = 1, - GPBEnumValueOptions_FieldNumber_UninterpretedOptionArray = 999, -}; - -@interface GPBEnumValueOptions : GPBMessage - -/// Is this enum value deprecated? -/// Depending on the target platform, this can emit Deprecated annotations -/// for the enum value, or it will be completely ignored; in the very least, -/// this is a formalization for deprecating enum values. -@property(nonatomic, readwrite) BOOL deprecated; - -@property(nonatomic, readwrite) BOOL hasDeprecated; -/// The parser stores options it doesn't recognize here. See above. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray; -/// The number of items in @c uninterpretedOptionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count; - -@end - -#pragma mark - GPBServiceOptions - -typedef GPB_ENUM(GPBServiceOptions_FieldNumber) { - GPBServiceOptions_FieldNumber_Deprecated = 33, - GPBServiceOptions_FieldNumber_UninterpretedOptionArray = 999, -}; - -@interface GPBServiceOptions : GPBMessage - -/// Is this service deprecated? -/// Depending on the target platform, this can emit Deprecated annotations -/// for the service, or it will be completely ignored; in the very least, -/// this is a formalization for deprecating services. -@property(nonatomic, readwrite) BOOL deprecated; - -@property(nonatomic, readwrite) BOOL hasDeprecated; -/// The parser stores options it doesn't recognize here. See above. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray; -/// The number of items in @c uninterpretedOptionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count; - -@end - -#pragma mark - GPBMethodOptions - -typedef GPB_ENUM(GPBMethodOptions_FieldNumber) { - GPBMethodOptions_FieldNumber_Deprecated = 33, - GPBMethodOptions_FieldNumber_UninterpretedOptionArray = 999, -}; - -@interface GPBMethodOptions : GPBMessage - -/// Is this method deprecated? -/// Depending on the target platform, this can emit Deprecated annotations -/// for the method, or it will be completely ignored; in the very least, -/// this is a formalization for deprecating methods. -@property(nonatomic, readwrite) BOOL deprecated; - -@property(nonatomic, readwrite) BOOL hasDeprecated; -/// The parser stores options it doesn't recognize here. See above. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *uninterpretedOptionArray; -/// The number of items in @c uninterpretedOptionArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger uninterpretedOptionArray_Count; - -@end - -#pragma mark - GPBUninterpretedOption - -typedef GPB_ENUM(GPBUninterpretedOption_FieldNumber) { - GPBUninterpretedOption_FieldNumber_NameArray = 2, - GPBUninterpretedOption_FieldNumber_IdentifierValue = 3, - GPBUninterpretedOption_FieldNumber_PositiveIntValue = 4, - GPBUninterpretedOption_FieldNumber_NegativeIntValue = 5, - GPBUninterpretedOption_FieldNumber_DoubleValue = 6, - GPBUninterpretedOption_FieldNumber_StringValue = 7, - GPBUninterpretedOption_FieldNumber_AggregateValue = 8, -}; - -/// A message representing a option the parser does not recognize. This only -/// appears in options protos created by the compiler::Parser class. -/// DescriptorPool resolves these when building Descriptor objects. Therefore, -/// options protos in descriptor objects (e.g. returned by Descriptor::options(), -/// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -/// in them. -@interface GPBUninterpretedOption : GPBMessage - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nameArray; -/// The number of items in @c nameArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger nameArray_Count; - -/// The value of the uninterpreted option, in whatever type the tokenizer -/// identified it as during parsing. Exactly one of these should be set. -@property(nonatomic, readwrite, copy, null_resettable) NSString *identifierValue; -/// Test to see if @c identifierValue has been set. -@property(nonatomic, readwrite) BOOL hasIdentifierValue; - -@property(nonatomic, readwrite) uint64_t positiveIntValue; - -@property(nonatomic, readwrite) BOOL hasPositiveIntValue; -@property(nonatomic, readwrite) int64_t negativeIntValue; - -@property(nonatomic, readwrite) BOOL hasNegativeIntValue; -@property(nonatomic, readwrite) double doubleValue; - -@property(nonatomic, readwrite) BOOL hasDoubleValue; -@property(nonatomic, readwrite, copy, null_resettable) NSData *stringValue; -/// Test to see if @c stringValue has been set. -@property(nonatomic, readwrite) BOOL hasStringValue; - -@property(nonatomic, readwrite, copy, null_resettable) NSString *aggregateValue; -/// Test to see if @c aggregateValue has been set. -@property(nonatomic, readwrite) BOOL hasAggregateValue; - -@end - -#pragma mark - GPBUninterpretedOption_NamePart - -typedef GPB_ENUM(GPBUninterpretedOption_NamePart_FieldNumber) { - GPBUninterpretedOption_NamePart_FieldNumber_NamePart = 1, - GPBUninterpretedOption_NamePart_FieldNumber_IsExtension = 2, -}; - -/// The name of the uninterpreted option. Each string represents a segment in -/// a dot-separated name. is_extension is true iff a segment represents an -/// extension (denoted with parentheses in options specs in .proto files). -/// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents -/// "foo.(bar.baz).qux". -@interface GPBUninterpretedOption_NamePart : GPBMessage - -@property(nonatomic, readwrite, copy, null_resettable) NSString *namePart; -/// Test to see if @c namePart has been set. -@property(nonatomic, readwrite) BOOL hasNamePart; - -@property(nonatomic, readwrite) BOOL isExtension; - -@property(nonatomic, readwrite) BOOL hasIsExtension; -@end - -#pragma mark - GPBSourceCodeInfo - -typedef GPB_ENUM(GPBSourceCodeInfo_FieldNumber) { - GPBSourceCodeInfo_FieldNumber_LocationArray = 1, -}; - -/// Encapsulates information about the original source file from which a -/// FileDescriptorProto was generated. -@interface GPBSourceCodeInfo : GPBMessage - -/// A Location identifies a piece of source code in a .proto file which -/// corresponds to a particular definition. This information is intended -/// to be useful to IDEs, code indexers, documentation generators, and similar -/// tools. -/// -/// For example, say we have a file like: -/// message Foo { -/// optional string foo = 1; -/// } -/// Let's look at just the field definition: -/// optional string foo = 1; -/// ^ ^^ ^^ ^ ^^^ -/// a bc de f ghi -/// We have the following locations: -/// span path represents -/// [a,i) [ 4, 0, 2, 0 ] The whole field definition. -/// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). -/// [c,d) [ 4, 0, 2, 0, 5 ] The type (string). -/// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). -/// [g,h) [ 4, 0, 2, 0, 3 ] The number (1). -/// -/// Notes: -/// - A location may refer to a repeated field itself (i.e. not to any -/// particular index within it). This is used whenever a set of elements are -/// logically enclosed in a single code segment. For example, an entire -/// extend block (possibly containing multiple extension definitions) will -/// have an outer location whose path refers to the "extensions" repeated -/// field without an index. -/// - Multiple locations may have the same path. This happens when a single -/// logical declaration is spread out across multiple places. The most -/// obvious example is the "extend" block again -- there may be multiple -/// extend blocks in the same scope, each of which will have the same path. -/// - A location's span is not always a subset of its parent's span. For -/// example, the "extendee" of an extension declaration appears at the -/// beginning of the "extend" block and is shared by all extensions within -/// the block. -/// - Just because a location's span is a subset of some other location's span -/// does not mean that it is a descendent. For example, a "group" defines -/// both a type and a field in a single declaration. Thus, the locations -/// corresponding to the type and field and their components will overlap. -/// - Code which tries to interpret locations should probably be designed to -/// ignore those that it doesn't understand, as more types of locations could -/// be recorded in the future. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *locationArray; -/// The number of items in @c locationArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger locationArray_Count; - -@end - -#pragma mark - GPBSourceCodeInfo_Location - -typedef GPB_ENUM(GPBSourceCodeInfo_Location_FieldNumber) { - GPBSourceCodeInfo_Location_FieldNumber_PathArray = 1, - GPBSourceCodeInfo_Location_FieldNumber_SpanArray = 2, - GPBSourceCodeInfo_Location_FieldNumber_LeadingComments = 3, - GPBSourceCodeInfo_Location_FieldNumber_TrailingComments = 4, - GPBSourceCodeInfo_Location_FieldNumber_LeadingDetachedCommentsArray = 6, -}; - -@interface GPBSourceCodeInfo_Location : GPBMessage - -/// Identifies which part of the FileDescriptorProto was defined at this -/// location. -/// -/// Each element is a field number or an index. They form a path from -/// the root FileDescriptorProto to the place where the definition. For -/// example, this path: -/// [ 4, 3, 2, 7, 1 ] -/// refers to: -/// file.message_type(3) // 4, 3 -/// .field(7) // 2, 7 -/// .name() // 1 -/// This is because FileDescriptorProto.message_type has field number 4: -/// repeated DescriptorProto message_type = 4; -/// and DescriptorProto.field has field number 2: -/// repeated FieldDescriptorProto field = 2; -/// and FieldDescriptorProto.name has field number 1: -/// optional string name = 1; -/// -/// Thus, the above path gives the location of a field name. If we removed -/// the last element: -/// [ 4, 3, 2, 7 ] -/// this path refers to the whole field declaration (from the beginning -/// of the label to the terminating semicolon). -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *pathArray; -/// The number of items in @c pathArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger pathArray_Count; - -/// Always has exactly three or four elements: start line, start column, -/// end line (optional, otherwise assumed same as start line), end column. -/// These are packed into a single field for efficiency. Note that line -/// and column numbers are zero-based -- typically you will want to add -/// 1 to each before displaying to a user. -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *spanArray; -/// The number of items in @c spanArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger spanArray_Count; - -/// If this SourceCodeInfo represents a complete declaration, these are any -/// comments appearing before and after the declaration which appear to be -/// attached to the declaration. -/// -/// A series of line comments appearing on consecutive lines, with no other -/// tokens appearing on those lines, will be treated as a single comment. -/// -/// leading_detached_comments will keep paragraphs of comments that appear -/// before (but not connected to) the current element. Each paragraph, -/// separated by empty lines, will be one comment element in the repeated -/// field. -/// -/// Only the comment content is provided; comment markers (e.g. //) are -/// stripped out. For block comments, leading whitespace and an asterisk -/// will be stripped from the beginning of each line other than the first. -/// Newlines are included in the output. -/// -/// Examples: -/// -/// optional int32 foo = 1; // Comment attached to foo. -/// // Comment attached to bar. -/// optional int32 bar = 2; -/// -/// optional string baz = 3; -/// // Comment attached to baz. -/// // Another line attached to baz. -/// -/// // Comment attached to qux. -/// // -/// // Another line attached to qux. -/// optional double qux = 4; -/// -/// // Detached comment for corge. This is not leading or trailing comments -/// // to qux or corge because there are blank lines separating it from -/// // both. -/// -/// // Detached comment for corge paragraph 2. -/// -/// optional string corge = 5; -/// /* Block comment attached -/// * to corge. Leading asterisks -/// * will be removed. */ -/// /* Block comment attached to -/// * grault. */ -/// optional int32 grault = 6; -/// -/// // ignored detached comments. -@property(nonatomic, readwrite, copy, null_resettable) NSString *leadingComments; -/// Test to see if @c leadingComments has been set. -@property(nonatomic, readwrite) BOOL hasLeadingComments; - -@property(nonatomic, readwrite, copy, null_resettable) NSString *trailingComments; -/// Test to see if @c trailingComments has been set. -@property(nonatomic, readwrite) BOOL hasTrailingComments; - -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *leadingDetachedCommentsArray; -/// The number of items in @c leadingDetachedCommentsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger leadingDetachedCommentsArray_Count; - -@end - -#pragma mark - GPBGeneratedCodeInfo - -typedef GPB_ENUM(GPBGeneratedCodeInfo_FieldNumber) { - GPBGeneratedCodeInfo_FieldNumber_AnnotationArray = 1, -}; - -/// Describes the relationship between generated code and its original source -/// file. A GeneratedCodeInfo message is associated with only one generated -/// source file, but may contain references to different source .proto files. -@interface GPBGeneratedCodeInfo : GPBMessage - -/// An Annotation connects some span of text in generated code to an element -/// of its generating .proto file. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *annotationArray; -/// The number of items in @c annotationArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger annotationArray_Count; - -@end - -#pragma mark - GPBGeneratedCodeInfo_Annotation - -typedef GPB_ENUM(GPBGeneratedCodeInfo_Annotation_FieldNumber) { - GPBGeneratedCodeInfo_Annotation_FieldNumber_PathArray = 1, - GPBGeneratedCodeInfo_Annotation_FieldNumber_SourceFile = 2, - GPBGeneratedCodeInfo_Annotation_FieldNumber_Begin = 3, - GPBGeneratedCodeInfo_Annotation_FieldNumber_End = 4, -}; - -@interface GPBGeneratedCodeInfo_Annotation : GPBMessage - -/// Identifies the element in the original source .proto file. This field -/// is formatted the same as SourceCodeInfo.Location.path. -@property(nonatomic, readwrite, strong, null_resettable) GPBInt32Array *pathArray; -/// The number of items in @c pathArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger pathArray_Count; - -/// Identifies the filesystem path to the original source .proto. -@property(nonatomic, readwrite, copy, null_resettable) NSString *sourceFile; -/// Test to see if @c sourceFile has been set. -@property(nonatomic, readwrite) BOOL hasSourceFile; - -/// Identifies the starting offset in bytes in the generated code -/// that relates to the identified object. -@property(nonatomic, readwrite) int32_t begin; - -@property(nonatomic, readwrite) BOOL hasBegin; -/// Identifies the ending offset in bytes in the generated code that -/// relates to the identified offset. The end offset should be one past -/// the last relevant byte (so the length of the text = end - begin). -@property(nonatomic, readwrite) int32_t end; - -@property(nonatomic, readwrite) BOOL hasEnd; -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Descriptor.pbobjc.m b/objectivec/google/protobuf/Descriptor.pbobjc.m deleted file mode 100644 index 40309893..00000000 --- a/objectivec/google/protobuf/Descriptor.pbobjc.m +++ /dev/null @@ -1,2594 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/descriptor.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Descriptor.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma mark - GPBDescriptorRoot - -@implementation GPBDescriptorRoot - -@end - -#pragma mark - GPBDescriptorRoot_FileDescriptor - -static GPBFileDescriptor *GPBDescriptorRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto2]; - } - return descriptor; -} - -#pragma mark - GPBFileDescriptorSet - -@implementation GPBFileDescriptorSet - -@dynamic fileArray, fileArray_Count; - -typedef struct GPBFileDescriptorSet__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *fileArray; -} GPBFileDescriptorSet__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fileArray", - .number = GPBFileDescriptorSet_FieldNumber_FileArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileDescriptorSet__storage_, fileArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBFileDescriptorProto), - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBFileDescriptorSet class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBFileDescriptorSet__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBFileDescriptorProto - -@implementation GPBFileDescriptorProto - -@dynamic hasName, name; -@dynamic hasPackage, package; -@dynamic dependencyArray, dependencyArray_Count; -@dynamic publicDependencyArray, publicDependencyArray_Count; -@dynamic weakDependencyArray, weakDependencyArray_Count; -@dynamic messageTypeArray, messageTypeArray_Count; -@dynamic enumTypeArray, enumTypeArray_Count; -@dynamic serviceArray, serviceArray_Count; -@dynamic extensionArray, extensionArray_Count; -@dynamic hasOptions, options; -@dynamic hasSourceCodeInfo, sourceCodeInfo; -@dynamic hasSyntax, syntax; - -typedef struct GPBFileDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - NSString *package; - NSMutableArray *dependencyArray; - NSMutableArray *messageTypeArray; - NSMutableArray *enumTypeArray; - NSMutableArray *serviceArray; - NSMutableArray *extensionArray; - GPBFileOptions *options; - GPBSourceCodeInfo *sourceCodeInfo; - GPBInt32Array *publicDependencyArray; - GPBInt32Array *weakDependencyArray; - NSString *syntax; -} GPBFileDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBFileDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "package", - .number = GPBFileDescriptorProto_FieldNumber_Package, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileDescriptorProto__storage_, package), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "dependencyArray", - .number = GPBFileDescriptorProto_FieldNumber_DependencyArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileDescriptorProto__storage_, dependencyArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "messageTypeArray", - .number = GPBFileDescriptorProto_FieldNumber_MessageTypeArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileDescriptorProto__storage_, messageTypeArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "enumTypeArray", - .number = GPBFileDescriptorProto_FieldNumber_EnumTypeArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileDescriptorProto__storage_, enumTypeArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "serviceArray", - .number = GPBFileDescriptorProto_FieldNumber_ServiceArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileDescriptorProto__storage_, serviceArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBServiceDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "extensionArray", - .number = GPBFileDescriptorProto_FieldNumber_ExtensionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileDescriptorProto__storage_, extensionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "options", - .number = GPBFileDescriptorProto_FieldNumber_Options, - .hasIndex = 9, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileDescriptorProto__storage_, options), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBFileOptions), - .fieldOptions = NULL, - }, - { - .name = "sourceCodeInfo", - .number = GPBFileDescriptorProto_FieldNumber_SourceCodeInfo, - .hasIndex = 10, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileDescriptorProto__storage_, sourceCodeInfo), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceCodeInfo), - .fieldOptions = NULL, - }, - { - .name = "publicDependencyArray", - .number = GPBFileDescriptorProto_FieldNumber_PublicDependencyArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBFileDescriptorProto__storage_, publicDependencyArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "weakDependencyArray", - .number = GPBFileDescriptorProto_FieldNumber_WeakDependencyArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBFileDescriptorProto__storage_, weakDependencyArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "syntax", - .number = GPBFileDescriptorProto_FieldNumber_Syntax, - .hasIndex = 11, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileDescriptorProto__storage_, syntax), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBFileDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBFileDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBDescriptorProto - -@implementation GPBDescriptorProto - -@dynamic hasName, name; -@dynamic fieldArray, fieldArray_Count; -@dynamic extensionArray, extensionArray_Count; -@dynamic nestedTypeArray, nestedTypeArray_Count; -@dynamic enumTypeArray, enumTypeArray_Count; -@dynamic extensionRangeArray, extensionRangeArray_Count; -@dynamic oneofDeclArray, oneofDeclArray_Count; -@dynamic hasOptions, options; -@dynamic reservedRangeArray, reservedRangeArray_Count; -@dynamic reservedNameArray, reservedNameArray_Count; - -typedef struct GPBDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - NSMutableArray *fieldArray; - NSMutableArray *nestedTypeArray; - NSMutableArray *enumTypeArray; - NSMutableArray *extensionRangeArray; - NSMutableArray *extensionArray; - GPBMessageOptions *options; - NSMutableArray *oneofDeclArray; - NSMutableArray *reservedRangeArray; - NSMutableArray *reservedNameArray; -} GPBDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "fieldArray", - .number = GPBDescriptorProto_FieldNumber_FieldArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, fieldArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "nestedTypeArray", - .number = GPBDescriptorProto_FieldNumber_NestedTypeArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, nestedTypeArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "enumTypeArray", - .number = GPBDescriptorProto_FieldNumber_EnumTypeArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, enumTypeArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "extensionRangeArray", - .number = GPBDescriptorProto_FieldNumber_ExtensionRangeArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, extensionRangeArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto_ExtensionRange), - .fieldOptions = NULL, - }, - { - .name = "extensionArray", - .number = GPBDescriptorProto_FieldNumber_ExtensionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, extensionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "options", - .number = GPBDescriptorProto_FieldNumber_Options, - .hasIndex = 7, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, options), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBMessageOptions), - .fieldOptions = NULL, - }, - { - .name = "oneofDeclArray", - .number = GPBDescriptorProto_FieldNumber_OneofDeclArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, oneofDeclArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBOneofDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "reservedRangeArray", - .number = GPBDescriptorProto_FieldNumber_ReservedRangeArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBDescriptorProto__storage_, reservedRangeArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBDescriptorProto_ReservedRange), - .fieldOptions = NULL, - }, - { - .name = "reservedNameArray", - .number = GPBDescriptorProto_FieldNumber_ReservedNameArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBDescriptorProto__storage_, reservedNameArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBDescriptorProto_ExtensionRange - -@implementation GPBDescriptorProto_ExtensionRange - -@dynamic hasStart, start; -@dynamic hasEnd, end; - -typedef struct GPBDescriptorProto_ExtensionRange__storage_ { - uint32_t _has_storage_[1]; - int32_t start; - int32_t end; -} GPBDescriptorProto_ExtensionRange__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "start", - .number = GPBDescriptorProto_ExtensionRange_FieldNumber_Start, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBDescriptorProto_ExtensionRange__storage_, start), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "end", - .number = GPBDescriptorProto_ExtensionRange_FieldNumber_End, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBDescriptorProto_ExtensionRange__storage_, end), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto_ExtensionRange class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBDescriptorProto_ExtensionRange__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBDescriptorProto_ReservedRange - -@implementation GPBDescriptorProto_ReservedRange - -@dynamic hasStart, start; -@dynamic hasEnd, end; - -typedef struct GPBDescriptorProto_ReservedRange__storage_ { - uint32_t _has_storage_[1]; - int32_t start; - int32_t end; -} GPBDescriptorProto_ReservedRange__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "start", - .number = GPBDescriptorProto_ReservedRange_FieldNumber_Start, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBDescriptorProto_ReservedRange__storage_, start), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "end", - .number = GPBDescriptorProto_ReservedRange_FieldNumber_End, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBDescriptorProto_ReservedRange__storage_, end), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBDescriptorProto_ReservedRange class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBDescriptorProto_ReservedRange__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBFieldDescriptorProto - -@implementation GPBFieldDescriptorProto - -@dynamic hasName, name; -@dynamic hasNumber, number; -@dynamic hasLabel, label; -@dynamic hasType, type; -@dynamic hasTypeName, typeName; -@dynamic hasExtendee, extendee; -@dynamic hasDefaultValue, defaultValue; -@dynamic hasOneofIndex, oneofIndex; -@dynamic hasJsonName, jsonName; -@dynamic hasOptions, options; - -typedef struct GPBFieldDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - int32_t number; - GPBFieldDescriptorProto_Label label; - GPBFieldDescriptorProto_Type type; - int32_t oneofIndex; - NSString *name; - NSString *extendee; - NSString *typeName; - NSString *defaultValue; - GPBFieldOptions *options; - NSString *jsonName; -} GPBFieldDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBFieldDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFieldDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "extendee", - .number = GPBFieldDescriptorProto_FieldNumber_Extendee, - .hasIndex = 5, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFieldDescriptorProto__storage_, extendee), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "number", - .number = GPBFieldDescriptorProto_FieldNumber_Number, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBFieldDescriptorProto__storage_, number), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "label", - .number = GPBFieldDescriptorProto_FieldNumber_Label, - .hasIndex = 2, - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBFieldDescriptorProto__storage_, label), - .defaultValue.valueEnum = GPBFieldDescriptorProto_Label_LabelOptional, - .dataTypeSpecific.enumDescFunc = GPBFieldDescriptorProto_Label_EnumDescriptor, - .fieldOptions = NULL, - }, - { - .name = "type", - .number = GPBFieldDescriptorProto_FieldNumber_Type, - .hasIndex = 3, - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBFieldDescriptorProto__storage_, type), - .defaultValue.valueEnum = GPBFieldDescriptorProto_Type_TypeDouble, - .dataTypeSpecific.enumDescFunc = GPBFieldDescriptorProto_Type_EnumDescriptor, - .fieldOptions = NULL, - }, - { - .name = "typeName", - .number = GPBFieldDescriptorProto_FieldNumber_TypeName, - .hasIndex = 4, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFieldDescriptorProto__storage_, typeName), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "defaultValue", - .number = GPBFieldDescriptorProto_FieldNumber_DefaultValue, - .hasIndex = 6, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFieldDescriptorProto__storage_, defaultValue), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "options", - .number = GPBFieldDescriptorProto_FieldNumber_Options, - .hasIndex = 9, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFieldDescriptorProto__storage_, options), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBFieldOptions), - .fieldOptions = NULL, - }, - { - .name = "oneofIndex", - .number = GPBFieldDescriptorProto_FieldNumber_OneofIndex, - .hasIndex = 7, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBFieldDescriptorProto__storage_, oneofIndex), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "jsonName", - .number = GPBFieldDescriptorProto_FieldNumber_JsonName, - .hasIndex = 8, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFieldDescriptorProto__storage_, jsonName), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - static GPBMessageEnumDescription enums[] = { - { .enumDescriptorFunc = GPBFieldDescriptorProto_Type_EnumDescriptor }, - { .enumDescriptorFunc = GPBFieldDescriptorProto_Label_EnumDescriptor }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBFieldDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:enums - enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription) - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBFieldDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - Enum GPBFieldDescriptorProto_Type - -GPBEnumDescriptor *GPBFieldDescriptorProto_Type_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "TypeDouble", .number = GPBFieldDescriptorProto_Type_TypeDouble }, - { .name = "TypeFloat", .number = GPBFieldDescriptorProto_Type_TypeFloat }, - { .name = "TypeInt64", .number = GPBFieldDescriptorProto_Type_TypeInt64 }, - { .name = "TypeUint64", .number = GPBFieldDescriptorProto_Type_TypeUint64 }, - { .name = "TypeInt32", .number = GPBFieldDescriptorProto_Type_TypeInt32 }, - { .name = "TypeFixed64", .number = GPBFieldDescriptorProto_Type_TypeFixed64 }, - { .name = "TypeFixed32", .number = GPBFieldDescriptorProto_Type_TypeFixed32 }, - { .name = "TypeBool", .number = GPBFieldDescriptorProto_Type_TypeBool }, - { .name = "TypeString", .number = GPBFieldDescriptorProto_Type_TypeString }, - { .name = "TypeGroup", .number = GPBFieldDescriptorProto_Type_TypeGroup }, - { .name = "TypeMessage", .number = GPBFieldDescriptorProto_Type_TypeMessage }, - { .name = "TypeBytes", .number = GPBFieldDescriptorProto_Type_TypeBytes }, - { .name = "TypeUint32", .number = GPBFieldDescriptorProto_Type_TypeUint32 }, - { .name = "TypeEnum", .number = GPBFieldDescriptorProto_Type_TypeEnum }, - { .name = "TypeSfixed32", .number = GPBFieldDescriptorProto_Type_TypeSfixed32 }, - { .name = "TypeSfixed64", .number = GPBFieldDescriptorProto_Type_TypeSfixed64 }, - { .name = "TypeSint32", .number = GPBFieldDescriptorProto_Type_TypeSint32 }, - { .name = "TypeSint64", .number = GPBFieldDescriptorProto_Type_TypeSint64 }, - }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldDescriptorProto_Type) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBFieldDescriptorProto_Type_IsValidValue]; - } - return descriptor; -} - -BOOL GPBFieldDescriptorProto_Type_IsValidValue(int32_t value__) { - switch (value__) { - case GPBFieldDescriptorProto_Type_TypeDouble: - case GPBFieldDescriptorProto_Type_TypeFloat: - case GPBFieldDescriptorProto_Type_TypeInt64: - case GPBFieldDescriptorProto_Type_TypeUint64: - case GPBFieldDescriptorProto_Type_TypeInt32: - case GPBFieldDescriptorProto_Type_TypeFixed64: - case GPBFieldDescriptorProto_Type_TypeFixed32: - case GPBFieldDescriptorProto_Type_TypeBool: - case GPBFieldDescriptorProto_Type_TypeString: - case GPBFieldDescriptorProto_Type_TypeGroup: - case GPBFieldDescriptorProto_Type_TypeMessage: - case GPBFieldDescriptorProto_Type_TypeBytes: - case GPBFieldDescriptorProto_Type_TypeUint32: - case GPBFieldDescriptorProto_Type_TypeEnum: - case GPBFieldDescriptorProto_Type_TypeSfixed32: - case GPBFieldDescriptorProto_Type_TypeSfixed64: - case GPBFieldDescriptorProto_Type_TypeSint32: - case GPBFieldDescriptorProto_Type_TypeSint64: - return YES; - default: - return NO; - } -} - -#pragma mark - Enum GPBFieldDescriptorProto_Label - -GPBEnumDescriptor *GPBFieldDescriptorProto_Label_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "LabelOptional", .number = GPBFieldDescriptorProto_Label_LabelOptional }, - { .name = "LabelRequired", .number = GPBFieldDescriptorProto_Label_LabelRequired }, - { .name = "LabelRepeated", .number = GPBFieldDescriptorProto_Label_LabelRepeated }, - }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldDescriptorProto_Label) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBFieldDescriptorProto_Label_IsValidValue]; - } - return descriptor; -} - -BOOL GPBFieldDescriptorProto_Label_IsValidValue(int32_t value__) { - switch (value__) { - case GPBFieldDescriptorProto_Label_LabelOptional: - case GPBFieldDescriptorProto_Label_LabelRequired: - case GPBFieldDescriptorProto_Label_LabelRepeated: - return YES; - default: - return NO; - } -} - -#pragma mark - GPBOneofDescriptorProto - -@implementation GPBOneofDescriptorProto - -@dynamic hasName, name; - -typedef struct GPBOneofDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - NSString *name; -} GPBOneofDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBOneofDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBOneofDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBOneofDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBOneofDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBEnumDescriptorProto - -@implementation GPBEnumDescriptorProto - -@dynamic hasName, name; -@dynamic valueArray, valueArray_Count; -@dynamic hasOptions, options; - -typedef struct GPBEnumDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - NSMutableArray *valueArray; - GPBEnumOptions *options; -} GPBEnumDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBEnumDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBEnumDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "valueArray", - .number = GPBEnumDescriptorProto_FieldNumber_ValueArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnumDescriptorProto__storage_, valueArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValueDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "options", - .number = GPBEnumDescriptorProto_FieldNumber_Options, - .hasIndex = 2, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnumDescriptorProto__storage_, options), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumOptions), - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBEnumDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBEnumDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBEnumValueDescriptorProto - -@implementation GPBEnumValueDescriptorProto - -@dynamic hasName, name; -@dynamic hasNumber, number; -@dynamic hasOptions, options; - -typedef struct GPBEnumValueDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - int32_t number; - NSString *name; - GPBEnumValueOptions *options; -} GPBEnumValueDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBEnumValueDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBEnumValueDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "number", - .number = GPBEnumValueDescriptorProto_FieldNumber_Number, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBEnumValueDescriptorProto__storage_, number), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "options", - .number = GPBEnumValueDescriptorProto_FieldNumber_Options, - .hasIndex = 2, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnumValueDescriptorProto__storage_, options), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValueOptions), - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBEnumValueDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBEnumValueDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBServiceDescriptorProto - -@implementation GPBServiceDescriptorProto - -@dynamic hasName, name; -@dynamic methodArray, methodArray_Count; -@dynamic hasOptions, options; - -typedef struct GPBServiceDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - NSMutableArray *methodArray; - GPBServiceOptions *options; -} GPBServiceDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBServiceDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBServiceDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "methodArray", - .number = GPBServiceDescriptorProto_FieldNumber_MethodArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBServiceDescriptorProto__storage_, methodArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBMethodDescriptorProto), - .fieldOptions = NULL, - }, - { - .name = "options", - .number = GPBServiceDescriptorProto_FieldNumber_Options, - .hasIndex = 2, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBServiceDescriptorProto__storage_, options), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBServiceOptions), - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBServiceDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBServiceDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBMethodDescriptorProto - -@implementation GPBMethodDescriptorProto - -@dynamic hasName, name; -@dynamic hasInputType, inputType; -@dynamic hasOutputType, outputType; -@dynamic hasOptions, options; -@dynamic hasClientStreaming, clientStreaming; -@dynamic hasServerStreaming, serverStreaming; - -typedef struct GPBMethodDescriptorProto__storage_ { - uint32_t _has_storage_[1]; - BOOL clientStreaming; - BOOL serverStreaming; - NSString *name; - NSString *inputType; - NSString *outputType; - GPBMethodOptions *options; -} GPBMethodDescriptorProto__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .number = GPBMethodDescriptorProto_FieldNumber_Name, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBMethodDescriptorProto__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "inputType", - .number = GPBMethodDescriptorProto_FieldNumber_InputType, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBMethodDescriptorProto__storage_, inputType), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "outputType", - .number = GPBMethodDescriptorProto_FieldNumber_OutputType, - .hasIndex = 2, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBMethodDescriptorProto__storage_, outputType), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "options", - .number = GPBMethodDescriptorProto_FieldNumber_Options, - .hasIndex = 3, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBMethodDescriptorProto__storage_, options), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBMethodOptions), - .fieldOptions = NULL, - }, - { - .name = "clientStreaming", - .number = GPBMethodDescriptorProto_FieldNumber_ClientStreaming, - .hasIndex = 4, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMethodDescriptorProto__storage_, clientStreaming), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "serverStreaming", - .number = GPBMethodDescriptorProto_FieldNumber_ServerStreaming, - .hasIndex = 5, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMethodDescriptorProto__storage_, serverStreaming), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBMethodDescriptorProto class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBMethodDescriptorProto__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBFileOptions - -@implementation GPBFileOptions - -@dynamic hasJavaPackage, javaPackage; -@dynamic hasJavaOuterClassname, javaOuterClassname; -@dynamic hasJavaMultipleFiles, javaMultipleFiles; -@dynamic hasJavaGenerateEqualsAndHash, javaGenerateEqualsAndHash; -@dynamic hasJavaStringCheckUtf8, javaStringCheckUtf8; -@dynamic hasOptimizeFor, optimizeFor; -@dynamic hasGoPackage, goPackage; -@dynamic hasCcGenericServices, ccGenericServices; -@dynamic hasJavaGenericServices, javaGenericServices; -@dynamic hasPyGenericServices, pyGenericServices; -@dynamic hasDeprecated, deprecated; -@dynamic hasCcEnableArenas, ccEnableArenas; -@dynamic hasObjcClassPrefix, objcClassPrefix; -@dynamic hasCsharpNamespace, csharpNamespace; -@dynamic hasJavananoUseDeprecatedPackage, javananoUseDeprecatedPackage; -@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count; - -typedef struct GPBFileOptions__storage_ { - uint32_t _has_storage_[1]; - BOOL javaMultipleFiles; - BOOL ccGenericServices; - BOOL javaGenericServices; - BOOL pyGenericServices; - BOOL javaGenerateEqualsAndHash; - BOOL deprecated; - BOOL javaStringCheckUtf8; - BOOL ccEnableArenas; - BOOL javananoUseDeprecatedPackage; - GPBFileOptions_OptimizeMode optimizeFor; - NSString *javaPackage; - NSString *javaOuterClassname; - NSString *goPackage; - NSString *objcClassPrefix; - NSString *csharpNamespace; - NSMutableArray *uninterpretedOptionArray; -} GPBFileOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "javaPackage", - .number = GPBFileOptions_FieldNumber_JavaPackage, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileOptions__storage_, javaPackage), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "javaOuterClassname", - .number = GPBFileOptions_FieldNumber_JavaOuterClassname, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileOptions__storage_, javaOuterClassname), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "optimizeFor", - .number = GPBFileOptions_FieldNumber_OptimizeFor, - .hasIndex = 5, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBFileOptions__storage_, optimizeFor), - .defaultValue.valueEnum = GPBFileOptions_OptimizeMode_Speed, - .dataTypeSpecific.enumDescFunc = GPBFileOptions_OptimizeMode_EnumDescriptor, - .fieldOptions = NULL, - }, - { - .name = "javaMultipleFiles", - .number = GPBFileOptions_FieldNumber_JavaMultipleFiles, - .hasIndex = 2, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, javaMultipleFiles), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "goPackage", - .number = GPBFileOptions_FieldNumber_GoPackage, - .hasIndex = 6, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileOptions__storage_, goPackage), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "ccGenericServices", - .number = GPBFileOptions_FieldNumber_CcGenericServices, - .hasIndex = 7, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, ccGenericServices), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "javaGenericServices", - .number = GPBFileOptions_FieldNumber_JavaGenericServices, - .hasIndex = 8, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, javaGenericServices), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "pyGenericServices", - .number = GPBFileOptions_FieldNumber_PyGenericServices, - .hasIndex = 9, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, pyGenericServices), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "javaGenerateEqualsAndHash", - .number = GPBFileOptions_FieldNumber_JavaGenerateEqualsAndHash, - .hasIndex = 3, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, javaGenerateEqualsAndHash), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "deprecated", - .number = GPBFileOptions_FieldNumber_Deprecated, - .hasIndex = 10, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, deprecated), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "javaStringCheckUtf8", - .number = GPBFileOptions_FieldNumber_JavaStringCheckUtf8, - .hasIndex = 4, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, javaStringCheckUtf8), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "ccEnableArenas", - .number = GPBFileOptions_FieldNumber_CcEnableArenas, - .hasIndex = 11, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, ccEnableArenas), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "objcClassPrefix", - .number = GPBFileOptions_FieldNumber_ObjcClassPrefix, - .hasIndex = 12, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileOptions__storage_, objcClassPrefix), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "csharpNamespace", - .number = GPBFileOptions_FieldNumber_CsharpNamespace, - .hasIndex = 13, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBFileOptions__storage_, csharpNamespace), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "javananoUseDeprecatedPackage", - .number = GPBFileOptions_FieldNumber_JavananoUseDeprecatedPackage, - .hasIndex = 14, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFileOptions__storage_, javananoUseDeprecatedPackage), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - #if GPBOBJC_INCLUDE_FIELD_OPTIONS - .fieldOptions = "\000\000\000\002\030\001", - #else - .fieldOptions = NULL, - #endif // GPBOBJC_INCLUDE_FIELD_OPTIONS - }, - { - .name = "uninterpretedOptionArray", - .number = GPBFileOptions_FieldNumber_UninterpretedOptionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFileOptions__storage_, uninterpretedOptionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), - .fieldOptions = NULL, - }, - }; - static GPBMessageEnumDescription enums[] = { - { .enumDescriptorFunc = GPBFileOptions_OptimizeMode_EnumDescriptor }, - }; - static GPBExtensionRange ranges[] = { - { .start = 1000, .end = 536870912 }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBFileOptions class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:enums - enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription) - ranges:ranges - rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) - storageSize:sizeof(GPBFileOptions__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - Enum GPBFileOptions_OptimizeMode - -GPBEnumDescriptor *GPBFileOptions_OptimizeMode_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "Speed", .number = GPBFileOptions_OptimizeMode_Speed }, - { .name = "CodeSize", .number = GPBFileOptions_OptimizeMode_CodeSize }, - { .name = "LiteRuntime", .number = GPBFileOptions_OptimizeMode_LiteRuntime }, - }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFileOptions_OptimizeMode) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBFileOptions_OptimizeMode_IsValidValue]; - } - return descriptor; -} - -BOOL GPBFileOptions_OptimizeMode_IsValidValue(int32_t value__) { - switch (value__) { - case GPBFileOptions_OptimizeMode_Speed: - case GPBFileOptions_OptimizeMode_CodeSize: - case GPBFileOptions_OptimizeMode_LiteRuntime: - return YES; - default: - return NO; - } -} - -#pragma mark - GPBMessageOptions - -@implementation GPBMessageOptions - -@dynamic hasMessageSetWireFormat, messageSetWireFormat; -@dynamic hasNoStandardDescriptorAccessor, noStandardDescriptorAccessor; -@dynamic hasDeprecated, deprecated; -@dynamic hasMapEntry, mapEntry; -@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count; - -typedef struct GPBMessageOptions__storage_ { - uint32_t _has_storage_[1]; - BOOL messageSetWireFormat; - BOOL noStandardDescriptorAccessor; - BOOL deprecated; - BOOL mapEntry; - NSMutableArray *uninterpretedOptionArray; -} GPBMessageOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "messageSetWireFormat", - .number = GPBMessageOptions_FieldNumber_MessageSetWireFormat, - .hasIndex = 0, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMessageOptions__storage_, messageSetWireFormat), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "noStandardDescriptorAccessor", - .number = GPBMessageOptions_FieldNumber_NoStandardDescriptorAccessor, - .hasIndex = 1, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMessageOptions__storage_, noStandardDescriptorAccessor), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "deprecated", - .number = GPBMessageOptions_FieldNumber_Deprecated, - .hasIndex = 2, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMessageOptions__storage_, deprecated), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "mapEntry", - .number = GPBMessageOptions_FieldNumber_MapEntry, - .hasIndex = 3, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMessageOptions__storage_, mapEntry), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "uninterpretedOptionArray", - .number = GPBMessageOptions_FieldNumber_UninterpretedOptionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBMessageOptions__storage_, uninterpretedOptionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), - .fieldOptions = NULL, - }, - }; - static GPBExtensionRange ranges[] = { - { .start = 1000, .end = 536870912 }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBMessageOptions class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:ranges - rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) - storageSize:sizeof(GPBMessageOptions__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBFieldOptions - -@implementation GPBFieldOptions - -@dynamic hasCtype, ctype; -@dynamic hasPacked, packed; -@dynamic hasJstype, jstype; -@dynamic hasLazy, lazy; -@dynamic hasDeprecated, deprecated; -@dynamic hasWeak, weak; -@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count; - -typedef struct GPBFieldOptions__storage_ { - uint32_t _has_storage_[1]; - BOOL packed; - BOOL deprecated; - BOOL lazy; - BOOL weak; - GPBFieldOptions_CType ctype; - GPBFieldOptions_JSType jstype; - NSMutableArray *uninterpretedOptionArray; -} GPBFieldOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "ctype", - .number = GPBFieldOptions_FieldNumber_Ctype, - .hasIndex = 0, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBFieldOptions__storage_, ctype), - .defaultValue.valueEnum = GPBFieldOptions_CType_String, - .dataTypeSpecific.enumDescFunc = GPBFieldOptions_CType_EnumDescriptor, - .fieldOptions = NULL, - }, - { - .name = "packed", - .number = GPBFieldOptions_FieldNumber_Packed, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFieldOptions__storage_, packed), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "deprecated", - .number = GPBFieldOptions_FieldNumber_Deprecated, - .hasIndex = 4, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFieldOptions__storage_, deprecated), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "lazy", - .number = GPBFieldOptions_FieldNumber_Lazy, - .hasIndex = 3, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFieldOptions__storage_, lazy), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "jstype", - .number = GPBFieldOptions_FieldNumber_Jstype, - .hasIndex = 2, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBFieldOptions__storage_, jstype), - .defaultValue.valueEnum = GPBFieldOptions_JSType_JsNormal, - .dataTypeSpecific.enumDescFunc = GPBFieldOptions_JSType_EnumDescriptor, - .fieldOptions = NULL, - }, - { - .name = "weak", - .number = GPBFieldOptions_FieldNumber_Weak, - .hasIndex = 5, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBFieldOptions__storage_, weak), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "uninterpretedOptionArray", - .number = GPBFieldOptions_FieldNumber_UninterpretedOptionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBFieldOptions__storage_, uninterpretedOptionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), - .fieldOptions = NULL, - }, - }; - static GPBMessageEnumDescription enums[] = { - { .enumDescriptorFunc = GPBFieldOptions_CType_EnumDescriptor }, - { .enumDescriptorFunc = GPBFieldOptions_JSType_EnumDescriptor }, - }; - static GPBExtensionRange ranges[] = { - { .start = 1000, .end = 536870912 }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBFieldOptions class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:enums - enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription) - ranges:ranges - rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) - storageSize:sizeof(GPBFieldOptions__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - Enum GPBFieldOptions_CType - -GPBEnumDescriptor *GPBFieldOptions_CType_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "String", .number = GPBFieldOptions_CType_String }, - { .name = "Cord", .number = GPBFieldOptions_CType_Cord }, - { .name = "StringPiece", .number = GPBFieldOptions_CType_StringPiece }, - }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldOptions_CType) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBFieldOptions_CType_IsValidValue]; - } - return descriptor; -} - -BOOL GPBFieldOptions_CType_IsValidValue(int32_t value__) { - switch (value__) { - case GPBFieldOptions_CType_String: - case GPBFieldOptions_CType_Cord: - case GPBFieldOptions_CType_StringPiece: - return YES; - default: - return NO; - } -} - -#pragma mark - Enum GPBFieldOptions_JSType - -GPBEnumDescriptor *GPBFieldOptions_JSType_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "JsNormal", .number = GPBFieldOptions_JSType_JsNormal }, - { .name = "JsString", .number = GPBFieldOptions_JSType_JsString }, - { .name = "JsNumber", .number = GPBFieldOptions_JSType_JsNumber }, - }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBFieldOptions_JSType) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBFieldOptions_JSType_IsValidValue]; - } - return descriptor; -} - -BOOL GPBFieldOptions_JSType_IsValidValue(int32_t value__) { - switch (value__) { - case GPBFieldOptions_JSType_JsNormal: - case GPBFieldOptions_JSType_JsString: - case GPBFieldOptions_JSType_JsNumber: - return YES; - default: - return NO; - } -} - -#pragma mark - GPBEnumOptions - -@implementation GPBEnumOptions - -@dynamic hasAllowAlias, allowAlias; -@dynamic hasDeprecated, deprecated; -@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count; - -typedef struct GPBEnumOptions__storage_ { - uint32_t _has_storage_[1]; - BOOL allowAlias; - BOOL deprecated; - NSMutableArray *uninterpretedOptionArray; -} GPBEnumOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "allowAlias", - .number = GPBEnumOptions_FieldNumber_AllowAlias, - .hasIndex = 0, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBEnumOptions__storage_, allowAlias), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "deprecated", - .number = GPBEnumOptions_FieldNumber_Deprecated, - .hasIndex = 1, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBEnumOptions__storage_, deprecated), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "uninterpretedOptionArray", - .number = GPBEnumOptions_FieldNumber_UninterpretedOptionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnumOptions__storage_, uninterpretedOptionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), - .fieldOptions = NULL, - }, - }; - static GPBExtensionRange ranges[] = { - { .start = 1000, .end = 536870912 }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBEnumOptions class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:ranges - rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) - storageSize:sizeof(GPBEnumOptions__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBEnumValueOptions - -@implementation GPBEnumValueOptions - -@dynamic hasDeprecated, deprecated; -@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count; - -typedef struct GPBEnumValueOptions__storage_ { - uint32_t _has_storage_[1]; - BOOL deprecated; - NSMutableArray *uninterpretedOptionArray; -} GPBEnumValueOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "deprecated", - .number = GPBEnumValueOptions_FieldNumber_Deprecated, - .hasIndex = 0, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBEnumValueOptions__storage_, deprecated), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "uninterpretedOptionArray", - .number = GPBEnumValueOptions_FieldNumber_UninterpretedOptionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnumValueOptions__storage_, uninterpretedOptionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), - .fieldOptions = NULL, - }, - }; - static GPBExtensionRange ranges[] = { - { .start = 1000, .end = 536870912 }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBEnumValueOptions class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:ranges - rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) - storageSize:sizeof(GPBEnumValueOptions__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBServiceOptions - -@implementation GPBServiceOptions - -@dynamic hasDeprecated, deprecated; -@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count; - -typedef struct GPBServiceOptions__storage_ { - uint32_t _has_storage_[1]; - BOOL deprecated; - NSMutableArray *uninterpretedOptionArray; -} GPBServiceOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "deprecated", - .number = GPBServiceOptions_FieldNumber_Deprecated, - .hasIndex = 0, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBServiceOptions__storage_, deprecated), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "uninterpretedOptionArray", - .number = GPBServiceOptions_FieldNumber_UninterpretedOptionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBServiceOptions__storage_, uninterpretedOptionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), - .fieldOptions = NULL, - }, - }; - static GPBExtensionRange ranges[] = { - { .start = 1000, .end = 536870912 }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBServiceOptions class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:ranges - rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) - storageSize:sizeof(GPBServiceOptions__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBMethodOptions - -@implementation GPBMethodOptions - -@dynamic hasDeprecated, deprecated; -@dynamic uninterpretedOptionArray, uninterpretedOptionArray_Count; - -typedef struct GPBMethodOptions__storage_ { - uint32_t _has_storage_[1]; - BOOL deprecated; - NSMutableArray *uninterpretedOptionArray; -} GPBMethodOptions__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "deprecated", - .number = GPBMethodOptions_FieldNumber_Deprecated, - .hasIndex = 0, - .flags = GPBFieldOptional | GPBFieldHasDefaultValue, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBMethodOptions__storage_, deprecated), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "uninterpretedOptionArray", - .number = GPBMethodOptions_FieldNumber_UninterpretedOptionArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBMethodOptions__storage_, uninterpretedOptionArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption), - .fieldOptions = NULL, - }, - }; - static GPBExtensionRange ranges[] = { - { .start = 1000, .end = 536870912 }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBMethodOptions class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:ranges - rangeCount:sizeof(ranges) / sizeof(GPBExtensionRange) - storageSize:sizeof(GPBMethodOptions__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBUninterpretedOption - -@implementation GPBUninterpretedOption - -@dynamic nameArray, nameArray_Count; -@dynamic hasIdentifierValue, identifierValue; -@dynamic hasPositiveIntValue, positiveIntValue; -@dynamic hasNegativeIntValue, negativeIntValue; -@dynamic hasDoubleValue, doubleValue; -@dynamic hasStringValue, stringValue; -@dynamic hasAggregateValue, aggregateValue; - -typedef struct GPBUninterpretedOption__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *nameArray; - NSString *identifierValue; - NSData *stringValue; - NSString *aggregateValue; - uint64_t positiveIntValue; - int64_t negativeIntValue; - double doubleValue; -} GPBUninterpretedOption__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "nameArray", - .number = GPBUninterpretedOption_FieldNumber_NameArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBUninterpretedOption__storage_, nameArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBUninterpretedOption_NamePart), - .fieldOptions = NULL, - }, - { - .name = "identifierValue", - .number = GPBUninterpretedOption_FieldNumber_IdentifierValue, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBUninterpretedOption__storage_, identifierValue), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "positiveIntValue", - .number = GPBUninterpretedOption_FieldNumber_PositiveIntValue, - .hasIndex = 2, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeUInt64, - .offset = offsetof(GPBUninterpretedOption__storage_, positiveIntValue), - .defaultValue.valueUInt64 = 0ULL, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "negativeIntValue", - .number = GPBUninterpretedOption_FieldNumber_NegativeIntValue, - .hasIndex = 3, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt64, - .offset = offsetof(GPBUninterpretedOption__storage_, negativeIntValue), - .defaultValue.valueInt64 = 0LL, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "doubleValue", - .number = GPBUninterpretedOption_FieldNumber_DoubleValue, - .hasIndex = 4, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeDouble, - .offset = offsetof(GPBUninterpretedOption__storage_, doubleValue), - .defaultValue.valueDouble = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "stringValue", - .number = GPBUninterpretedOption_FieldNumber_StringValue, - .hasIndex = 5, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - .offset = offsetof(GPBUninterpretedOption__storage_, stringValue), - .defaultValue.valueData = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "aggregateValue", - .number = GPBUninterpretedOption_FieldNumber_AggregateValue, - .hasIndex = 6, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBUninterpretedOption__storage_, aggregateValue), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBUninterpretedOption class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBUninterpretedOption__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBUninterpretedOption_NamePart - -@implementation GPBUninterpretedOption_NamePart - -@dynamic hasNamePart, namePart; -@dynamic hasIsExtension, isExtension; - -typedef struct GPBUninterpretedOption_NamePart__storage_ { - uint32_t _has_storage_[1]; - BOOL isExtension; - NSString *namePart; -} GPBUninterpretedOption_NamePart__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "namePart", - .number = GPBUninterpretedOption_NamePart_FieldNumber_NamePart, - .hasIndex = 0, - .flags = GPBFieldRequired, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBUninterpretedOption_NamePart__storage_, namePart), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "isExtension", - .number = GPBUninterpretedOption_NamePart_FieldNumber_IsExtension, - .hasIndex = 1, - .flags = GPBFieldRequired, - .dataType = GPBDataTypeBool, - .offset = offsetof(GPBUninterpretedOption_NamePart__storage_, isExtension), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBUninterpretedOption_NamePart class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBUninterpretedOption_NamePart__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBSourceCodeInfo - -@implementation GPBSourceCodeInfo - -@dynamic locationArray, locationArray_Count; - -typedef struct GPBSourceCodeInfo__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *locationArray; -} GPBSourceCodeInfo__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "locationArray", - .number = GPBSourceCodeInfo_FieldNumber_LocationArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBSourceCodeInfo__storage_, locationArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceCodeInfo_Location), - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBSourceCodeInfo class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBSourceCodeInfo__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBSourceCodeInfo_Location - -@implementation GPBSourceCodeInfo_Location - -@dynamic pathArray, pathArray_Count; -@dynamic spanArray, spanArray_Count; -@dynamic hasLeadingComments, leadingComments; -@dynamic hasTrailingComments, trailingComments; -@dynamic leadingDetachedCommentsArray, leadingDetachedCommentsArray_Count; - -typedef struct GPBSourceCodeInfo_Location__storage_ { - uint32_t _has_storage_[1]; - GPBInt32Array *pathArray; - GPBInt32Array *spanArray; - NSString *leadingComments; - NSString *trailingComments; - NSMutableArray *leadingDetachedCommentsArray; -} GPBSourceCodeInfo_Location__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "pathArray", - .number = GPBSourceCodeInfo_Location_FieldNumber_PathArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated | GPBFieldPacked, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBSourceCodeInfo_Location__storage_, pathArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - #if GPBOBJC_INCLUDE_FIELD_OPTIONS - .fieldOptions = "\000\000\000\002\020\001", - #else - .fieldOptions = NULL, - #endif // GPBOBJC_INCLUDE_FIELD_OPTIONS - }, - { - .name = "spanArray", - .number = GPBSourceCodeInfo_Location_FieldNumber_SpanArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated | GPBFieldPacked, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBSourceCodeInfo_Location__storage_, spanArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - #if GPBOBJC_INCLUDE_FIELD_OPTIONS - .fieldOptions = "\000\000\000\002\020\001", - #else - .fieldOptions = NULL, - #endif // GPBOBJC_INCLUDE_FIELD_OPTIONS - }, - { - .name = "leadingComments", - .number = GPBSourceCodeInfo_Location_FieldNumber_LeadingComments, - .hasIndex = 2, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBSourceCodeInfo_Location__storage_, leadingComments), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "trailingComments", - .number = GPBSourceCodeInfo_Location_FieldNumber_TrailingComments, - .hasIndex = 3, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBSourceCodeInfo_Location__storage_, trailingComments), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "leadingDetachedCommentsArray", - .number = GPBSourceCodeInfo_Location_FieldNumber_LeadingDetachedCommentsArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBSourceCodeInfo_Location__storage_, leadingDetachedCommentsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBSourceCodeInfo_Location class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBSourceCodeInfo_Location__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBGeneratedCodeInfo - -@implementation GPBGeneratedCodeInfo - -@dynamic annotationArray, annotationArray_Count; - -typedef struct GPBGeneratedCodeInfo__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *annotationArray; -} GPBGeneratedCodeInfo__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "annotationArray", - .number = GPBGeneratedCodeInfo_FieldNumber_AnnotationArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBGeneratedCodeInfo__storage_, annotationArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBGeneratedCodeInfo_Annotation), - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBGeneratedCodeInfo class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBGeneratedCodeInfo__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBGeneratedCodeInfo_Annotation - -@implementation GPBGeneratedCodeInfo_Annotation - -@dynamic pathArray, pathArray_Count; -@dynamic hasSourceFile, sourceFile; -@dynamic hasBegin, begin; -@dynamic hasEnd, end; - -typedef struct GPBGeneratedCodeInfo_Annotation__storage_ { - uint32_t _has_storage_[1]; - int32_t begin; - int32_t end; - GPBInt32Array *pathArray; - NSString *sourceFile; -} GPBGeneratedCodeInfo_Annotation__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "pathArray", - .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_PathArray, - .hasIndex = GPBNoHasBit, - .flags = GPBFieldRepeated | GPBFieldPacked, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, pathArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - #if GPBOBJC_INCLUDE_FIELD_OPTIONS - .fieldOptions = "\000\000\000\002\020\001", - #else - .fieldOptions = NULL, - #endif // GPBOBJC_INCLUDE_FIELD_OPTIONS - }, - { - .name = "sourceFile", - .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_SourceFile, - .hasIndex = 1, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, sourceFile), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "begin", - .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_Begin, - .hasIndex = 2, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, begin), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - { - .name = "end", - .number = GPBGeneratedCodeInfo_Annotation_FieldNumber_End, - .hasIndex = 3, - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBGeneratedCodeInfo_Annotation__storage_, end), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBGeneratedCodeInfo_Annotation class] - rootClass:[GPBDescriptorRoot class] - file:GPBDescriptorRoot_FileDescriptor() - fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 - storageSize:sizeof(GPBGeneratedCodeInfo_Annotation__storage_) - wireFormat:NO]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h index ebf9119e..3685a614 100644 --- a/objectivec/google/protobuf/Duration.pbobjc.h +++ b/objectivec/google/protobuf/Duration.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m index e4fd4951..bb79c7a3 100644 --- a/objectivec/google/protobuf/Duration.pbobjc.m +++ b/objectivec/google/protobuf/Duration.pbobjc.m @@ -46,25 +46,21 @@ typedef struct GPBDuration__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "seconds", + .dataTypeSpecific.className = NULL, .number = GPBDuration_FieldNumber_Seconds, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBDuration__storage_, seconds), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt64, - .offset = offsetof(GPBDuration__storage_, seconds), - .defaultValue.valueInt64 = 0LL, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "nanos", + .dataTypeSpecific.className = NULL, .number = GPBDuration_FieldNumber_Nanos, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBDuration__storage_, nanos), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBDuration__storage_, nanos), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -72,15 +68,9 @@ typedef struct GPBDuration__storage_ { rootClass:[GPBDurationRoot class] file:GPBDurationRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBDuration__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h index ca09f71d..6651ef71 100644 --- a/objectivec/google/protobuf/Empty.pbobjc.h +++ b/objectivec/google/protobuf/Empty.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m index 17f0c1ac..5d7f8f19 100644 --- a/objectivec/google/protobuf/Empty.pbobjc.m +++ b/objectivec/google/protobuf/Empty.pbobjc.m @@ -31,7 +31,7 @@ static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) { typedef struct GPBEmpty__storage_ { - uint32_t _has_storage_[0]; + uint32_t _has_storage_[1]; } GPBEmpty__storage_; // This method is threadsafe because it is initially called @@ -45,14 +45,8 @@ typedef struct GPBEmpty__storage_ { file:GPBEmptyRoot_FileDescriptor() fields:NULL fieldCount:0 - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 storageSize:sizeof(GPBEmpty__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h index f861a986..931f664c 100644 --- a/objectivec/google/protobuf/FieldMask.pbobjc.h +++ b/objectivec/google/protobuf/FieldMask.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m index f9684f51..36fc758e 100644 --- a/objectivec/google/protobuf/FieldMask.pbobjc.m +++ b/objectivec/google/protobuf/FieldMask.pbobjc.m @@ -44,14 +44,12 @@ typedef struct GPBFieldMask__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "pathsArray", + .dataTypeSpecific.className = NULL, .number = GPBFieldMask_FieldNumber_PathsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBFieldMask__storage_, pathsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeString, - .offset = offsetof(GPBFieldMask__storage_, pathsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -59,15 +57,9 @@ typedef struct GPBFieldMask__storage_ { rootClass:[GPBFieldMaskRoot class] file:GPBFieldMaskRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBFieldMask__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h index 546db674..67b6d479 100644 --- a/objectivec/google/protobuf/SourceContext.pbobjc.h +++ b/objectivec/google/protobuf/SourceContext.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m index ac1827fc..4e8bf3d2 100644 --- a/objectivec/google/protobuf/SourceContext.pbobjc.m +++ b/objectivec/google/protobuf/SourceContext.pbobjc.m @@ -44,14 +44,12 @@ typedef struct GPBSourceContext__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "fileName", + .dataTypeSpecific.className = NULL, .number = GPBSourceContext_FieldNumber_FileName, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBSourceContext__storage_, fileName), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBSourceContext__storage_, fileName), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -59,15 +57,9 @@ typedef struct GPBSourceContext__storage_ { rootClass:[GPBSourceContextRoot class] file:GPBSourceContextRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBSourceContext__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h index 7b9c45a0..e2388e22 100644 --- a/objectivec/google/protobuf/Struct.pbobjc.h +++ b/objectivec/google/protobuf/Struct.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m index 14b8f271..0601a4b2 100644 --- a/objectivec/google/protobuf/Struct.pbobjc.m +++ b/objectivec/google/protobuf/Struct.pbobjc.m @@ -30,13 +30,20 @@ static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) { GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void) { static GPBEnumDescriptor *descriptor = NULL; if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "NullValue", .number = GPBNullValue_NullValue }, + static const char *valueNames = + "NullValue\000"; + static const int32_t values[] = { + GPBNullValue_NullValue, }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBNullValue) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBNullValue_IsValidValue]; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBNullValue) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBNullValue_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } } return descriptor; } @@ -69,14 +76,12 @@ typedef struct GPBStruct__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "fields", + .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), .number = GPBStruct_FieldNumber_Fields, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBStruct__storage_, fields), .flags = GPBFieldMapKeyString, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBStruct__storage_, fields), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -84,15 +89,9 @@ typedef struct GPBStruct__storage_ { rootClass:[GPBStructRoot class] file:GPBStructRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBStruct__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -115,7 +114,6 @@ typedef struct GPBStruct__storage_ { typedef struct GPBValue__storage_ { uint32_t _has_storage_[2]; - BOOL boolValue; GPBNullValue nullValue; NSString *stringValue; GPBStruct *structValue; @@ -128,78 +126,60 @@ typedef struct GPBValue__storage_ { + (GPBDescriptor *)descriptor { static GPBDescriptor *descriptor = nil; if (!descriptor) { - static GPBMessageOneofDescription oneofs[] = { - { - .name = "kind", - .index = -1, - }, - }; static GPBMessageFieldDescription fields[] = { { .name = "nullValue", + .dataTypeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor, .number = GPBValue_FieldNumber_NullValue, .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, nullValue), .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBValue__storage_, nullValue), - .defaultValue.valueEnum = GPBNullValue_NullValue, - .dataTypeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor, - .fieldOptions = NULL, }, { .name = "numberValue", + .dataTypeSpecific.className = NULL, .number = GPBValue_FieldNumber_NumberValue, .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, numberValue), .flags = GPBFieldOptional, .dataType = GPBDataTypeDouble, - .offset = offsetof(GPBValue__storage_, numberValue), - .defaultValue.valueDouble = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "stringValue", + .dataTypeSpecific.className = NULL, .number = GPBValue_FieldNumber_StringValue, .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, stringValue), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBValue__storage_, stringValue), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "boolValue", + .dataTypeSpecific.className = NULL, .number = GPBValue_FieldNumber_BoolValue, .hasIndex = -1, + .offset = 0, // Stored in _has_storage_ to save space. .flags = GPBFieldOptional, .dataType = GPBDataTypeBool, - .offset = offsetof(GPBValue__storage_, boolValue), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "structValue", + .dataTypeSpecific.className = GPBStringifySymbol(GPBStruct), .number = GPBValue_FieldNumber_StructValue, .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, structValue), .flags = GPBFieldOptional, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBValue__storage_, structValue), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBStruct), - .fieldOptions = NULL, }, { .name = "listValue", + .dataTypeSpecific.className = GPBStringifySymbol(GPBListValue), .number = GPBValue_FieldNumber_ListValue, .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, listValue), .flags = GPBFieldOptional, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBValue__storage_, listValue), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBListValue), - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -207,15 +187,15 @@ typedef struct GPBValue__storage_ { rootClass:[GPBStructRoot class] file:GPBStructRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:oneofs - oneofCount:sizeof(oneofs) / sizeof(GPBMessageOneofDescription) - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBValue__storage_) - wireFormat:NO]; + flags:0]; + static const char *oneofs[] = { + "kind", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -239,7 +219,7 @@ void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value) { void GPBValue_ClearKindOneOfCase(GPBValue *message) { GPBDescriptor *descriptor = [message descriptor]; GPBOneofDescriptor *oneof = descriptor->oneofs_[0]; - GPBMaybeClearOneof(message, oneof, 0); + GPBMaybeClearOneof(message, oneof, -1, 0); } #pragma mark - GPBListValue @@ -260,14 +240,12 @@ typedef struct GPBListValue__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "valuesArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), .number = GPBListValue_FieldNumber_ValuesArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBListValue__storage_, valuesArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBListValue__storage_, valuesArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -275,15 +253,9 @@ typedef struct GPBListValue__storage_ { rootClass:[GPBStructRoot class] file:GPBStructRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBListValue__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h index d17c2860..b66b323a 100644 --- a/objectivec/google/protobuf/Timestamp.pbobjc.h +++ b/objectivec/google/protobuf/Timestamp.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m index a206f159..14161159 100644 --- a/objectivec/google/protobuf/Timestamp.pbobjc.m +++ b/objectivec/google/protobuf/Timestamp.pbobjc.m @@ -46,25 +46,21 @@ typedef struct GPBTimestamp__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "seconds", + .dataTypeSpecific.className = NULL, .number = GPBTimestamp_FieldNumber_Seconds, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBTimestamp__storage_, seconds), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt64, - .offset = offsetof(GPBTimestamp__storage_, seconds), - .defaultValue.valueInt64 = 0LL, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "nanos", + .dataTypeSpecific.className = NULL, .number = GPBTimestamp_FieldNumber_Nanos, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBTimestamp__storage_, nanos), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBTimestamp__storage_, nanos), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -72,15 +68,9 @@ typedef struct GPBTimestamp__storage_ { rootClass:[GPBTimestampRoot class] file:GPBTimestampRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBTimestamp__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h index 9301e4f4..efaeab39 100644 --- a/objectivec/google/protobuf/Type.pbobjc.h +++ b/objectivec/google/protobuf/Type.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m index b4e0a5f6..175c0233 100644 --- a/objectivec/google/protobuf/Type.pbobjc.m +++ b/objectivec/google/protobuf/Type.pbobjc.m @@ -45,14 +45,21 @@ static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) { GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void) { static GPBEnumDescriptor *descriptor = NULL; if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "SyntaxProto2", .number = GPBSyntax_SyntaxProto2 }, - { .name = "SyntaxProto3", .number = GPBSyntax_SyntaxProto3 }, + static const char *valueNames = + "SyntaxProto2\000SyntaxProto3\000"; + static const int32_t values[] = { + GPBSyntax_SyntaxProto2, + GPBSyntax_SyntaxProto3, }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBSyntax) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBSyntax_IsValidValue]; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBSyntax) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBSyntax_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } } return descriptor; } @@ -96,69 +103,57 @@ typedef struct GPBType__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBType_FieldNumber_Name, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBType__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBType__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "fieldsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBField), .number = GPBType_FieldNumber_FieldsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBType__storage_, fieldsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBType__storage_, fieldsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBField), - .fieldOptions = NULL, }, { .name = "oneofsArray", + .dataTypeSpecific.className = NULL, .number = GPBType_FieldNumber_OneofsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBType__storage_, oneofsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeString, - .offset = offsetof(GPBType__storage_, oneofsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), .number = GPBType_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBType__storage_, optionsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBType__storage_, optionsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .fieldOptions = NULL, }, { .name = "sourceContext", + .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), .number = GPBType_FieldNumber_SourceContext, - .hasIndex = 4, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBType__storage_, sourceContext), .flags = GPBFieldOptional, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBType__storage_, sourceContext), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), - .fieldOptions = NULL, }, { .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, .number = GPBType_FieldNumber_Syntax, - .hasIndex = 5, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBType__storage_, syntax), .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBType__storage_, syntax), - .defaultValue.valueEnum = GPBSyntax_SyntaxProto2, - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -166,15 +161,9 @@ typedef struct GPBType__storage_ { rootClass:[GPBTypeRoot class] file:GPBTypeRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBType__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -212,7 +201,6 @@ void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value) { typedef struct GPBField__storage_ { uint32_t _has_storage_[1]; - BOOL packed; GPBField_Kind kind; GPBField_Cardinality cardinality; int32_t number; @@ -232,139 +220,108 @@ typedef struct GPBField__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "kind", + .dataTypeSpecific.enumDescFunc = GPBField_Kind_EnumDescriptor, .number = GPBField_FieldNumber_Kind, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBField__storage_, kind), .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBField__storage_, kind), - .defaultValue.valueEnum = GPBField_Kind_TypeUnknown, - .dataTypeSpecific.enumDescFunc = GPBField_Kind_EnumDescriptor, - .fieldOptions = NULL, }, { .name = "cardinality", + .dataTypeSpecific.enumDescFunc = GPBField_Cardinality_EnumDescriptor, .number = GPBField_FieldNumber_Cardinality, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBField__storage_, cardinality), .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBField__storage_, cardinality), - .defaultValue.valueEnum = GPBField_Cardinality_CardinalityUnknown, - .dataTypeSpecific.enumDescFunc = GPBField_Cardinality_EnumDescriptor, - .fieldOptions = NULL, }, { .name = "number", + .dataTypeSpecific.className = NULL, .number = GPBField_FieldNumber_Number, .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBField__storage_, number), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBField__storage_, number), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBField_FieldNumber_Name, .hasIndex = 3, + .offset = (uint32_t)offsetof(GPBField__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBField__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "typeURL", + .dataTypeSpecific.className = NULL, .number = GPBField_FieldNumber_TypeURL, .hasIndex = 4, + .offset = (uint32_t)offsetof(GPBField__storage_, typeURL), .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, .dataType = GPBDataTypeString, - .offset = offsetof(GPBField__storage_, typeURL), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "oneofIndex", + .dataTypeSpecific.className = NULL, .number = GPBField_FieldNumber_OneofIndex, .hasIndex = 5, + .offset = (uint32_t)offsetof(GPBField__storage_, oneofIndex), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBField__storage_, oneofIndex), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "packed", + .dataTypeSpecific.className = NULL, .number = GPBField_FieldNumber_Packed, .hasIndex = 6, + .offset = 7, // Stored in _has_storage_ to save space. .flags = GPBFieldOptional, .dataType = GPBDataTypeBool, - .offset = offsetof(GPBField__storage_, packed), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), .number = GPBField_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBField__storage_, optionsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBField__storage_, optionsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .fieldOptions = NULL, }, { .name = "jsonName", + .dataTypeSpecific.className = NULL, .number = GPBField_FieldNumber_JsonName, .hasIndex = 8, + .offset = (uint32_t)offsetof(GPBField__storage_, jsonName), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBField__storage_, jsonName), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "defaultValue", + .dataTypeSpecific.className = NULL, .number = GPBField_FieldNumber_DefaultValue, .hasIndex = 9, + .offset = (uint32_t)offsetof(GPBField__storage_, defaultValue), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBField__storage_, defaultValue), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; - static GPBMessageEnumDescription enums[] = { - { .enumDescriptorFunc = GPBField_Kind_EnumDescriptor }, - { .enumDescriptorFunc = GPBField_Cardinality_EnumDescriptor }, - }; -#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - const char *extraTextFormatInfo = NULL; -#else - static const char *extraTextFormatInfo = "\001\006\004\241!!\000"; -#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS GPBDescriptor *localDescriptor = [GPBDescriptor allocDescriptorForClass:[GPBField class] rootClass:[GPBTypeRoot class] file:GPBTypeRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:enums - enumCount:sizeof(enums) / sizeof(GPBMessageEnumDescription) - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBField__storage_) - wireFormat:NO - extraTextFormatInfo:extraTextFormatInfo]; + flags:0]; +#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + static const char *extraTextFormatInfo = + "\001\006\004\241!!\000"; + [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; +#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -402,31 +359,43 @@ void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value) { GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void) { static GPBEnumDescriptor *descriptor = NULL; if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "TypeUnknown", .number = GPBField_Kind_TypeUnknown }, - { .name = "TypeDouble", .number = GPBField_Kind_TypeDouble }, - { .name = "TypeFloat", .number = GPBField_Kind_TypeFloat }, - { .name = "TypeInt64", .number = GPBField_Kind_TypeInt64 }, - { .name = "TypeUint64", .number = GPBField_Kind_TypeUint64 }, - { .name = "TypeInt32", .number = GPBField_Kind_TypeInt32 }, - { .name = "TypeFixed64", .number = GPBField_Kind_TypeFixed64 }, - { .name = "TypeFixed32", .number = GPBField_Kind_TypeFixed32 }, - { .name = "TypeBool", .number = GPBField_Kind_TypeBool }, - { .name = "TypeString", .number = GPBField_Kind_TypeString }, - { .name = "TypeGroup", .number = GPBField_Kind_TypeGroup }, - { .name = "TypeMessage", .number = GPBField_Kind_TypeMessage }, - { .name = "TypeBytes", .number = GPBField_Kind_TypeBytes }, - { .name = "TypeUint32", .number = GPBField_Kind_TypeUint32 }, - { .name = "TypeEnum", .number = GPBField_Kind_TypeEnum }, - { .name = "TypeSfixed32", .number = GPBField_Kind_TypeSfixed32 }, - { .name = "TypeSfixed64", .number = GPBField_Kind_TypeSfixed64 }, - { .name = "TypeSint32", .number = GPBField_Kind_TypeSint32 }, - { .name = "TypeSint64", .number = GPBField_Kind_TypeSint64 }, + static const char *valueNames = + "TypeUnknown\000TypeDouble\000TypeFloat\000TypeInt" + "64\000TypeUint64\000TypeInt32\000TypeFixed64\000Type" + "Fixed32\000TypeBool\000TypeString\000TypeGroup\000Ty" + "peMessage\000TypeBytes\000TypeUint32\000TypeEnum\000" + "TypeSfixed32\000TypeSfixed64\000TypeSint32\000Typ" + "eSint64\000"; + static const int32_t values[] = { + GPBField_Kind_TypeUnknown, + GPBField_Kind_TypeDouble, + GPBField_Kind_TypeFloat, + GPBField_Kind_TypeInt64, + GPBField_Kind_TypeUint64, + GPBField_Kind_TypeInt32, + GPBField_Kind_TypeFixed64, + GPBField_Kind_TypeFixed32, + GPBField_Kind_TypeBool, + GPBField_Kind_TypeString, + GPBField_Kind_TypeGroup, + GPBField_Kind_TypeMessage, + GPBField_Kind_TypeBytes, + GPBField_Kind_TypeUint32, + GPBField_Kind_TypeEnum, + GPBField_Kind_TypeSfixed32, + GPBField_Kind_TypeSfixed64, + GPBField_Kind_TypeSint32, + GPBField_Kind_TypeSint64, }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Kind) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBField_Kind_IsValidValue]; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Kind) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBField_Kind_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } } return descriptor; } @@ -463,16 +432,24 @@ BOOL GPBField_Kind_IsValidValue(int32_t value__) { GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void) { static GPBEnumDescriptor *descriptor = NULL; if (!descriptor) { - static GPBMessageEnumValueDescription values[] = { - { .name = "CardinalityUnknown", .number = GPBField_Cardinality_CardinalityUnknown }, - { .name = "CardinalityOptional", .number = GPBField_Cardinality_CardinalityOptional }, - { .name = "CardinalityRequired", .number = GPBField_Cardinality_CardinalityRequired }, - { .name = "CardinalityRepeated", .number = GPBField_Cardinality_CardinalityRepeated }, + static const char *valueNames = + "CardinalityUnknown\000CardinalityOptional\000C" + "ardinalityRequired\000CardinalityRepeated\000"; + static const int32_t values[] = { + GPBField_Cardinality_CardinalityUnknown, + GPBField_Cardinality_CardinalityOptional, + GPBField_Cardinality_CardinalityRequired, + GPBField_Cardinality_CardinalityRepeated, }; - descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Cardinality) - values:values - valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription) - enumVerifier:GPBField_Cardinality_IsValidValue]; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Cardinality) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBField_Cardinality_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } } return descriptor; } @@ -516,58 +493,48 @@ typedef struct GPBEnum__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBEnum_FieldNumber_Name, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBEnum__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBEnum__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "enumvalueArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValue), .number = GPBEnum_FieldNumber_EnumvalueArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBEnum__storage_, enumvalueArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnum__storage_, enumvalueArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValue), - .fieldOptions = NULL, }, { .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), .number = GPBEnum_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBEnum__storage_, optionsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnum__storage_, optionsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .fieldOptions = NULL, }, { .name = "sourceContext", + .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), .number = GPBEnum_FieldNumber_SourceContext, - .hasIndex = 3, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBEnum__storage_, sourceContext), .flags = GPBFieldOptional, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnum__storage_, sourceContext), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), - .fieldOptions = NULL, }, { .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, .number = GPBEnum_FieldNumber_Syntax, - .hasIndex = 4, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBEnum__storage_, syntax), .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, .dataType = GPBDataTypeEnum, - .offset = offsetof(GPBEnum__storage_, syntax), - .defaultValue.valueEnum = GPBSyntax_SyntaxProto2, - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -575,15 +542,9 @@ typedef struct GPBEnum__storage_ { rootClass:[GPBTypeRoot class] file:GPBTypeRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBEnum__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -627,36 +588,30 @@ typedef struct GPBEnumValue__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBEnumValue_FieldNumber_Name, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBEnumValue__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBEnumValue__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "number", + .dataTypeSpecific.className = NULL, .number = GPBEnumValue_FieldNumber_Number, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBEnumValue__storage_, number), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBEnumValue__storage_, number), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), .number = GPBEnumValue_FieldNumber_OptionsArray, .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBEnumValue__storage_, optionsArray), .flags = GPBFieldRepeated, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBEnumValue__storage_, optionsArray), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -664,15 +619,9 @@ typedef struct GPBEnumValue__storage_ { rootClass:[GPBTypeRoot class] file:GPBTypeRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBEnumValue__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -702,25 +651,21 @@ typedef struct GPBOption__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "name", + .dataTypeSpecific.className = NULL, .number = GPBOption_FieldNumber_Name, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBOption__storage_, name), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBOption__storage_, name), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, { .name = "value", + .dataTypeSpecific.className = GPBStringifySymbol(GPBAny), .number = GPBOption_FieldNumber_Value, .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBOption__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeMessage, - .offset = offsetof(GPBOption__storage_, value), - .defaultValue.valueMessage = nil, - .dataTypeSpecific.className = GPBStringifySymbol(GPBAny), - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -728,15 +673,9 @@ typedef struct GPBOption__storage_ { rootClass:[GPBTypeRoot class] file:GPBTypeRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBOption__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h index 38b99622..0ca439a8 100644 --- a/objectivec/google/protobuf/Wrappers.pbobjc.h +++ b/objectivec/google/protobuf/Wrappers.pbobjc.h @@ -3,7 +3,7 @@ #import "GPBProtocolBuffers.h" -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30000 +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 #error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. #endif diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m index 0403b464..b1b5be69 100644 --- a/objectivec/google/protobuf/Wrappers.pbobjc.m +++ b/objectivec/google/protobuf/Wrappers.pbobjc.m @@ -44,14 +44,12 @@ typedef struct GPBDoubleValue__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBDoubleValue_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBDoubleValue__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeDouble, - .offset = offsetof(GPBDoubleValue__storage_, value), - .defaultValue.valueDouble = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -59,15 +57,9 @@ typedef struct GPBDoubleValue__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBDoubleValue__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -95,14 +87,12 @@ typedef struct GPBFloatValue__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBFloatValue_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBFloatValue__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeFloat, - .offset = offsetof(GPBFloatValue__storage_, value), - .defaultValue.valueFloat = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -110,15 +100,9 @@ typedef struct GPBFloatValue__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBFloatValue__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -146,14 +130,12 @@ typedef struct GPBInt64Value__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBInt64Value_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBInt64Value__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt64, - .offset = offsetof(GPBInt64Value__storage_, value), - .defaultValue.valueInt64 = 0LL, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -161,15 +143,9 @@ typedef struct GPBInt64Value__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBInt64Value__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -197,14 +173,12 @@ typedef struct GPBUInt64Value__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBUInt64Value_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBUInt64Value__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeUInt64, - .offset = offsetof(GPBUInt64Value__storage_, value), - .defaultValue.valueUInt64 = 0ULL, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -212,15 +186,9 @@ typedef struct GPBUInt64Value__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBUInt64Value__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -248,14 +216,12 @@ typedef struct GPBInt32Value__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBInt32Value_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBInt32Value__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeInt32, - .offset = offsetof(GPBInt32Value__storage_, value), - .defaultValue.valueInt32 = 0, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -263,15 +229,9 @@ typedef struct GPBInt32Value__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBInt32Value__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -299,14 +259,12 @@ typedef struct GPBUInt32Value__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBUInt32Value_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBUInt32Value__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeUInt32, - .offset = offsetof(GPBUInt32Value__storage_, value), - .defaultValue.valueUInt32 = 0U, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -314,15 +272,9 @@ typedef struct GPBUInt32Value__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBUInt32Value__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -339,7 +291,6 @@ typedef struct GPBUInt32Value__storage_ { typedef struct GPBBoolValue__storage_ { uint32_t _has_storage_[1]; - BOOL value; } GPBBoolValue__storage_; // This method is threadsafe because it is initially called @@ -350,14 +301,12 @@ typedef struct GPBBoolValue__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBBoolValue_FieldNumber_Value, .hasIndex = 0, + .offset = 1, // Stored in _has_storage_ to save space. .flags = GPBFieldOptional, .dataType = GPBDataTypeBool, - .offset = offsetof(GPBBoolValue__storage_, value), - .defaultValue.valueBool = NO, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -365,15 +314,9 @@ typedef struct GPBBoolValue__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBBoolValue__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -401,14 +344,12 @@ typedef struct GPBStringValue__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBStringValue_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBStringValue__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeString, - .offset = offsetof(GPBStringValue__storage_, value), - .defaultValue.valueString = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -416,15 +357,9 @@ typedef struct GPBStringValue__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBStringValue__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } @@ -452,14 +387,12 @@ typedef struct GPBBytesValue__storage_ { static GPBMessageFieldDescription fields[] = { { .name = "value", + .dataTypeSpecific.className = NULL, .number = GPBBytesValue_FieldNumber_Value, .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBBytesValue__storage_, value), .flags = GPBFieldOptional, .dataType = GPBDataTypeBytes, - .offset = offsetof(GPBBytesValue__storage_, value), - .defaultValue.valueData = nil, - .dataTypeSpecific.className = NULL, - .fieldOptions = NULL, }, }; GPBDescriptor *localDescriptor = @@ -467,15 +400,9 @@ typedef struct GPBBytesValue__storage_ { rootClass:[GPBWrappersRoot class] file:GPBWrappersRoot_FileDescriptor() fields:fields - fieldCount:sizeof(fields) / sizeof(GPBMessageFieldDescription) - oneofs:NULL - oneofCount:0 - enums:NULL - enumCount:0 - ranges:NULL - rangeCount:0 + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) storageSize:sizeof(GPBBytesValue__storage_) - wireFormat:NO]; + flags:0]; NSAssert(descriptor == nil, @"Startup recursed!"); descriptor = localDescriptor; } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc index 857d24a4..3f81dcb8 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc @@ -122,16 +122,6 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { "\n", "name", name_); - printer->Print( - "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" - " static GPBEnumDescriptor *descriptor = NULL;\n" - " if (!descriptor) {\n" - " static GPBMessageEnumValueDescription values[] = {\n", - "name", name_); - printer->Indent(); - printer->Indent(); - printer->Indent(); - // Note: For the TextFormat decode info, we can't use the enum value as // the key because protocol buffer enums have 'allow_alias', which lets // a value be used more than once. Instead, the index into the list of @@ -139,41 +129,66 @@ void EnumGenerator::GenerateSource(io::Printer* printer) { // will be zero. TextFormatDecodeData text_format_decode_data; int enum_value_description_key = -1; + string text_blob; for (int i = 0; i < all_values_.size(); i++) { ++enum_value_description_key; string short_name(EnumValueShortName(all_values_[i])); - printer->Print("{ .name = \"$short_name$\", .number = $name$ },\n", - "short_name", short_name, - "name", EnumValueName(all_values_[i])); + text_blob += short_name + '\0'; if (UnCamelCaseEnumShortName(short_name) != all_values_[i]->name()) { text_format_decode_data.AddString(enum_value_description_key, short_name, all_values_[i]->name()); } } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); + + printer->Print( + "GPBEnumDescriptor *$name$_EnumDescriptor(void) {\n" + " static GPBEnumDescriptor *descriptor = NULL;\n" + " if (!descriptor) {\n", + "name", name_); + + static const int kBytesPerLine = 40; // allow for escaping + printer->Print( + " static const char *valueNames ="); + for (int i = 0; i < text_blob.size(); i += kBytesPerLine) { + printer->Print( + "\n \"$data$\"", + "data", EscapeTrigraphs(CEscape(text_blob.substr(i, kBytesPerLine)))); + } + printer->Print( + ";\n" + " static const int32_t values[] = {\n"); + for (int i = 0; i < all_values_.size(); i++) { + printer->Print(" $name$,\n", "name", EnumValueName(all_values_[i])); + } printer->Print(" };\n"); + if (text_format_decode_data.num_entries() == 0) { printer->Print( - " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" - " values:values\n" - " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n" - " enumVerifier:$name$_IsValidValue];\n", + " GPBEnumDescriptor *worker =\n" + " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " valueNames:valueNames\n" + " values:values\n" + " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" + " enumVerifier:$name$_IsValidValue];\n", "name", name_); } else { printer->Print( " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" - " descriptor = [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" - " values:values\n" - " valueCount:sizeof(values) / sizeof(GPBMessageEnumValueDescription)\n" - " enumVerifier:$name$_IsValidValue\n" - " extraTextFormatInfo:extraTextFormatInfo];\n", + " GPBEnumDescriptor *worker =\n" + " [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol($name$)\n" + " valueNames:valueNames\n" + " values:values\n" + " count:(uint32_t)(sizeof(values) / sizeof(int32_t))\n" + " enumVerifier:$name$_IsValidValue\n" + " extraTextFormatInfo:extraTextFormatInfo];\n", "name", name_, "extraTextFormatInfo", CEscape(text_format_decode_data.Data())); } printer->Print( + " if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) {\n" + " [worker release];\n" + " }\n" " }\n" " return descriptor;\n" "}\n\n"); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc index cfbb8c52..b63bc0de 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc @@ -59,6 +59,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["enum_verifier"] = type + "_IsValidValue"; (*variables)["enum_desc_func"] = type + "_EnumDescriptor"; + (*variables)["dataTypeSpecific_name"] = "enumDescFunc"; + (*variables)["dataTypeSpecific_value"] = (*variables)["enum_desc_func"]; + const Descriptor* msg_descriptor = descriptor->containing_type(); (*variables)["owning_message_class"] = ClassName(msg_descriptor); } @@ -72,13 +75,6 @@ EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, EnumFieldGenerator::~EnumFieldGenerator() {} -void EnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - printer->Print( - variables_, - " .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n"); -} - void EnumFieldGenerator::GenerateCFunctionDeclarations( io::Printer* printer) const { if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) { @@ -145,13 +141,6 @@ void RepeatedEnumFieldGenerator::FinishInitialization(void) { "// |" + variables_["name"] + "| contains |" + variables_["storage_type"] + "|\n"; } -void RepeatedEnumFieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - printer->Print( - variables_, - " .dataTypeSpecific.enumDescFunc = $enum_desc_func$,\n"); -} - } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h index ae2f57e3..946faa81 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h @@ -45,7 +45,6 @@ class EnumFieldGenerator : public SingleFieldGenerator { const Options& options); public: - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; virtual void GenerateCFunctionImplementations(io::Printer* printer) const; virtual void DetermineForwardDeclarations(set* fwd_decls) const; @@ -64,7 +63,6 @@ class RepeatedEnumFieldGenerator : public RepeatedFieldGenerator { public: virtual void FinishInitialization(); - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; protected: RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, diff --git a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc index 4e348393..3f7ab9d3 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_extension.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_extension.cc @@ -114,14 +114,14 @@ void ExtensionGenerator::GenerateStaticVariablesInitialization( printer->Print(vars, "{\n" - " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" - " .dataType = $extension_type$,\n" - " .extendedClass = GPBStringifySymbol($extended_type$),\n" - " .fieldNumber = $number$,\n" " .defaultValue.$default_name$ = $default$,\n" + " .singletonName = GPBStringifySymbol($root_class_and_method_name$),\n" + " .extendedClass = GPBStringifySymbol($extended_type$),\n" " .messageOrGroupClassName = $type$,\n" - " .options = $options$,\n" " .enumDescriptorFunc = $enum_desc_func_name$,\n" + " .fieldNumber = $number$,\n" + " .dataType = $extension_type$,\n" + " .options = $options$,\n" "},\n"); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index 8697e225..7bb9837d 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -28,6 +28,8 @@ // (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 + #include #include #include @@ -75,7 +77,6 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["field_number_name"] = classname + "_FieldNumber_" + capitalized_name; (*variables)["field_number"] = SimpleItoa(descriptor->number()); - (*variables)["has_index"] = SimpleItoa(descriptor->index()); (*variables)["field_type"] = GetCapitalizedType(descriptor); std::vector field_flags; if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); @@ -99,18 +100,9 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["dataTypeSpecific_name"] = "className"; (*variables)["dataTypeSpecific_value"] = "NULL"; - string field_options = descriptor->options().SerializeAsString(); - // Must convert to a standard byte order for packing length into - // a cstring. - uint32 length = ghtonl(field_options.length()); - if (length > 0) { - string bytes((const char*)&length, sizeof(length)); - bytes.append(field_options); - string options_str = "\"" + CEscape(bytes) + "\""; - (*variables)["fieldoptions"] = "\"" + CEscape(bytes) + "\""; - } else { - (*variables)["fieldoptions"] = ""; - } + (*variables)["storage_offset_value"] = + "(uint32_t)offsetof(" + classname + "__storage_, " + camel_case_name + ")"; + (*variables)["storage_offset_comment"] = ""; // Clear some common things so they can be set just when needed. (*variables)["storage_attribute"] = ""; @@ -190,52 +182,54 @@ void FieldGenerator::DetermineForwardDeclarations( } void FieldGenerator::GenerateFieldDescription( - io::Printer* printer) const { - printer->Print( - variables_, - "{\n" - " .name = \"$name$\",\n" - " .number = $field_number_name$,\n" - " .hasIndex = $has_index$,\n" - " .flags = $fieldflags$,\n" - " .dataType = GPBDataType$field_type$,\n" - " .offset = offsetof($classname$__storage_, $name$),\n" - " .defaultValue.$default_name$ = $default$,\n"); - - // TODO(thomasvl): It might be useful to add a CPP wrapper to support - // compiling away the EnumDescriptors. To do that, we'd need a #if here - // to control setting the descriptor vs. the validator, and above in - // SetCommonFieldVariables() we'd want to wrap how we add - // GPBFieldHasDefaultValue to the flags. - - // " .dataTypeSpecific.value* = [something]," - GenerateFieldDescriptionTypeSpecific(printer); - - const string& field_options(variables_.find("fieldoptions")->second); - if (field_options.empty()) { - printer->Print(" .fieldOptions = NULL,\n"); - } else { - // Can't use PrintRaw() here to get the #if/#else/#endif lines completely - // outdented because the need for indent captured on the previous - // printing of a \n and there is no way to get the current indent level - // to call the right number of Outdent()/Indents() to maintain state. + io::Printer* printer, bool include_default) const { + // Printed in the same order as the structure decl. + if (include_default) { printer->Print( variables_, - "#if GPBOBJC_INCLUDE_FIELD_OPTIONS\n" - " .fieldOptions = $fieldoptions$,\n" - "#else\n" - " .fieldOptions = NULL,\n" - "#endif // GPBOBJC_INCLUDE_FIELD_OPTIONS\n"); + "{\n" + " .defaultValue.$default_name$ = $default$,\n" + " .core.name = \"$name$\",\n" + " .core.dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" + " .core.number = $field_number_name$,\n" + " .core.hasIndex = $has_index$,\n" + " .core.offset = $storage_offset_value$,$storage_offset_comment$\n" + " .core.flags = $fieldflags$,\n" + " .core.dataType = GPBDataType$field_type$,\n" + "},\n"); + } else { + printer->Print( + variables_, + "{\n" + " .name = \"$name$\",\n" + " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n" + " .number = $field_number_name$,\n" + " .hasIndex = $has_index$,\n" + " .offset = $storage_offset_value$,$storage_offset_comment$\n" + " .flags = $fieldflags$,\n" + " .dataType = GPBDataType$field_type$,\n" + "},\n"); } - - printer->Print("},\n"); } -void FieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - printer->Print( - variables_, - " .dataTypeSpecific.$dataTypeSpecific_name$ = $dataTypeSpecific_value$,\n"); +void FieldGenerator::SetRuntimeHasBit(int has_index) { + variables_["has_index"] = SimpleItoa(has_index); +} + +void FieldGenerator::SetNoHasBit(void) { + variables_["has_index"] = "GPBNoHasBit"; +} + +int FieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { + return 0; +} + +void FieldGenerator::SetExtraRuntimeHasBitsBase(int index_base) { + // NOTE: src/google/protobuf/compiler/plugin.cc makes use of cerr for some + // error cases, so it seems to be ok to use as a back door for errors. + cerr << "Error: should have overriden SetExtraRuntimeHasBitsBase()." << endl; + cerr.flush(); + abort(); } void FieldGenerator::SetOneofIndexBase(int index_base) { @@ -302,6 +296,14 @@ bool SingleFieldGenerator::WantsHasProperty(void) const { return false; } +bool SingleFieldGenerator::RuntimeUsesHasBit(void) const { + if (descriptor_->containing_oneof() != NULL) { + // The oneof tracks what is set instead. + return false; + } + return true; +} + ObjCObjFieldGenerator::ObjCObjFieldGenerator(const FieldDescriptor* descriptor, const Options& options) : SingleFieldGenerator(descriptor, options) { @@ -347,8 +349,6 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration( RepeatedFieldGenerator::RepeatedFieldGenerator( const FieldDescriptor* descriptor, const Options& options) : ObjCObjFieldGenerator(descriptor, options) { - // Repeated fields don't use the has index. - variables_["has_index"] = "GPBNoHasBit"; // Default to no comment and let the cases needing it fill it in. variables_["array_comment"] = ""; } @@ -402,6 +402,10 @@ bool RepeatedFieldGenerator::WantsHasProperty(void) const { return false; } +bool RepeatedFieldGenerator::RuntimeUsesHasBit(void) const { + return false; // The array having anything is what is used. +} + FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Options& options) : descriptor_(descriptor), @@ -432,12 +436,40 @@ const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { return *extension_generators_[index]; } +int FieldGeneratorMap::CalculateHasBits(void) { + int total_bits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + if (field_generators_[i]->RuntimeUsesHasBit()) { + field_generators_[i]->SetRuntimeHasBit(total_bits); + ++total_bits; + } else { + field_generators_[i]->SetNoHasBit(); + } + int extra_bits = field_generators_[i]->ExtraRuntimeHasBitsNeeded(); + if (extra_bits) { + field_generators_[i]->SetExtraRuntimeHasBitsBase(total_bits); + total_bits += extra_bits; + } + } + return total_bits; +} + void FieldGeneratorMap::SetOneofIndexBase(int index_base) { for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_[i]->SetOneofIndexBase(index_base); } } +bool FieldGeneratorMap::DoesAnyFieldHaveNonZeroDefault(void) const { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (HasNonZeroDefaultValue(descriptor_->field(i))) { + return true; + } + } + + return false; +} + } // namespace objectivec } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.h b/src/google/protobuf/compiler/objectivec/objectivec_field.h index e8a20a72..a3a4b1b6 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.h @@ -61,7 +61,6 @@ class FieldGenerator { // Called by GenerateFieldDescription, exposed for classes that need custom // generation. - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; // Exposed for subclasses to extend, base does nothing. virtual void GenerateCFunctionDeclarations(io::Printer* printer) const; @@ -71,9 +70,16 @@ class FieldGenerator { virtual void DetermineForwardDeclarations(set* fwd_decls) const; // Used during generation, not intended to be extended by subclasses. - void GenerateFieldDescription(io::Printer* printer) const; + void GenerateFieldDescription( + io::Printer* printer, bool include_default) const; void GenerateFieldNumberConstant(io::Printer* printer) const; + // Exposed to get and set the has bits information. + virtual bool RuntimeUsesHasBit(void) const = 0; + void SetRuntimeHasBit(int has_index); + void SetNoHasBit(void); + virtual int ExtraRuntimeHasBitsNeeded(void) const; + virtual void SetExtraRuntimeHasBitsBase(int index_base); void SetOneofIndexBase(int index_base); string variable(const char* key) const { @@ -109,6 +115,8 @@ class SingleFieldGenerator : public FieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; + virtual bool RuntimeUsesHasBit(void) const; + protected: SingleFieldGenerator(const FieldDescriptor* descriptor, const Options& options); @@ -143,6 +151,8 @@ class RepeatedFieldGenerator : public ObjCObjFieldGenerator { virtual void GeneratePropertyImplementation(io::Printer* printer) const; + virtual bool RuntimeUsesHasBit(void) const; + protected: RepeatedFieldGenerator(const FieldDescriptor* descriptor, const Options& options); @@ -162,8 +172,14 @@ class FieldGeneratorMap { const FieldGenerator& get(const FieldDescriptor* field) const; const FieldGenerator& get_extension(int index) const; + // Assigns the has bits and returns the number of bits needed. + int CalculateHasBits(void); + void SetOneofIndexBase(int index_base); + // Check if any field of this message has a non zero default. + bool DoesAnyFieldHaveNonZeroDefault(void) const; + private: const Descriptor* descriptor_; scoped_array > field_generators_; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index 16199884..c58e7530 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -45,7 +45,7 @@ namespace protobuf { // This is also found in GPBBootstrap.h, and needs to be kept in sync. It // is the version check done to ensure generated code works with the current // runtime being used. -const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30000; +const int32 GOOGLE_PROTOBUF_OBJC_GEN_VERSION = 30001; namespace compiler { namespace objectivec { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index b912ea67..fda51807 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -220,11 +220,6 @@ string NameFromFieldDescriptor(const FieldDescriptor* field) { } } -// Escape C++ trigraphs by escaping question marks to \? -string EscapeTrigraphs(const string& to_escape) { - return StringReplace(to_escape, "?", "\\?", true); -} - void PathSplit(const string& path, string* directory, string* basename) { string::size_type last_slash = path.rfind('/'); if (last_slash == string::npos) { @@ -264,6 +259,11 @@ bool IsSpecialName(const string& name, const string* special_names, } // namespace +// Escape C++ trigraphs by escaping question marks to \? +string EscapeTrigraphs(const string& to_escape) { + return StringReplace(to_escape, "?", "\\?", true); +} + string StripProto(const string& filename) { if (HasSuffixString(filename, ".protodevel")) { return StripSuffixString(filename, ".protodevel"); @@ -734,7 +734,7 @@ string DefaultValue(const FieldDescriptor* field) { uint32 length = ghtonl(default_string.length()); string bytes((const char*)&length, sizeof(length)); bytes.append(default_string); - return "(NSData*)\"" + CEscape(bytes) + "\""; + return "(NSData*)\"" + EscapeTrigraphs(CEscape(bytes)) + "\""; } else { return "@\"" + EscapeTrigraphs(CEscape(default_string)) + "\""; } @@ -751,6 +751,50 @@ string DefaultValue(const FieldDescriptor* field) { return NULL; } +bool HasNonZeroDefaultValue(const FieldDescriptor* field) { + // Repeated fields don't have defaults. + if (field->is_repeated()) { + return false; + } + + if (!field->has_default_value()) { + // No custom default set in the proto file. + return false; + } + + // Some proto file set the default to the zero value, so make sure the value + // isn't the zero case. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return field->default_value_int32() != 0; + case FieldDescriptor::CPPTYPE_UINT32: + return field->default_value_uint32() != 0U; + case FieldDescriptor::CPPTYPE_INT64: + return field->default_value_int64() != 0LL; + case FieldDescriptor::CPPTYPE_UINT64: + return field->default_value_uint64() != 0ULL; + case FieldDescriptor::CPPTYPE_DOUBLE: + return field->default_value_double() != 0.0; + case FieldDescriptor::CPPTYPE_FLOAT: + return field->default_value_float() != 0.0f; + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool(); + case FieldDescriptor::CPPTYPE_STRING: { + const string& default_string = field->default_value_string(); + return default_string.length() != 0; + } + case FieldDescriptor::CPPTYPE_ENUM: + return field->default_value_enum()->number() != 0; + case FieldDescriptor::CPPTYPE_MESSAGE: + return false; + } + + // Some compilers report reaching end of function even though all cases of + // the enum are handed in the switch. + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + string BuildFlagsString(const vector& strings) { if (strings.size() == 0) { return "0"; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index a301493e..0db9de94 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -48,6 +48,9 @@ struct Options { string expected_prefixes_path; }; +// Escape C++ trigraphs by escaping question marks to "\?". +string EscapeTrigraphs(const string& to_escape); + // Strips ".proto" or ".protodevel" from the end of a filename. string StripProto(const string& filename); @@ -143,6 +146,7 @@ bool IsReferenceType(const FieldDescriptor* field); string GPBGenericValueFieldName(const FieldDescriptor* field); string DefaultValue(const FieldDescriptor* field); +bool HasNonZeroDefaultValue(const FieldDescriptor* field); string BuildFlagsString(const vector& strings); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc index 2751e936..ac5d8aea 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc @@ -140,13 +140,18 @@ MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, value_field_generator_->variable("storage_type") + "*>"; } } + + variables_["dataTypeSpecific_name"] = + value_field_generator_->variable("dataTypeSpecific_name"); + variables_["dataTypeSpecific_value"] = + value_field_generator_->variable("dataTypeSpecific_value"); } MapFieldGenerator::~MapFieldGenerator() {} void MapFieldGenerator::FinishInitialization(void) { RepeatedFieldGenerator::FinishInitialization(); - // Use the array_comment suport in RepeatedFieldGenerator to output what the + // Use the array_comment support in RepeatedFieldGenerator to output what the // values in the map are. const FieldDescriptor* value_descriptor = descriptor_->message_type()->FindFieldByName("value"); @@ -156,13 +161,6 @@ void MapFieldGenerator::FinishInitialization(void) { } } -void MapFieldGenerator::GenerateFieldDescriptionTypeSpecific( - io::Printer* printer) const { - // Relay it to the value generator to provide enum validator, message - // class, etc. - value_field_generator_->GenerateFieldDescriptionTypeSpecific(printer); -} - void MapFieldGenerator::DetermineForwardDeclarations( set* fwd_decls) const { RepeatedFieldGenerator::DetermineForwardDeclarations(fwd_decls); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h index 7351ea05..bc68a682 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_map_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_map_field.h @@ -46,7 +46,6 @@ class MapFieldGenerator : public RepeatedFieldGenerator { public: virtual void FinishInitialization(void); - virtual void GenerateFieldDescriptionTypeSpecific(io::Printer* printer) const; protected: MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index e0ea8bd2..3ebeeade 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -66,11 +66,12 @@ int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { // The first item in the object structure is our uint32[] for has bits. // We then want to order things to make the instances as small as // possible. So we follow the has bits with: - // 1. Bools (1 byte) - // 2. Anything always 4 bytes - float, *32, enums - // 3. Anything that is always a pointer (they will be 8 bytes on 64 bit + // 1. Anything always 4 bytes - float, *32, enums + // 2. Anything that is always a pointer (they will be 8 bytes on 64 bit // builds and 4 bytes on 32bit builds. - // 4. Anything always 8 bytes - double, *64 + // 3. Anything always 8 bytes - double, *64 + // + // NOTE: Bools aren't listed, they were stored in the has bits. // // Why? Using 64bit builds as an example, this means worse case, we have // enough bools that we overflow 1 byte from 4 byte alignment, so 3 bytes @@ -115,9 +116,9 @@ int OrderGroupForFieldDescriptor(const FieldDescriptor* descriptor) { case FieldDescriptor::TYPE_ENUM: return 2; - // 1 byte. + // 0 bytes. Stored in the has bits. case FieldDescriptor::TYPE_BOOL: - return 1; + return 99; // End of the list (doesn't really matter). } // Some compilers report reaching end of function even though all cases of @@ -404,32 +405,28 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { sort(sorted_extensions.begin(), sorted_extensions.end(), ExtensionRangeOrdering()); - // TODO(thomasvl): Finish optimizing has bit. The current behavior is as - // follows: - // 1. objectivec_field.cc's SetCommonFieldVariables() defaults the has_index - // to the field's index in the list of fields. - // 2. RepeatedFieldGenerator::RepeatedFieldGenerator() sets has_index to - // GPBNoHasBit because repeated fields & map<> fields don't use the has - // bit. - // 3. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative - // index that groups all the elements on of the oneof. - // So in has_storage, we need enough bits for the single fields that aren't - // in any oneof, and then one int32 for each oneof (to store the field - // number). So we could save a little space by not using the field's index - // and instead make a second pass only assigning indexes for the fields - // that would need it. The only savings would come when messages have over - // a multiple of 32 fields with some number being repeated or in oneofs to - // drop the count below that 32 multiple; so it hasn't seemed worth doing - // at the moment. - size_t num_has_bits = descriptor_->field_count(); + // Assign has bits: + // 1. FieldGeneratorMap::CalculateHasBits() loops through the fields seeing + // who needs has bits and assigning them. + // 2. FieldGenerator::SetOneofIndexBase() overrides has_bit with a negative + // index that groups all the elements in the oneof. + size_t num_has_bits = field_generators_.CalculateHasBits(); size_t sizeof_has_storage = (num_has_bits + 31) / 32; + if (sizeof_has_storage == 0) { + // In the case where no field needs has bits, don't let the _has_storage_ + // end up as zero length (zero length arrays are sort of a grey area + // since it has to be at the start of the struct). This also ensures a + // field with only oneofs keeps the required negative indices they need. + sizeof_has_storage = 1; + } // Tell all the fields the oneof base. for (vector::iterator iter = oneof_generators_.begin(); iter != oneof_generators_.end(); ++iter) { (*iter)->SetOneofIndexBase(sizeof_has_storage); } field_generators_.SetOneofIndexBase(sizeof_has_storage); - // Add an int32 for each oneof to store which is set. + // sizeof_has_storage needs enough bits for the single fields that aren't in + // any oneof, and then one int32 for each oneof (to store the field number). sizeof_has_storage += descriptor_->oneof_decl_count(); printer->Print( @@ -456,47 +453,26 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " static GPBDescriptor *descriptor = nil;\n" " if (!descriptor) {\n"); - bool has_oneofs = oneof_generators_.size(); - if (has_oneofs) { - printer->Print( - " static GPBMessageOneofDescription oneofs[] = {\n"); - printer->Indent(); - printer->Indent(); - printer->Indent(); - for (vector::iterator iter = oneof_generators_.begin(); - iter != oneof_generators_.end(); ++iter) { - (*iter)->GenerateDescription(printer); - } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " };\n"); - } - TextFormatDecodeData text_format_decode_data; bool has_fields = descriptor_->field_count() > 0; + bool need_defaults = field_generators_.DoesAnyFieldHaveNonZeroDefault(); + string field_description_type; + if (need_defaults) { + field_description_type = "GPBMessageFieldDescriptionWithDefault"; + } else { + field_description_type = "GPBMessageFieldDescription"; + } if (has_fields) { - // TODO(thomasvl): The plugin's FieldGenerator::GenerateFieldDescription() - // wraps the fieldOptions's value of this structure in an CPP gate so - // they can be compiled away; but that still results in a const char* in - // the structure for a NULL pointer for every message field. If the - // fieldOptions are moved to a separate payload like the TextFormat extra - // data is, then it would shrink that static data shrinking the binaries - // a little more. - // TODO(thomasvl): proto3 syntax doens't need a defaultValue in the - // structure because primitive types are always zero. If we add a second - // structure and a different initializer, we can avoid the wasted static - // storage for every field in a proto3 message. printer->Print( - " static GPBMessageFieldDescription fields[] = {\n"); + " static $field_description_type$ fields[] = {\n", + "field_description_type", field_description_type); printer->Indent(); printer->Indent(); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); ++i) { const FieldGenerator& field_generator = field_generators_.get(sorted_fields[i]); - field_generator.GenerateFieldDescription(printer); + field_generator.GenerateFieldDescription(printer, need_defaults); if (field_generator.needs_textformat_name_support()) { text_format_decode_data.AddString(sorted_fields[i]->number(), field_generator.generated_objc_name(), @@ -510,111 +486,89 @@ void MessageGenerator::GenerateSource(io::Printer* printer) { " };\n"); } - bool has_enums = enum_generators_.size(); - if (has_enums) { - printer->Print( - " static GPBMessageEnumDescription enums[] = {\n"); - printer->Indent(); - printer->Indent(); - printer->Indent(); - for (vector::iterator iter = enum_generators_.begin(); - iter != enum_generators_.end(); ++iter) { - printer->Print("{ .enumDescriptorFunc = $name$_EnumDescriptor },\n", - "name", (*iter)->name()); - } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " };\n"); - } - - bool has_extensions = sorted_extensions.size(); - if (has_extensions) { - printer->Print( - " static GPBExtensionRange ranges[] = {\n"); - printer->Indent(); - printer->Indent(); - printer->Indent(); - for (int i = 0; i < sorted_extensions.size(); i++) { - printer->Print("{ .start = $start$, .end = $end$ },\n", - "start", SimpleItoa(sorted_extensions[i]->start), - "end", SimpleItoa(sorted_extensions[i]->end)); - } - printer->Outdent(); - printer->Outdent(); - printer->Outdent(); - printer->Print( - " };\n"); - } - map vars; vars["classname"] = class_name_; vars["rootclassname"] = root_classname_; vars["fields"] = has_fields ? "fields" : "NULL"; - vars["fields_count"] = - has_fields ? "sizeof(fields) / sizeof(GPBMessageFieldDescription)" : "0"; - vars["oneofs"] = has_oneofs ? "oneofs" : "NULL"; - vars["oneof_count"] = - has_oneofs ? "sizeof(oneofs) / sizeof(GPBMessageOneofDescription)" : "0"; - vars["enums"] = has_enums ? "enums" : "NULL"; - vars["enum_count"] = - has_enums ? "sizeof(enums) / sizeof(GPBMessageEnumDescription)" : "0"; - vars["ranges"] = has_extensions ? "ranges" : "NULL"; - vars["range_count"] = - has_extensions ? "sizeof(ranges) / sizeof(GPBExtensionRange)" : "0"; - vars["wireformat"] = - descriptor_->options().message_set_wire_format() ? "YES" : "NO"; - - if (text_format_decode_data.num_entries() == 0) { - printer->Print( - vars, - " GPBDescriptor *localDescriptor =\n" - " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" - " rootClass:[$rootclassname$ class]\n" - " file:$rootclassname$_FileDescriptor()\n" - " fields:$fields$\n" - " fieldCount:$fields_count$\n" - " oneofs:$oneofs$\n" - " oneofCount:$oneof_count$\n" - " enums:$enums$\n" - " enumCount:$enum_count$\n" - " ranges:$ranges$\n" - " rangeCount:$range_count$\n" - " storageSize:sizeof($classname$__storage_)\n" - " wireFormat:$wireformat$];\n"); + if (has_fields) { + vars["fields_count"] = + "(uint32_t)(sizeof(fields) / sizeof(" + field_description_type + "))"; } else { - vars["extraTextFormatInfo"] = CEscape(text_format_decode_data.Data()); + vars["fields_count"] = "0"; + } + + std::vector init_flags; + if (need_defaults) { + init_flags.push_back("GPBDescriptorInitializationFlag_FieldsWithDefault"); + } + if (descriptor_->options().message_set_wire_format()) { + init_flags.push_back("GPBDescriptorInitializationFlag_WireFormat"); + } + vars["init_flags"] = BuildFlagsString(init_flags); + + printer->Print( + vars, + " GPBDescriptor *localDescriptor =\n" + " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" + " rootClass:[$rootclassname$ class]\n" + " file:$rootclassname$_FileDescriptor()\n" + " fields:$fields$\n" + " fieldCount:$fields_count$\n" + " storageSize:sizeof($classname$__storage_)\n" + " flags:$init_flags$];\n"); + if (oneof_generators_.size() != 0) { printer->Print( - vars, - "#if GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" - " const char *extraTextFormatInfo = NULL;\n" - "#else\n" - " static const char *extraTextFormatInfo = \"$extraTextFormatInfo$\";\n" - "#endif // GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" - " GPBDescriptor *localDescriptor =\n" - " [GPBDescriptor allocDescriptorForClass:[$classname$ class]\n" - " rootClass:[$rootclassname$ class]\n" - " file:$rootclassname$_FileDescriptor()\n" - " fields:$fields$\n" - " fieldCount:$fields_count$\n" - " oneofs:$oneofs$\n" - " oneofCount:$oneof_count$\n" - " enums:$enums$\n" - " enumCount:$enum_count$\n" - " ranges:$ranges$\n" - " rangeCount:$range_count$\n" - " storageSize:sizeof($classname$__storage_)\n" - " wireFormat:$wireformat$\n" - " extraTextFormatInfo:extraTextFormatInfo];\n"); + " static const char *oneofs[] = {\n"); + for (vector::iterator iter = oneof_generators_.begin(); + iter != oneof_generators_.end(); ++iter) { + printer->Print( + " \"$name$\",\n", + "name", (*iter)->DescriptorName()); } printer->Print( - " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" - " descriptor = localDescriptor;\n" - " }\n" - " return descriptor;\n" - "}\n\n" - "@end\n\n"); + " };\n" + " [localDescriptor setupOneofs:oneofs\n" + " count:(uint32_t)(sizeof(oneofs) / sizeof(char*))\n" + " firstHasIndex:$first_has_index$];\n", + "first_has_index", oneof_generators_[0]->HasIndexAsString()); + } + if (text_format_decode_data.num_entries() != 0) { + const string text_format_data_str(text_format_decode_data.Data()); + printer->Print( + "#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n" + " static const char *extraTextFormatInfo ="); + static const int kBytesPerLine = 40; // allow for escaping + for (int i = 0; i < text_format_data_str.size(); i += kBytesPerLine) { + printer->Print( + "\n \"$data$\"", + "data", EscapeTrigraphs( + CEscape(text_format_data_str.substr(i, kBytesPerLine)))); + } + printer->Print( + ";\n" + " [localDescriptor setupExtraTextInfo:extraTextFormatInfo];\n" + "#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS\n"); + } + if (sorted_extensions.size() != 0) { + printer->Print( + " static const GPBExtensionRange ranges[] = {\n"); + for (int i = 0; i < sorted_extensions.size(); i++) { + printer->Print(" { .start = $start$, .end = $end$ },\n", + "start", SimpleItoa(sorted_extensions[i]->start), + "end", SimpleItoa(sorted_extensions[i]->end)); + } + printer->Print( + " };\n" + " [localDescriptor setupExtensionRanges:ranges\n" + " count:(uint32_t)(sizeof(ranges) / sizeof(GPBExtensionRange))];\n"); + } + printer->Print( + " NSAssert(descriptor == nil, @\"Startup recursed!\");\n" + " descriptor = localDescriptor;\n" + " }\n" + " return descriptor;\n" + "}\n\n" + "@end\n\n"); for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc index 24e6df07..44bafd7f 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc @@ -120,17 +120,16 @@ void OneofGenerator::GenerateClearFunctionImplementation(io::Printer* printer) { "void $owning_message_class$_Clear$capitalized_name$OneOfCase($owning_message_class$ *message) {\n" " GPBDescriptor *descriptor = [message descriptor];\n" " GPBOneofDescriptor *oneof = descriptor->oneofs_[$raw_index$];\n" - " GPBMaybeClearOneof(message, oneof, 0);\n" + " GPBMaybeClearOneof(message, oneof, $index$, 0);\n" "}\n"); } -void OneofGenerator::GenerateDescription(io::Printer* printer) { - printer->Print( - variables_, - "{\n" - " .name = \"$name$\",\n" - " .index = $index$,\n" - "},\n"); +string OneofGenerator::DescriptorName(void) const { + return variables_.find("name")->second; +} + +string OneofGenerator::HasIndexAsString(void) const { + return variables_.find("index")->second; } } // namespace objectivec diff --git a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h index bcba82da..3d9df4db 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_oneof.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_oneof.h @@ -61,7 +61,9 @@ class OneofGenerator { void GeneratePropertyImplementation(io::Printer* printer); void GenerateClearFunctionImplementation(io::Printer* printer); - void GenerateDescription(io::Printer* printer); + + string DescriptorName(void) const; + string HasIndexAsString(void) const; private: const OneofDescriptor* descriptor_; diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc index ea7f1b91..d49350f4 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc @@ -134,6 +134,32 @@ PrimitiveFieldGenerator::PrimitiveFieldGenerator( PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} +void PrimitiveFieldGenerator::GenerateFieldStorageDeclaration( + io::Printer* printer) const { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Nothing, BOOLs are stored in the has bits. + } else { + SingleFieldGenerator::GenerateFieldStorageDeclaration(printer); + } +} + +int PrimitiveFieldGenerator::ExtraRuntimeHasBitsNeeded(void) const { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Reserve a bit for the storage of the boolean. + return 1; + } + return 0; +} + +void PrimitiveFieldGenerator::SetExtraRuntimeHasBitsBase(int has_base) { + if (GetObjectiveCType(descriptor_) == OBJECTIVECTYPE_BOOLEAN) { + // Set into the offset the has bit to use for the actual value. + variables_["storage_offset_value"] = SimpleItoa(has_base); + variables_["storage_offset_comment"] = + " // Stored in _has_storage_ to save space."; + } +} + PrimitiveObjFieldGenerator::PrimitiveObjFieldGenerator( const FieldDescriptor* descriptor, const Options& options) : ObjCObjFieldGenerator(descriptor, options) { diff --git a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h index 87139afb..69bb1fdd 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h @@ -49,6 +49,11 @@ class PrimitiveFieldGenerator : public SingleFieldGenerator { const Options& options); virtual ~PrimitiveFieldGenerator(); + virtual void GenerateFieldStorageDeclaration(io::Printer* printer) const; + + virtual int ExtraRuntimeHasBitsNeeded(void) const; + virtual void SetExtraRuntimeHasBitsBase(int index_base); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); }; From 0d32ab37fa94134427478d6776108e7cdb3e5e15 Mon Sep 17 00:00:00 2001 From: alien Date: Thu, 17 Mar 2016 15:19:04 +0300 Subject: [PATCH 025/123] csharp: add support for the json_name option Conflicts: csharp/src/Google.Protobuf/JsonFormatter.cs --- csharp/protos/unittest_issues.proto | 9 +- csharp/src/Google.Protobuf.Test/IssuesTest.cs | 18 ++ .../TestProtos/UnittestIssues.cs | 173 +++++++++++++++++- csharp/src/Google.Protobuf/JsonFormatter.cs | 7 +- .../Reflection/FieldDescriptor.cs | 6 + .../Reflection/MessageDescriptor.cs | 2 + 6 files changed, 207 insertions(+), 8 deletions(-) diff --git a/csharp/protos/unittest_issues.proto b/csharp/protos/unittest_issues.proto index 989b3dc4..f120516c 100644 --- a/csharp/protos/unittest_issues.proto +++ b/csharp/protos/unittest_issues.proto @@ -116,4 +116,11 @@ message TestJsonFieldOrdering { string o2_string = 3; } -} \ No newline at end of file +} + +message TestJsonName { + // json_name field options are not properly handled during deserialization + string name = 1; + string description = 2 [json_name = "desc"]; + string guid = 3 [json_name = "exid"]; +} diff --git a/csharp/src/Google.Protobuf.Test/IssuesTest.cs b/csharp/src/Google.Protobuf.Test/IssuesTest.cs index a0350035..5b432edf 100644 --- a/csharp/src/Google.Protobuf.Test/IssuesTest.cs +++ b/csharp/src/Google.Protobuf.Test/IssuesTest.cs @@ -59,5 +59,23 @@ namespace Google.Protobuf // Underscores aren't reflected in the JSON. Assert.AreEqual("{ \"types\": 10, \"descriptor\": 20 }", message.ToString()); } + + [Test] + public void JsonNameParseTest() + { + var settings = new JsonParser.Settings(10, TypeRegistry.FromFiles(UnittestIssuesReflection.Descriptor)); + var parser = new JsonParser(settings); + + Assert.AreEqual(new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }, + parser.Parse("{ \"name\": \"test\", \"desc\": \"test2\", \"guid\": \"test3\" }")); + } + + [Test] + public void JsonNameFormatTest() + { + var message = new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }; + Assert.AreEqual("{ \"name\": \"test\", \"desc\": \"test2\", \"exid\": \"test3\" }", + JsonFormatter.Default.Format(message)); + } } } diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs index 16176a33..586f01c8 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs @@ -42,10 +42,12 @@ namespace UnitTest.Issues.TestProtos { "CgtwbGFpbl9pbnQzMhgEIAEoBRITCglvMV9zdHJpbmcYAiABKAlIABISCghv", "MV9pbnQzMhgFIAEoBUgAEhQKDHBsYWluX3N0cmluZxgBIAEoCRISCghvMl9p", "bnQzMhgGIAEoBUgBEhMKCW8yX3N0cmluZxgDIAEoCUgBQgQKAm8xQgQKAm8y", - "KlUKDE5lZ2F0aXZlRW51bRIWChJORUdBVElWRV9FTlVNX1pFUk8QABIWCglG", - "aXZlQmVsb3cQ+///////////ARIVCghNaW51c09uZRD///////////8BKi4K", - "DkRlcHJlY2F0ZWRFbnVtEhMKD0RFUFJFQ0FURURfWkVSTxAAEgcKA29uZRAB", - "Qh9IAaoCGlVuaXRUZXN0Lklzc3Vlcy5UZXN0UHJvdG9zYgZwcm90bzM=")); + "IksKDFRlc3RKc29uTmFtZRIMCgRuYW1lGAEgASgJEhkKC2Rlc2NyaXB0aW9u", + "GAIgASgJUgRkZXNjEhIKBGd1aWQYAyABKAlSBGV4aWQqVQoMTmVnYXRpdmVF", + "bnVtEhYKEk5FR0FUSVZFX0VOVU1fWkVSTxAAEhYKCUZpdmVCZWxvdxD7////", + "//////8BEhUKCE1pbnVzT25lEP///////////wEqLgoORGVwcmVjYXRlZEVu", + "dW0SEwoPREVQUkVDQVRFRF9aRVJPEAASBwoDb25lEAFCH0gBqgIaVW5pdFRl", + "c3QuSXNzdWVzLlRlc3RQcm90b3NiBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, new pbr::GeneratedClrTypeInfo[] { @@ -55,7 +57,8 @@ namespace UnitTest.Issues.TestProtos { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage), global::UnitTest.Issues.TestProtos.DeprecatedFieldsMessage.Parser, new[]{ "PrimitiveValue", "PrimitiveArray", "MessageValue", "MessageArray", "EnumValue", "EnumArray" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ItemField), global::UnitTest.Issues.TestProtos.ItemField.Parser, new[]{ "Item" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames), global::UnitTest.Issues.TestProtos.ReservedNames.Parser, new[]{ "Types_", "Descriptor_" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.ReservedNames.Types.SomeNestedType), global::UnitTest.Issues.TestProtos.ReservedNames.Types.SomeNestedType.Parser, null, null, null, null)}), - new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering), global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering.Parser, new[]{ "PlainInt32", "O1String", "O1Int32", "PlainString", "O2Int32", "O2String" }, new[]{ "O1", "O2" }, null, null) + new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering), global::UnitTest.Issues.TestProtos.TestJsonFieldOrdering.Parser, new[]{ "PlainInt32", "O1String", "O1Int32", "PlainString", "O2Int32", "O2String" }, new[]{ "O1", "O2" }, null, null), + new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.TestJsonName), global::UnitTest.Issues.TestProtos.TestJsonName.Parser, new[]{ "Name", "Description", "Guid" }, null, null, null) })); } #endregion @@ -1399,6 +1402,166 @@ namespace UnitTest.Issues.TestProtos { } + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + public sealed partial class TestJsonName : pb::IMessage { + private static readonly pb::MessageParser _parser = new pb::MessageParser(() => new TestJsonName()); + public static pb::MessageParser Parser { get { return _parser; } } + + public static pbr::MessageDescriptor Descriptor { + get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[7]; } + } + + pbr::MessageDescriptor pb::IMessage.Descriptor { + get { return Descriptor; } + } + + public TestJsonName() { + OnConstruction(); + } + + partial void OnConstruction(); + + public TestJsonName(TestJsonName other) : this() { + name_ = other.name_; + description_ = other.description_; + guid_ = other.guid_; + } + + public TestJsonName Clone() { + return new TestJsonName(this); + } + + /// Field number for the "name" field. + public const int NameFieldNumber = 1; + private string name_ = ""; + /// + /// json_name field options are not properly handled during deserialization + /// + public string Name { + get { return name_; } + set { + name_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "description" field. + public const int DescriptionFieldNumber = 2; + private string description_ = ""; + public string Description { + get { return description_; } + set { + description_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + /// Field number for the "guid" field. + public const int GuidFieldNumber = 3; + private string guid_ = ""; + public string Guid { + get { return guid_; } + set { + guid_ = pb::ProtoPreconditions.CheckNotNull(value, "value"); + } + } + + public override bool Equals(object other) { + return Equals(other as TestJsonName); + } + + public bool Equals(TestJsonName other) { + if (ReferenceEquals(other, null)) { + return false; + } + if (ReferenceEquals(other, this)) { + return true; + } + if (Name != other.Name) return false; + if (Description != other.Description) return false; + if (Guid != other.Guid) return false; + return true; + } + + public override int GetHashCode() { + int hash = 1; + if (Name.Length != 0) hash ^= Name.GetHashCode(); + if (Description.Length != 0) hash ^= Description.GetHashCode(); + if (Guid.Length != 0) hash ^= Guid.GetHashCode(); + return hash; + } + + public override string ToString() { + return pb::JsonFormatter.ToDiagnosticString(this); + } + + public void WriteTo(pb::CodedOutputStream output) { + if (Name.Length != 0) { + output.WriteRawTag(10); + output.WriteString(Name); + } + if (Description.Length != 0) { + output.WriteRawTag(18); + output.WriteString(Description); + } + if (Guid.Length != 0) { + output.WriteRawTag(26); + output.WriteString(Guid); + } + } + + public int CalculateSize() { + int size = 0; + if (Name.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Name); + } + if (Description.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Description); + } + if (Guid.Length != 0) { + size += 1 + pb::CodedOutputStream.ComputeStringSize(Guid); + } + return size; + } + + public void MergeFrom(TestJsonName other) { + if (other == null) { + return; + } + if (other.Name.Length != 0) { + Name = other.Name; + } + if (other.Description.Length != 0) { + Description = other.Description; + } + if (other.Guid.Length != 0) { + Guid = other.Guid; + } + } + + public void MergeFrom(pb::CodedInputStream input) { + uint tag; + while ((tag = input.ReadTag()) != 0) { + switch(tag) { + default: + input.SkipLastField(); + break; + case 10: { + Name = input.ReadString(); + break; + } + case 18: { + Description = input.ReadString(); + break; + } + case 26: { + Guid = input.ReadString(); + break; + } + } + } + } + + } + #endregion } diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index eb959c9f..1b5349e9 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -237,11 +237,14 @@ namespace Google.Protobuf { writer.Write(PropertySeparator); } - WriteString(writer, ToCamelCase(accessor.Descriptor.Name)); + + WriteString(writer, string.IsNullOrEmpty(accessor.Descriptor.JsonName) ? + ToCamelCase(accessor.Descriptor.Name) : accessor.Descriptor.JsonName); writer.Write(NameValueSeparator); WriteValue(writer, value); + first = false; - } + } return !first; } diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs index c6caaec6..8cfdb779 100644 --- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs @@ -90,6 +90,12 @@ namespace Google.Protobuf.Reflection /// public override string Name { get { return proto.Name; } } + + /// + /// The json_name option of the descriptor's target. + /// + public string JsonName { get { return proto.JsonName; } } + internal FieldDescriptorProto Proto { get { return proto; } } /// diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs index f5798d1e..63f168ca 100644 --- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs @@ -104,6 +104,8 @@ namespace Google.Protobuf.Reflection { map[JsonFormatter.ToCamelCase(field.Name)] = field; map[field.Name] = field; + if (!string.IsNullOrEmpty(field.JsonName)) + map[field.JsonName] = field; } return new ReadOnlyDictionary(map); } From 4d98369f6d00dbdaa45ee2b91f1ec149a60ef905 Mon Sep 17 00:00:00 2001 From: Pradeep Gollakota Date: Fri, 18 Mar 2016 23:06:14 -0700 Subject: [PATCH 026/123] Allow custom URLs for Any in JsonFormat - Using custom URL for types in Any will no longer throw an InvalidProtocolBufferException in JsonFormat - Fixes #1128 --- .../src/main/java/com/google/protobuf/util/JsonFormat.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) 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 d13ff0ed..c9a28c9e 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 @@ -951,16 +951,15 @@ public class JsonFormat { } } - private static final String TYPE_URL_PREFIX = "type.googleapis.com"; - + private static String getTypeName(String typeUrl) throws InvalidProtocolBufferException { String[] parts = typeUrl.split("/"); - if (parts.length != 2 || !parts[0].equals(TYPE_URL_PREFIX)) { + if (parts.length == 1) { throw new InvalidProtocolBufferException( "Invalid type url found: " + typeUrl); } - return parts[1]; + return parts[parts.length - 1]; } private static class ParserImpl { From bd41a39f693d8307d407e42b634b315e075b6c8f Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Mon, 21 Mar 2016 11:11:14 -0400 Subject: [PATCH 027/123] Only create the readonlySemaphore on demand. This will lower the amount of dispatch_semaphores created per Message when the full object tree isn't walked in a way that would require them to be created. Uses a dispatch_once_t for one time init of the dispatch_semaphore. --- objectivec/GPBMessage.m | 9 ++++++--- objectivec/GPBMessage_PackagePrivate.h | 12 ++++++++++++ objectivec/GPBUtilities.m | 1 + 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 94d179be..3da85b5b 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -556,6 +556,7 @@ static id GetArrayIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { id array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!array) { // Check again after getting the lock. + GPBPrepareReadOnlySemaphore(self); dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); array = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!array) { @@ -586,6 +587,7 @@ static id GetMapIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { id dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!dict) { // Check again after getting the lock. + GPBPrepareReadOnlySemaphore(self); dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); dict = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!dict) { @@ -791,8 +793,6 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { if ((self = [super init])) { messageStorage_ = (GPBMessage_StoragePtr)( ((uint8_t *)self) + class_getInstanceSize([self class])); - - readOnlySemaphore_ = dispatch_semaphore_create(1); } return self; @@ -868,7 +868,9 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { - (void)dealloc { [self internalClear:NO]; NSCAssert(!autocreator_, @"Autocreator was not cleared before dealloc."); - dispatch_release(readOnlySemaphore_); + if (readOnlySemaphore_) { + dispatch_release(readOnlySemaphore_); + } [super dealloc]; } @@ -1706,6 +1708,7 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { } // Check for an autocreated value. + GPBPrepareReadOnlySemaphore(self); dispatch_semaphore_wait(readOnlySemaphore_, DISPATCH_TIME_FOREVER); value = [autocreatedExtensionMap_ objectForKey:extension]; if (!value) { diff --git a/objectivec/GPBMessage_PackagePrivate.h b/objectivec/GPBMessage_PackagePrivate.h index b7e24fc9..478db2cf 100644 --- a/objectivec/GPBMessage_PackagePrivate.h +++ b/objectivec/GPBMessage_PackagePrivate.h @@ -67,6 +67,10 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr; // priority inversion: // http://mjtsai.com/blog/2015/12/16/osspinlock-is-unsafe/ // https://lists.swift.org/pipermail/swift-dev/Week-of-Mon-20151214/000372.html + // Use of readOnlySemaphore_ must be prefaced by a call to + // GPBPrepareReadOnlySemaphore to ensure it has been created. This allows + // readOnlySemaphore_ to be only created when actually needed. + dispatch_once_t readOnlySemaphoreCreationOnce_; dispatch_semaphore_t readOnlySemaphore_; } @@ -103,6 +107,14 @@ typedef struct GPBMessage_Storage *GPBMessage_StoragePtr; CF_EXTERN_C_BEGIN + +// Call this before using the readOnlySemaphore_. This ensures it is created only once. +NS_INLINE void GPBPrepareReadOnlySemaphore(GPBMessage *self) { + dispatch_once(&self->readOnlySemaphoreCreationOnce_, ^{ + self->readOnlySemaphore_ = dispatch_semaphore_create(1); + }); +} + // Returns a new instance that was automatically created by |autocreator| for // its field |field|. GPBMessage *GPBCreateMessageWithAutocreator(Class msgClass, diff --git a/objectivec/GPBUtilities.m b/objectivec/GPBUtilities.m index 3e9d11c0..447c749a 100644 --- a/objectivec/GPBUtilities.m +++ b/objectivec/GPBUtilities.m @@ -412,6 +412,7 @@ id GPBGetObjectIvarWithField(GPBMessage *self, GPBFieldDescriptor *field) { return field.defaultValue.valueMessage; } + GPBPrepareReadOnlySemaphore(self); dispatch_semaphore_wait(self->readOnlySemaphore_, DISPATCH_TIME_FOREVER); GPBMessage *result = GPBGetObjectIvarWithFieldNoAutocreate(self, field); if (!result) { From 64dfb5f80a4c09ebf09d7f5c2bf0655c840e690b Mon Sep 17 00:00:00 2001 From: topillar Date: Tue, 22 Mar 2016 23:45:41 +0800 Subject: [PATCH 028/123] Update coded_stream.h fix warning treated as error prevents building on 64-bit windows. --- src/google/protobuf/io/coded_stream.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index e3771003..c81a33ac 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -1136,7 +1136,7 @@ inline void CodedOutputStream::WriteVarint32(uint32 value) { // this write won't cross the end, so we can skip the checks. uint8* target = buffer_; uint8* end = WriteVarint32ToArray(value, target); - int size = end - target; + int size = static_cast(end - target); Advance(size); } else { WriteVarint32SlowPath(value); From d5a573274df4fabd2afd34b5d98bc7ccf5cb5229 Mon Sep 17 00:00:00 2001 From: Steven Parkes Date: Tue, 22 Mar 2016 17:56:07 -0700 Subject: [PATCH 029/123] export well known protos --- BUILD | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/BUILD b/BUILD index 2cb96b20..e35a2e8e 100644 --- a/BUILD +++ b/BUILD @@ -194,6 +194,12 @@ RELATIVE_WELL_KNOWN_PROTOS = [ WELL_KNOWN_PROTOS = ["src/" + s for s in RELATIVE_WELL_KNOWN_PROTOS] +filegroup( + name = "well_known_protos", + srcs = WELL_KNOWN_PROTOS, + visibility = ["//visibility:public"], +) + cc_proto_library( name = "cc_wkt_protos", srcs = WELL_KNOWN_PROTOS, From 3f917447e7805fb470bac9487e2dcc19da3c545b Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Thu, 24 Mar 2016 15:25:21 -0400 Subject: [PATCH 030/123] The message was autoreleased, the -releases are an over release. --- objectivec/GPBMessage.m | 2 -- 1 file changed, 2 deletions(-) diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 3da85b5b..0e1599dc 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -1920,7 +1920,6 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { } } @catch (NSException *exception) { - [message release]; message = nil; if (errorPtr) { *errorPtr = MessageErrorWithReason(GPBMessageErrorCodeMalformedData, @@ -1929,7 +1928,6 @@ static GPBUnknownFieldSet *GetOrMakeUnknownFields(GPBMessage *self) { } #ifdef DEBUG if (message && !message.initialized) { - [message release]; message = nil; if (errorPtr) { *errorPtr = MessageError(GPBMessageErrorCodeMissingRequiredField, nil); From 8d47d7873e7cf332d30e7a661a4ec9cc4d794ad8 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 29 Mar 2016 09:21:50 -0400 Subject: [PATCH 031/123] Mark iOS tests as able to fail. Travis updated their images to include an xctool that can randomly kill tests, so mark them as flaky to avoid turning things red. --- .travis.yml | 9 +++++++++ travis.sh | 8 +------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9bc4d88f..60c0427d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -71,5 +71,14 @@ matrix: # we moved to an OS X image that is 10.11. - os: osx env: CONFIG=python_cpp + # xctool 0.2.8 seems to have a bug where it randomly kills tests saying + # they failed. + # https://github.com/facebook/xctool/issues/619 + # https://github.com/google/protobuf/issues/1232 + # travis updated their images to include 0.2.8: + # https://blog.travis-ci.com/2016-03-23-xcode-image-updates + # Mark the iOS test as flakey so these failures don't turn things red. + - os: osx + env: CONFIG=objectivec_ios notifications: email: false diff --git a/travis.sh b/travis.sh index ff5e99d5..f039b392 100755 --- a/travis.sh +++ b/travis.sh @@ -171,13 +171,7 @@ internal_objectivec_common () { # http://docs.travis-ci.com/user/osx-ci-environment/ # We don't use a before_install because we test multiple OSes. brew update - # xctool 0.2.8 seems to have a bug where it randomly kills tests saying - # they failed. Disabling the updates, but letting it report about being - # updates as a hint that this needs to eventually get re-enabled. - # https://github.com/facebook/xctool/issues/619 - # https://github.com/google/protobuf/issues/1232 - brew outdated xctool || true - #brew outdated xctool || brew upgrade xctool + brew outdated xctool || brew upgrade xctool # Reused the build script that takes care of configuring and ensuring things # are up to date. Xcode and conformance tests will be directly invoked. objectivec/DevTools/full_mac_build.sh \ From 6f8dd2115b3ed07819a48dfa78b15770dfa2c450 Mon Sep 17 00:00:00 2001 From: alien Date: Tue, 29 Mar 2016 20:56:32 +0300 Subject: [PATCH 032/123] Code review fixes --- csharp/protos/unittest_issues.proto | 2 +- csharp/src/Google.Protobuf.Test/IssuesTest.cs | 1 + csharp/src/Google.Protobuf/JsonFormatter.cs | 3 +-- csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs | 2 +- csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs | 4 +--- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/csharp/protos/unittest_issues.proto b/csharp/protos/unittest_issues.proto index f120516c..6c9f7634 100644 --- a/csharp/protos/unittest_issues.proto +++ b/csharp/protos/unittest_issues.proto @@ -119,7 +119,7 @@ message TestJsonFieldOrdering { } message TestJsonName { - // json_name field options are not properly handled during deserialization + // Message for testing the effects for of the json_name option string name = 1; string description = 2 [json_name = "desc"]; string guid = 3 [json_name = "exid"]; diff --git a/csharp/src/Google.Protobuf.Test/IssuesTest.cs b/csharp/src/Google.Protobuf.Test/IssuesTest.cs index 5b432edf..a38d6b08 100644 --- a/csharp/src/Google.Protobuf.Test/IssuesTest.cs +++ b/csharp/src/Google.Protobuf.Test/IssuesTest.cs @@ -66,6 +66,7 @@ namespace Google.Protobuf var settings = new JsonParser.Settings(10, TypeRegistry.FromFiles(UnittestIssuesReflection.Descriptor)); var parser = new JsonParser(settings); + // It is safe to use either original field name or explicitly specified json_name Assert.AreEqual(new TestJsonName { Name = "test", Description = "test2", Guid = "test3" }, parser.Parse("{ \"name\": \"test\", \"desc\": \"test2\", \"guid\": \"test3\" }")); } diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index 1b5349e9..cbd9366c 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -238,8 +238,7 @@ namespace Google.Protobuf writer.Write(PropertySeparator); } - WriteString(writer, string.IsNullOrEmpty(accessor.Descriptor.JsonName) ? - ToCamelCase(accessor.Descriptor.Name) : accessor.Descriptor.JsonName); + WriteString(writer, accessor.Descriptor.JsonName); writer.Write(NameValueSeparator); WriteValue(writer, value); diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs index 8cfdb779..6083f171 100644 --- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs @@ -94,7 +94,7 @@ namespace Google.Protobuf.Reflection /// /// The json_name option of the descriptor's target. /// - public string JsonName { get { return proto.JsonName; } } + public string JsonName { get { return proto.JsonName == "" ? JsonFormatter.ToCamelCase(proto.Name) : proto.JsonName; } } internal FieldDescriptorProto Proto { get { return proto; } } diff --git a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs index 63f168ca..f5a835e5 100644 --- a/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/MessageDescriptor.cs @@ -102,10 +102,8 @@ namespace Google.Protobuf.Reflection var map = new Dictionary(); foreach (var field in fields) { - map[JsonFormatter.ToCamelCase(field.Name)] = field; map[field.Name] = field; - if (!string.IsNullOrEmpty(field.JsonName)) - map[field.JsonName] = field; + map[field.JsonName] = field; } return new ReadOnlyDictionary(map); } From e164f1083fd08e61bbad9c79a37058f1aeca4086 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Tue, 29 Mar 2016 15:25:49 -0700 Subject: [PATCH 033/123] Use the T() instead of NULL for the default value. The template can be specialized on primitives, e.g. double, where converting NULL will trigger a warning. --- src/google/protobuf/stubs/statusor.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/google/protobuf/stubs/statusor.h b/src/google/protobuf/stubs/statusor.h index ad848701..29f869ad 100644 --- a/src/google/protobuf/stubs/statusor.h +++ b/src/google/protobuf/stubs/statusor.h @@ -224,7 +224,7 @@ inline StatusOr& StatusOr::operator=(const StatusOr& other) { template template inline StatusOr::StatusOr(const StatusOr& other) - : status_(other.status_), value_(other.status_.ok() ? other.value_ : NULL) { + : status_(other.status_), value_(other.status_.ok() ? other.value_ : T()) { } template From 71e8dca08312d9f9d76db6c2f762f8b395d05226 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 30 Mar 2016 09:42:37 +0100 Subject: [PATCH 034/123] Refactoring of FieldDescriptor This makes no externally visible behavioral changes. Internally and non-behaviorally: - We use a field (compiler-generated) to store the JsonName to avoid recomputing it repeatedly - The documentation for JsonName is updated to reflect the meaning better - Readonly autoprops and expression-bodied properties used where possible --- .../Reflection/FieldDescriptor.cs | 100 +++++++----------- 1 file changed, 39 insertions(+), 61 deletions(-) diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs index 6083f171..de6e5717 100644 --- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs @@ -30,9 +30,8 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endregion -using System; -using System.Linq; using Google.Protobuf.Compatibility; +using System; namespace Google.Protobuf.Reflection { @@ -41,20 +40,35 @@ namespace Google.Protobuf.Reflection /// public sealed class FieldDescriptor : DescriptorBase, IComparable { - private readonly FieldDescriptorProto proto; private EnumDescriptor enumType; private MessageDescriptor messageType; - private readonly MessageDescriptor containingType; - private readonly OneofDescriptor containingOneof; private FieldType fieldType; private readonly string propertyName; // Annoyingly, needed in Crosslink. private IFieldAccessor accessor; + /// + /// Get the field's containing message type. + /// + public MessageDescriptor ContainingType { get; } + + /// + /// Returns the oneof containing this field, or null if it is not part of a oneof. + /// + public OneofDescriptor ContainingOneof { get; } + + /// + /// The effective JSON name for this field. This is usually the lower-camel-cased form of the field name, + /// but can be overridden using the json_name option in the .proto file. + /// + public string JsonName { get; } + + internal FieldDescriptorProto Proto { get; } + internal FieldDescriptor(FieldDescriptorProto proto, FileDescriptor file, MessageDescriptor parent, int index, string propertyName) : base(file, file.ComputeFullName(parent, proto.Name), index) { - this.proto = proto; + Proto = proto; if (proto.Type != 0) { fieldType = GetFieldTypeFromProtoType(proto.Type); @@ -64,7 +78,7 @@ namespace Google.Protobuf.Reflection { throw new DescriptorValidationException(this, "Field numbers must be positive integers."); } - containingType = parent; + ContainingType = parent; // OneofIndex "defaults" to -1 due to a hack in FieldDescriptor.OnConstruction. if (proto.OneofIndex != -1) { @@ -73,7 +87,7 @@ namespace Google.Protobuf.Reflection throw new DescriptorValidationException(this, $"FieldDescriptorProto.oneof_index is out of range for type {parent.Name}"); } - containingOneof = parent.Oneofs[proto.OneofIndex]; + ContainingOneof = parent.Oneofs[proto.OneofIndex]; } file.DescriptorPool.AddSymbol(this); @@ -83,20 +97,14 @@ namespace Google.Protobuf.Reflection // We could trust the generated code and check whether the type of the property is // a MapField, but that feels a tad nasty. this.propertyName = propertyName; + JsonName = Proto.JsonName == "" ? JsonFormatter.ToCamelCase(Proto.Name) : Proto.JsonName; } + /// /// The brief name of the descriptor's target. /// - public override string Name { get { return proto.Name; } } - - - /// - /// The json_name option of the descriptor's target. - /// - public string JsonName { get { return proto.JsonName == "" ? JsonFormatter.ToCamelCase(proto.Name) : proto.JsonName; } } - - internal FieldDescriptorProto Proto { get { return proto; } } + public override string Name => Proto.Name; /// /// Returns the accessor for this field. @@ -116,7 +124,7 @@ namespace Google.Protobuf.Reflection /// and this property will return null. /// /// - public IFieldAccessor Accessor { get { return accessor; } } + public IFieldAccessor Accessor => accessor; /// /// Maps a field type as included in the .proto file to a FieldType. @@ -169,62 +177,32 @@ namespace Google.Protobuf.Reflection /// /// Returns true if this field is a repeated field; false otherwise. /// - public bool IsRepeated - { - get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; } - } + public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; /// /// Returns true if this field is a map field; false otherwise. /// - public bool IsMap - { - get { return fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry; } - } + public bool IsMap => fieldType == FieldType.Message && messageType.Proto.Options != null && messageType.Proto.Options.MapEntry; /// /// Returns true if this field is a packed, repeated field; false otherwise. /// - public bool IsPacked - { + public bool IsPacked => // Note the || rather than && here - we're effectively defaulting to packed, because that *is* // the default in proto3, which is all we support. We may give the wrong result for the protos // within descriptor.proto, but that's okay, as they're never exposed and we don't use IsPacked // within the runtime. - get { return Proto.Options == null || Proto.Options.Packed; } - } - - /// - /// Get the field's containing message type. - /// - public MessageDescriptor ContainingType - { - get { return containingType; } - } - - /// - /// Returns the oneof containing this field, or null if it is not part of a oneof. - /// - public OneofDescriptor ContainingOneof - { - get { return containingOneof; } - } - + Proto.Options == null || Proto.Options.Packed; + /// /// Returns the type of the field. /// - public FieldType FieldType - { - get { return fieldType; } - } + public FieldType FieldType => fieldType; /// /// Returns the field number declared in the proto file. /// - public int FieldNumber - { - get { return Proto.Number; } - } + public int FieldNumber => Proto.Number; /// /// Compares this descriptor with another one, ordering in "canonical" order @@ -234,7 +212,7 @@ namespace Google.Protobuf.Reflection /// public int CompareTo(FieldDescriptor other) { - if (other.containingType != containingType) + if (other.ContainingType != ContainingType) { throw new ArgumentException("FieldDescriptors can only be compared to other FieldDescriptors " + "for fields of the same message type."); @@ -337,14 +315,14 @@ namespace Google.Protobuf.Reflection File.DescriptorPool.AddFieldByNumber(this); - if (containingType != null && containingType.Proto.Options != null && containingType.Proto.Options.MessageSetWireFormat) + if (ContainingType != null && ContainingType.Proto.Options != null && ContainingType.Proto.Options.MessageSetWireFormat) { throw new DescriptorValidationException(this, "MessageSet format is not supported."); } - accessor = CreateAccessor(propertyName); + accessor = CreateAccessor(); } - private IFieldAccessor CreateAccessor(string propertyName) + private IFieldAccessor CreateAccessor() { // If we're given no property name, that's because we really don't want an accessor. // (At the moment, that means it's a map entry message...) @@ -352,10 +330,10 @@ namespace Google.Protobuf.Reflection { return null; } - var property = containingType.ClrType.GetProperty(propertyName); + var property = ContainingType.ClrType.GetProperty(propertyName); if (property == null) { - throw new DescriptorValidationException(this, $"Property {propertyName} not found in {containingType.ClrType}"); + throw new DescriptorValidationException(this, $"Property {propertyName} not found in {ContainingType.ClrType}"); } return IsMap ? new MapFieldAccessor(property, this) : IsRepeated ? new RepeatedFieldAccessor(property, this) From 3b3c8abb9635eb3ea078a821a99c9ef29d66dff7 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Wed, 30 Mar 2016 11:39:59 -0700 Subject: [PATCH 035/123] Integrate google internal changes. --- Makefile.am | 8 + conformance/ConformanceJava.java | 2 +- conformance/ConformanceJavaLite.java | 125 + conformance/Makefile.am | 20 +- generate_descriptor_proto.sh | 13 +- .../com/google/protobuf/ByteBufferWriter.java | 145 + .../java/com/google/protobuf/ByteOutput.java | 116 + .../java/com/google/protobuf/ByteString.java | 120 +- .../com/google/protobuf/CodedInputStream.java | 42 +- .../google/protobuf/CodedOutputStream.java | 1756 +-- .../java/com/google/protobuf/Descriptors.java | 4 +- .../com/google/protobuf/ExperimentalApi.java | 30 + .../com/google/protobuf/GeneratedMessage.java | 4 +- .../google/protobuf/GeneratedMessageLite.java | 301 +- .../java/com/google/protobuf/Internal.java | 9 +- .../java/com/google/protobuf/LazyField.java | 4 +- .../com/google/protobuf/LazyFieldLite.java | 112 +- .../google/protobuf/LazyStringArrayList.java | 4 +- .../google/protobuf/MessageLiteToString.java | 200 + .../com/google/protobuf/NioByteString.java | 55 +- .../main/java/com/google/protobuf/Parser.java | 1 - .../com/google/protobuf/RopeByteString.java | 26 +- .../com/google/protobuf/SmallSortedMap.java | 2 +- .../java/com/google/protobuf/TextFormat.java | 176 +- .../google/protobuf/TextFormatEscaper.java | 137 + .../protobuf/TextFormatParseInfoTree.java | 225 + .../protobuf/TextFormatParseLocation.java | 104 + .../google/protobuf/UnknownFieldSetLite.java | 110 +- .../google/protobuf/UnsafeByteOperations.java | 25 +- .../main/java/com/google/protobuf/Utf8.java | 1670 ++- .../google/protobuf/AbstractMessageTest.java | 1 - .../java/com/google/protobuf/AnyTest.java | 45 + .../protobuf/BoundedByteStringTest.java | 1 - .../google/protobuf/ByteBufferWriterTest.java | 81 + .../com/google/protobuf/ByteStringTest.java | 14 + .../com/google/protobuf/CheckUtf8Test.java | 1 + .../google/protobuf/CodedInputStreamTest.java | 50 + .../google/protobuf/DeprecatedFieldTest.java | 1 + .../com/google/protobuf/DescriptorsTest.java | 37 +- .../google/protobuf/DynamicMessageTest.java | 2 +- .../java/com/google/protobuf/EnumTest.java | 76 + .../google/protobuf/FieldPresenceTest.java | 98 +- .../google/protobuf/GeneratedMessageTest.java | 15 + .../com/google/protobuf/IsValidUtf8Test.java | 73 +- .../google/protobuf/IsValidUtf8TestUtil.java | 200 +- .../google/protobuf/LazyFieldLiteTest.java | 3 +- .../com/google/protobuf/LazyFieldTest.java | 3 +- .../protobuf/LiteEqualsAndHashTest.java | 17 + .../java/com/google/protobuf/LiteTest.java | 193 +- .../protobuf/LiteralByteStringTest.java | 70 +- .../google/protobuf/MapForProto2LiteTest.java | 2 +- .../com/google/protobuf/MapForProto2Test.java | 1 - .../java/com/google/protobuf/MapTest.java | 1 - .../java/com/google/protobuf/MessageTest.java | 4 +- .../google/protobuf/NestedBuildersTest.java | 2 +- .../google/protobuf/NioByteStringTest.java | 215 +- .../google/protobuf/ParseExceptionsTest.java | 210 +- .../java/com/google/protobuf/ParserTest.java | 4 +- .../java/com/google/protobuf/ServiceTest.java | 14 +- .../java/com/google/protobuf/TestUtil.java | 363 +- .../protobuf/TextFormatParseInfoTreeTest.java | 182 + .../protobuf/TextFormatParseLocationTest.java | 86 + .../com/google/protobuf/TextFormatTest.java | 107 +- .../protobuf/UnknownFieldSetLiteTest.java | 40 - .../com/google/protobuf/WireFormatTest.java | 22 +- .../protobuf/lite_equals_and_hash.proto | 12 + java/pom.xml | 2 +- .../google/protobuf/util/FieldMaskTree.java | 75 +- .../com/google/protobuf/util/JsonFormat.java | 26 +- .../protobuf/util/FieldMaskTreeTest.java | 124 +- .../google/protobuf/util/JsonFormatTest.java | 240 +- .../com/google/protobuf/util/json_test.proto | 31 + js/binary/constants.js | 46 +- js/binary/decoder.js | 12 +- js/binary/decoder_test.js | 120 +- js/binary/encoder.js | 430 + js/binary/proto_test.js | 315 +- js/binary/reader.js | 8 +- js/binary/reader_test.js | 74 +- js/binary/utils.js | 64 +- js/binary/utils_test.js | 27 +- js/binary/writer.js | 1205 +- js/debug.js | 2 +- js/debug_test.js | 1 + js/message.js | 284 +- js/message_test.js | 50 +- js/proto3_test.js | 89 +- js/test.proto | 12 + php/ext/google/protobuf/config.m4 | 10 + php/ext/google/protobuf/def.c | 381 + php/ext/google/protobuf/message.c | 273 + php/ext/google/protobuf/protobuf.c | 89 + php/ext/google/protobuf/protobuf.h | 281 + php/ext/google/protobuf/storage.c | 539 + php/ext/google/protobuf/test.php | 15 + php/ext/google/protobuf/upb.c | 11990 ++++++++++++++++ php/ext/google/protobuf/upb.h | 8217 +++++++++++ .../internal/descriptor_database_test.py | 3 +- .../protobuf/internal/descriptor_pool_test.py | 13 +- .../protobuf/internal/descriptor_test.py | 5 +- .../protobuf/internal/generator_test.py | 3 +- .../protobuf/internal/json_format_test.py | 5 +- .../protobuf/internal/message_factory_test.py | 3 +- .../google/protobuf/internal/message_test.py | 53 +- .../protobuf/internal/proto_builder_test.py | 5 +- .../protobuf/internal/reflection_test.py | 3 +- .../internal/service_reflection_test.py | 4 +- .../protobuf/internal/symbol_database_test.py | 3 +- python/google/protobuf/internal/test_util.py | 2 + .../protobuf/internal/text_encoding_test.py | 3 +- .../protobuf/internal/text_format_test.py | 37 +- .../protobuf/internal/unknown_fields_test.py | 2 +- .../internal/well_known_types_test.py | 2 +- .../protobuf/internal/wire_format_test.py | 3 +- python/google/protobuf/json_format.py | 6 +- python/google/protobuf/pyext/descriptor.cc | 10 +- .../protobuf/pyext/descriptor_database.cc | 3 + python/google/protobuf/pyext/extension_dict.h | 2 +- python/google/protobuf/pyext/map_container.h | 2 +- python/google/protobuf/pyext/message.cc | 34 +- python/google/protobuf/pyext/message.h | 4 +- .../pyext/repeated_composite_container.h | 2 +- .../pyext/repeated_scalar_container.h | 2 +- python/google/protobuf/text_format.py | 133 +- src/google/protobuf/any.cc | 46 +- src/google/protobuf/any.h | 16 + src/google/protobuf/any.pb.cc | 12 +- src/google/protobuf/any.pb.h | 2 + src/google/protobuf/any.proto | 37 +- src/google/protobuf/arena.cc | 1 + src/google/protobuf/arena.h | 12 +- src/google/protobuf/arena_nc_test.py | 2 +- src/google/protobuf/arenastring.h | 3 +- .../compiler/command_line_interface.cc | 2 +- .../command_line_interface_unittest.cc | 6 +- src/google/protobuf/compiler/cpp/cpp_enum.cc | 6 +- src/google/protobuf/compiler/cpp/cpp_enum.h | 6 +- src/google/protobuf/compiler/cpp/cpp_file.cc | 69 +- src/google/protobuf/compiler/cpp/cpp_file.h | 14 +- .../protobuf/compiler/cpp/cpp_generator.cc | 38 +- .../protobuf/compiler/cpp/cpp_message.cc | 25 +- .../protobuf/compiler/cpp/cpp_message.h | 10 +- .../protobuf/compiler/cpp/cpp_options.h | 7 +- .../protobuf/compiler/cpp/cpp_unittest.cc | 3 +- .../protobuf/compiler/cpp/metadata_test.cc | 183 + .../protobuf/compiler/java/java_context.cc | 9 +- .../protobuf/compiler/java/java_context.h | 16 + .../protobuf/compiler/java/java_enum.cc | 17 +- .../protobuf/compiler/java/java_enum_field.cc | 29 +- .../compiler/java/java_enum_field_lite.cc | 19 +- .../protobuf/compiler/java/java_enum_lite.cc | 10 +- .../protobuf/compiler/java/java_extension.cc | 87 +- .../compiler/java/java_extension_lite.cc | 118 + .../compiler/java/java_extension_lite.h | 76 + .../protobuf/compiler/java/java_field.cc | 12 +- .../protobuf/compiler/java/java_file.cc | 35 +- src/google/protobuf/compiler/java/java_file.h | 3 +- .../protobuf/compiler/java/java_generator.cc | 16 +- .../compiler/java/java_generator_factory.cc | 14 +- .../protobuf/compiler/java/java_helpers.h | 39 +- .../java/java_lazy_message_field_lite.cc | 5 +- .../protobuf/compiler/java/java_map_field.cc | 28 +- .../compiler/java/java_map_field_lite.cc | 9 +- .../protobuf/compiler/java/java_message.cc | 181 +- .../protobuf/compiler/java/java_message.h | 10 +- .../compiler/java/java_message_builder.cc | 11 +- .../java/java_message_builder_lite.cc | 19 +- .../compiler/java/java_message_field.cc | 3 +- .../compiler/java/java_message_field_lite.cc | 3 - .../compiler/java/java_message_lite.cc | 176 +- .../compiler/java/java_message_lite.h | 3 +- .../compiler/java/java_name_resolver.cc | 7 + .../compiler/java/java_name_resolver.h | 1 + .../compiler/java/java_primitive_field.cc | 12 +- .../java/java_primitive_field_lite.cc | 5 +- .../java/java_shared_code_generator.cc | 7 +- .../java/java_shared_code_generator.h | 5 + .../compiler/java/java_string_field.cc | 30 +- .../compiler/java/java_string_field_lite.cc | 19 +- .../compiler/javanano/javanano_generator.cc | 7 +- .../compiler/javanano/javanano_helpers.cc | 8 +- .../protobuf/compiler/js/js_generator.cc | 779 +- .../protobuf/compiler/js/js_generator.h | 18 +- .../protobuf/compiler/mock_code_generator.cc | 12 +- .../protobuf/compiler/mock_code_generator.h | 5 + src/google/protobuf/compiler/plugin.cc | 117 +- src/google/protobuf/compiler/plugin.h | 18 + .../compiler/python/python_generator.cc | 4 +- src/google/protobuf/compiler/subprocess.cc | 2 +- src/google/protobuf/descriptor.h | 26 + src/google/protobuf/descriptor.pb.cc | 178 +- src/google/protobuf/descriptor.pb.h | 40 +- src/google/protobuf/descriptor.proto | 6 +- src/google/protobuf/descriptor_unittest.cc | 1 + src/google/protobuf/duration.pb.cc | 7 +- src/google/protobuf/duration.proto | 2 + src/google/protobuf/dynamic_message.cc | 20 +- src/google/protobuf/empty.pb.cc | 7 +- src/google/protobuf/empty.proto | 1 + src/google/protobuf/field_mask.proto | 26 + src/google/protobuf/io/coded_stream.cc | 10 +- .../protobuf/io/coded_stream_unittest.cc | 1 + src/google/protobuf/io/gzip_stream.h | 3 +- src/google/protobuf/io/printer.cc | 76 +- src/google/protobuf/io/printer.h | 164 + src/google/protobuf/io/printer_unittest.cc | 237 + src/google/protobuf/io/tokenizer.cc | 8 +- src/google/protobuf/io/tokenizer.h | 20 +- src/google/protobuf/io/tokenizer_unittest.cc | 18 +- .../protobuf/io/zero_copy_stream_impl_lite.cc | 20 +- .../protobuf/io/zero_copy_stream_impl_lite.h | 1 + src/google/protobuf/map.h | 1084 +- src/google/protobuf/map_test.cc | 370 +- src/google/protobuf/message.cc | 4 +- src/google/protobuf/message_lite.cc | 16 +- src/google/protobuf/message_unittest.cc | 1 + src/google/protobuf/metadata.h | 2 +- src/google/protobuf/repeated_field.cc | 4 +- src/google/protobuf/repeated_field.h | 112 +- .../protobuf/repeated_field_unittest.cc | 38 + src/google/protobuf/struct.pb.cc | 8 +- src/google/protobuf/struct.proto | 3 +- src/google/protobuf/stubs/hash.h | 12 + src/google/protobuf/stubs/logging.h | 2 +- src/google/protobuf/stubs/mathutil.h | 2 +- src/google/protobuf/stubs/stringpiece.h | 38 + src/google/protobuf/stubs/strutil.h | 8 + src/google/protobuf/text_format.cc | 15 +- src/google/protobuf/text_format_unittest.cc | 1 + src/google/protobuf/timestamp.pb.cc | 7 +- src/google/protobuf/timestamp.proto | 1 + src/google/protobuf/unittest.proto | 1 + src/google/protobuf/unittest_lite.proto | 3 + src/google/protobuf/util/field_comparator.h | 4 +- .../protobuf/util/field_comparator_test.cc | 1 - src/google/protobuf/util/field_mask_util.cc | 76 + src/google/protobuf/util/field_mask_util.h | 40 +- .../protobuf/util/field_mask_util_test.cc | 112 +- src/google/protobuf/util/internal/constants.h | 20 +- .../protobuf/util/internal/datapiece.cc | 46 +- src/google/protobuf/util/internal/datapiece.h | 41 +- .../internal/default_value_objectwriter.cc | 64 +- .../internal/default_value_objectwriter.h | 50 +- .../util/internal/json_objectwriter.cc | 20 +- .../util/internal/json_objectwriter.h | 15 +- .../util/internal/json_objectwriter_test.cc | 26 +- .../util/internal/json_stream_parser.cc | 62 +- .../util/internal/json_stream_parser_test.cc | 119 +- .../protobuf/util/internal/object_writer.h | 19 +- .../protobuf/util/internal/proto_writer.cc | 212 +- .../protobuf/util/internal/proto_writer.h | 21 +- .../util/internal/protostream_objectsource.cc | 55 +- .../util/internal/protostream_objectsource.h | 31 + .../internal/protostream_objectsource_test.cc | 150 +- .../util/internal/protostream_objectwriter.cc | 54 +- .../util/internal/protostream_objectwriter.h | 25 +- .../internal/protostream_objectwriter_test.cc | 196 +- .../util/internal/testdata/books.proto | 7 + .../util/internal/type_info_test_helper.cc | 6 +- .../util/internal/type_info_test_helper.h | 8 +- src/google/protobuf/util/internal/utility.cc | 7 +- src/google/protobuf/util/json_util.cc | 40 +- src/google/protobuf/util/json_util_test.cc | 68 +- .../protobuf/util/message_differencer.cc | 5 +- src/google/protobuf/wire_format_lite.cc | 8 +- src/google/protobuf/wire_format_lite_inl.h | 6 +- src/google/protobuf/wire_format_unittest.cc | 1 + src/google/protobuf/wrappers.pb.cc | 9 +- src/google/protobuf/wrappers.proto | 1 + 269 files changed, 34752 insertions(+), 5152 deletions(-) create mode 100644 conformance/ConformanceJavaLite.java create mode 100644 java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java create mode 100644 java/core/src/main/java/com/google/protobuf/ByteOutput.java create mode 100644 java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java create mode 100644 java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java create mode 100644 java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java create mode 100644 java/core/src/test/java/com/google/protobuf/EnumTest.java create mode 100644 java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java create mode 100644 java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java create mode 100644 js/binary/encoder.js create mode 100644 php/ext/google/protobuf/config.m4 create mode 100644 php/ext/google/protobuf/def.c create mode 100644 php/ext/google/protobuf/message.c create mode 100644 php/ext/google/protobuf/protobuf.c create mode 100644 php/ext/google/protobuf/protobuf.h create mode 100644 php/ext/google/protobuf/storage.c create mode 100644 php/ext/google/protobuf/test.php create mode 100644 php/ext/google/protobuf/upb.c create mode 100644 php/ext/google/protobuf/upb.h diff --git a/Makefile.am b/Makefile.am index fbd27fc5..a95fda73 100644 --- a/Makefile.am +++ b/Makefile.am @@ -193,6 +193,8 @@ java_EXTRA_DIST= java/core/src/main/java/com/google/protobuf/BlockingRpcChannel.java \ java/core/src/main/java/com/google/protobuf/BlockingService.java \ java/core/src/main/java/com/google/protobuf/BooleanArrayList.java \ + java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java \ + java/core/src/main/java/com/google/protobuf/ByteOutput.java \ java/core/src/main/java/com/google/protobuf/ByteString.java \ java/core/src/main/java/com/google/protobuf/CodedInputStream.java \ java/core/src/main/java/com/google/protobuf/CodedOutputStream.java \ @@ -243,6 +245,8 @@ java_EXTRA_DIST= java/core/src/main/java/com/google/protobuf/SmallSortedMap.java \ java/core/src/main/java/com/google/protobuf/TextFormat.java \ java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java \ + java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java \ + java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java \ java/core/src/main/java/com/google/protobuf/UninitializedMessageException.java \ java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java \ java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java \ @@ -254,6 +258,7 @@ java_EXTRA_DIST= java/core/src/test/java/com/google/protobuf/AnyTest.java \ java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java \ java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java \ + java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java \ java/core/src/test/java/com/google/protobuf/ByteStringTest.java \ java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java \ java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java \ @@ -262,6 +267,7 @@ java_EXTRA_DIST= java/core/src/test/java/com/google/protobuf/DescriptorsTest.java \ java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java \ java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java \ + java/core/src/test/java/com/google/protobuf/EnumTest.java \ java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java \ java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java \ java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java \ @@ -294,6 +300,8 @@ java_EXTRA_DIST= java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java \ java/core/src/test/java/com/google/protobuf/TestBadIdentifiers.java \ java/core/src/test/java/com/google/protobuf/TestUtil.java \ + java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java \ + java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java \ java/core/src/test/java/com/google/protobuf/TextFormatTest.java \ java/core/src/test/java/com/google/protobuf/UnknownEnumValueTest.java \ java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java \ diff --git a/conformance/ConformanceJava.java b/conformance/ConformanceJava.java index a983ba3c..43787ffc 100644 --- a/conformance/ConformanceJava.java +++ b/conformance/ConformanceJava.java @@ -129,7 +129,7 @@ class ConformanceJava { typeRegistry = TypeRegistry.newBuilder().add( Conformance.TestAllTypes.getDescriptor()).build(); while (doTestIo()) { - // Empty. + this.testCount++; } System.err.println("ConformanceJava: received EOF from test runner after " + diff --git a/conformance/ConformanceJavaLite.java b/conformance/ConformanceJavaLite.java new file mode 100644 index 00000000..121dc7d1 --- /dev/null +++ b/conformance/ConformanceJavaLite.java @@ -0,0 +1,125 @@ + +import com.google.protobuf.conformance.Conformance; +import com.google.protobuf.InvalidProtocolBufferException; + +class ConformanceJavaLite { + private int testCount = 0; + + private boolean readFromStdin(byte[] buf, int len) throws Exception { + int ofs = 0; + while (len > 0) { + int read = System.in.read(buf, ofs, len); + if (read == -1) { + return false; // EOF + } + ofs += read; + len -= read; + } + + return true; + } + + private void writeToStdout(byte[] buf) throws Exception { + System.out.write(buf); + } + + // Returns -1 on EOF (the actual values will always be positive). + private int readLittleEndianIntFromStdin() throws Exception { + byte[] buf = new byte[4]; + if (!readFromStdin(buf, 4)) { + return -1; + } + return (buf[0] & 0xff) + | ((buf[1] & 0xff) << 8) + | ((buf[2] & 0xff) << 16) + | ((buf[3] & 0xff) << 24); + } + + private void writeLittleEndianIntToStdout(int val) throws Exception { + byte[] buf = new byte[4]; + buf[0] = (byte)val; + buf[1] = (byte)(val >> 8); + buf[2] = (byte)(val >> 16); + buf[3] = (byte)(val >> 24); + writeToStdout(buf); + } + + private Conformance.ConformanceResponse doTest(Conformance.ConformanceRequest request) { + Conformance.TestAllTypes testMessage; + + switch (request.getPayloadCase()) { + case PROTOBUF_PAYLOAD: { + try { + testMessage = Conformance.TestAllTypes.parseFrom(request.getProtobufPayload()); + } catch (InvalidProtocolBufferException e) { + return Conformance.ConformanceResponse.newBuilder().setParseError(e.getMessage()).build(); + } + break; + } + case JSON_PAYLOAD: { + return Conformance.ConformanceResponse.newBuilder().setSkipped( + "Lite runtime does not suport Json Formant.").build(); + } + case PAYLOAD_NOT_SET: { + throw new RuntimeException("Request didn't have payload."); + } + + default: { + throw new RuntimeException("Unexpected payload case."); + } + } + + switch (request.getRequestedOutputFormat()) { + case UNSPECIFIED: + throw new RuntimeException("Unspecified output format."); + + case PROTOBUF: + return Conformance.ConformanceResponse.newBuilder().setProtobufPayload(testMessage.toByteString()).build(); + + case JSON: + return Conformance.ConformanceResponse.newBuilder().setSkipped( + "Lite runtime does not suport Json Formant.").build(); + + default: { + throw new RuntimeException("Unexpected request output."); + } + } + } + + private boolean doTestIo() throws Exception { + int bytes = readLittleEndianIntFromStdin(); + + if (bytes == -1) { + return false; // EOF + } + + byte[] serializedInput = new byte[bytes]; + + if (!readFromStdin(serializedInput, bytes)) { + throw new RuntimeException("Unexpected EOF from test program."); + } + + Conformance.ConformanceRequest request = + Conformance.ConformanceRequest.parseFrom(serializedInput); + Conformance.ConformanceResponse response = doTest(request); + byte[] serializedOutput = response.toByteArray(); + + writeLittleEndianIntToStdout(serializedOutput.length); + writeToStdout(serializedOutput); + + return true; + } + + public void run() throws Exception { + while (doTestIo()) { + this.testCount++; + } + + System.err.println("ConformanceJavaLite: received EOF from test runner after " + + this.testCount + " tests"); + } + + public static void main(String[] args) throws Exception { + new ConformanceJavaLite().run(); + } +} diff --git a/conformance/Makefile.am b/conformance/Makefile.am index 2a43113b..abb1c00d 100644 --- a/conformance/Makefile.am +++ b/conformance/Makefile.am @@ -19,6 +19,7 @@ protoc_outputs = \ other_language_protoc_outputs = \ conformance.rb \ com/google/protobuf/conformance/Conformance.java \ + lite/com/google/protobuf/conformance/Conformance.java \ conformance_pb2.py \ Conformance.pbobjc.h \ Conformance.pbobjc.m @@ -30,6 +31,7 @@ bin_PROGRAMS = conformance-test-runner conformance-cpp # automatically. EXTRA_DIST = \ ConformanceJava.java \ + ConformanceJavaLite.java \ README.md \ conformance.proto \ conformance_python.py \ @@ -88,6 +90,7 @@ if USE_EXTERNAL_PROTOC protoc_middleman: $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) $(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --objc_out=. --python_out=. $(conformance_protoc_inputs) $(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. --java_out=. --ruby_out=. --python_out=. $(well_known_type_protoc_inputs) + $(PROTOC) -I$(srcdir) -I$(top_srcdir) --java_out=lite:lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) touch protoc_middleman else @@ -98,6 +101,8 @@ else protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --objc_out=$$oldpwd --python_out=$$oldpwd $(conformance_protoc_inputs) ) oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd --java_out=$$oldpwd --ruby_out=$$oldpwd --python_out=$$oldpwd $(well_known_type_protoc_inputs) ) + @mkdir -p lite + oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --java_out=lite:$$oldpwd/lite $(conformance_protoc_inputs) $(well_known_type_protoc_inputs) ) touch protoc_middleman endif @@ -108,7 +113,7 @@ $(other_language_protoc_outputs): protoc_middleman BUILT_SOURCES = $(protoc_outputs) $(other_language_protoc_outputs) -CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java conformance-csharp $(other_language_protoc_outputs) +CLEANFILES = $(protoc_outputs) protoc_middleman javac_middleman conformance-java javac_middleman_lite conformance-java-lite conformance-csharp $(other_language_protoc_outputs) MAINTAINERCLEANFILES = \ Makefile.in @@ -123,6 +128,16 @@ conformance-java: javac_middleman @jar=`ls ../java/util/target/*jar-with-dependencies.jar` && echo java -classpath .:../java/target/classes:$$jar ConformanceJava '$$@' >> conformance-java @chmod +x conformance-java +javac_middleman_lite: ConformanceJavaLite.java protoc_middleman $(other_language_protoc_outputs) + javac -classpath ../java/lite/target/classes:lite ConformanceJavaLite.java lite/com/google/protobuf/conformance/Conformance.java + @touch javac_middleman_lite + +conformance-java-lite: javac_middleman_lite + @echo "Writing shortcut script conformance-java-lite..." + @echo '#! /bin/sh' > conformance-java-lite + @echo java -classpath .:../java/lite/target/classes:lite ConformanceJavaLite '$$@' >> conformance-java-lite + @chmod +x conformance-java-lite + # Currently the conformance code is alongside the rest of the C# # source, as it's easier to maintain there. We assume we've already # built that, so we just need a script to run it. @@ -139,6 +154,9 @@ test_cpp: protoc_middleman conformance-test-runner conformance-cpp test_java: protoc_middleman conformance-test-runner conformance-java ./conformance-test-runner --failure_list failure_list_java.txt ./conformance-java +test_java_lite: protoc_middleman conformance-test-runner conformance-java-lite + ./conformance-test-runner ./conformance-java-lite + test_csharp: protoc_middleman conformance-test-runner conformance-csharp ./conformance-test-runner --failure_list failure_list_csharp.txt ./conformance-csharp diff --git a/generate_descriptor_proto.sh b/generate_descriptor_proto.sh index 81b8a0d6..4fe64dda 100755 --- a/generate_descriptor_proto.sh +++ b/generate_descriptor_proto.sh @@ -10,8 +10,6 @@ # to make when building protoc. This is particularly useful for passing # -j4 to run 4 jobs simultaneously. -set -e - if test ! -e src/google/protobuf/stubs/common.h; then cat >&2 << __EOF__ Could not find source code. Make sure you are running this script from the @@ -52,9 +50,14 @@ do echo "Round $PROCESS_ROUND" CORE_PROTO_IS_CORRECT=1 - make $@ protoc && - ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \ - ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP google/protobuf/compiler/plugin.proto + make $@ protoc + if test $? -ne 0; then + echo "Failed to build protoc." + exit 1 + fi + + ./protoc --cpp_out=dllexport_decl=LIBPROTOBUF_EXPORT:$TMP ${RUNTIME_PROTO_FILES[@]} && \ + ./protoc --cpp_out=dllexport_decl=LIBPROTOC_EXPORT:$TMP google/protobuf/compiler/plugin.proto for PROTO_FILE in ${RUNTIME_PROTO_FILES[@]}; do BASE_NAME=${PROTO_FILE%.*} diff --git a/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java new file mode 100644 index 00000000..0cc38175 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ByteBufferWriter.java @@ -0,0 +1,145 @@ +// 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. + +package com.google.protobuf; + +import static java.lang.Math.max; +import static java.lang.Math.min; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.lang.ref.SoftReference; +import java.nio.ByteBuffer; + +/** + * Utility class to provide efficient writing of {@link ByteBuffer}s to {@link OutputStream}s. + */ +final class ByteBufferWriter { + private ByteBufferWriter() {} + + /** + * Minimum size for a cached buffer. This prevents us from allocating buffers that are too + * small to be easily reused. + */ + // TODO(nathanmittler): tune this property or allow configuration? + private static final int MIN_CACHED_BUFFER_SIZE = 1024; + + /** + * Maximum size for a cached buffer. If a larger buffer is required, it will be allocated + * but not cached. + */ + // TODO(nathanmittler): tune this property or allow configuration? + private static final int MAX_CACHED_BUFFER_SIZE = 16 * 1024; + + /** + * The fraction of the requested buffer size under which the buffer will be reallocated. + */ + // TODO(nathanmittler): tune this property or allow configuration? + private static final float BUFFER_REALLOCATION_THRESHOLD = 0.5f; + + /** + * Keeping a soft reference to a thread-local buffer. This buffer is used for writing a + * {@link ByteBuffer} to an {@link OutputStream} when no zero-copy alternative was available. + * Using a "soft" reference since VMs may keep this reference around longer than "weak" + * (e.g. HotSpot will maintain soft references until memory pressure warrants collection). + */ + private static final ThreadLocal> BUFFER = + new ThreadLocal>(); + + /** + * For testing purposes only. Clears the cached buffer to force a new allocation on the next + * invocation. + */ + static void clearCachedBuffer() { + BUFFER.set(null); + } + + /** + * Writes the remaining content of the buffer to the given stream. The buffer {@code position} + * will remain unchanged by this method. + */ + static void write(ByteBuffer buffer, OutputStream output) throws IOException { + final int initialPos = buffer.position(); + try { + if (buffer.hasArray()) { + // Optimized write for array-backed buffers. + // Note that we're taking the risk that a malicious OutputStream could modify the array. + output.write(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()); + } else if (output instanceof FileOutputStream) { + // Use a channel to write out the ByteBuffer. This will automatically empty the buffer. + ((FileOutputStream) output).getChannel().write(buffer); + } else { + // Read all of the data from the buffer to an array. + // TODO(nathanmittler): Consider performance improvements for other "known" stream types. + final byte[] array = getOrCreateBuffer(buffer.remaining()); + while (buffer.hasRemaining()) { + int length = min(buffer.remaining(), array.length); + buffer.get(array, 0, length); + output.write(array, 0, length); + } + } + } finally { + // Restore the initial position. + buffer.position(initialPos); + } + } + + private static byte[] getOrCreateBuffer(int requestedSize) { + requestedSize = max(requestedSize, MIN_CACHED_BUFFER_SIZE); + + byte[] buffer = getBuffer(); + // Only allocate if we need to. + if (buffer == null || needToReallocate(requestedSize, buffer.length)) { + buffer = new byte[requestedSize]; + + // Only cache the buffer if it's not too big. + if (requestedSize <= MAX_CACHED_BUFFER_SIZE) { + setBuffer(buffer); + } + } + return buffer; + } + + private static boolean needToReallocate(int requestedSize, int bufferLength) { + // First check against just the requested length to avoid the multiply. + return bufferLength < requestedSize + && bufferLength < requestedSize * BUFFER_REALLOCATION_THRESHOLD; + } + + private static byte[] getBuffer() { + SoftReference sr = BUFFER.get(); + return sr == null ? null : sr.get(); + } + + private static void setBuffer(byte[] value) { + BUFFER.set(new SoftReference(value)); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/ByteOutput.java b/java/core/src/main/java/com/google/protobuf/ByteOutput.java new file mode 100644 index 00000000..8b7b04c8 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/ByteOutput.java @@ -0,0 +1,116 @@ +// 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. + +package com.google.protobuf; + +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * An output target for raw bytes. This interface provides semantics that support two types of + * writing: + * + *

Traditional write operations: + * (as defined by {@link java.io.OutputStream}) where the target method is responsible for either + * copying the data or completing the write before returning from the method call. + * + *

Lazy write operations: where the caller guarantees that it will never modify the + * provided buffer and it can therefore be considered immutable. The target method is free to + * maintain a reference to the buffer beyond the scope of the method call (e.g. until the write + * operation completes). + */ +@ExperimentalApi +public abstract class ByteOutput { + /** + * Writes a single byte. + * + * @param value the byte to be written + * @throws IOException thrown if an error occurred while writing + */ + public abstract void write(byte value) throws IOException; + + /** + * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will + * not be processed prior to the return of this method call, since {@code value} may be + * reused/altered by the caller. + * + *

NOTE: This method MUST NOT modify the {@code value}. Doing so is a + * programming error and will lead to data corruption which will be difficult to debug. + * + * @param value the bytes to be written + * @param offset the offset of the start of the writable range + * @param length the number of bytes to write starting from {@code offset} + * @throws IOException thrown if an error occurred while writing + */ + public abstract void write(byte[] value, int offset, int length) throws IOException; + + /** + * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value + * beyond the scope of this method call (e.g. write later) since it is considered immutable and is + * guaranteed not to change by the caller. + * + *

NOTE: This method MUST NOT modify the {@code value}. Doing so is a + * programming error and will lead to data corruption which will be difficult to debug. + * + * @param value the bytes to be written + * @param offset the offset of the start of the writable range + * @param length the number of bytes to write starting from {@code offset} + * @throws IOException thrown if an error occurred while writing + */ + public abstract void writeLazy(byte[] value, int offset, int length) throws IOException; + + /** + * Writes a sequence of bytes. The {@link ByteOutput} must copy {@code value} if it will + * not be processed prior to the return of this method call, since {@code value} may be + * reused/altered by the caller. + * + *

NOTE: This method MUST NOT modify the {@code value}. Doing so is a + * programming error and will lead to data corruption which will be difficult to debug. + * + * @param value the bytes to be written. Upon returning from this call, the {@code position} of + * this buffer will be set to the {@code limit} + * @throws IOException thrown if an error occurred while writing + */ + public abstract void write(ByteBuffer value) throws IOException; + + /** + * Writes a sequence of bytes. The {@link ByteOutput} is free to retain a reference to the value + * beyond the scope of this method call (e.g. write later) since it is considered immutable and is + * guaranteed not to change by the caller. + * + *

NOTE: This method MUST NOT modify the {@code value}. Doing so is a + * programming error and will lead to data corruption which will be difficult to debug. + * + * @param value the bytes to be written. Upon returning from this call, the {@code position} of + * this buffer will be set to the {@code limit} + * @throws IOException thrown if an error occurred while writing + */ + public abstract void writeLazy(ByteBuffer value) throws IOException; +} diff --git a/java/core/src/main/java/com/google/protobuf/ByteString.java b/java/core/src/main/java/com/google/protobuf/ByteString.java index 305236f3..62c94508 100644 --- a/java/core/src/main/java/com/google/protobuf/ByteString.java +++ b/java/core/src/main/java/com/google/protobuf/ByteString.java @@ -1,4 +1,32 @@ -// Copyright 2007 Google Inc. All rights reserved. +// 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. package com.google.protobuf; @@ -15,6 +43,7 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -58,6 +87,54 @@ public abstract class ByteString implements Iterable, Serializable { * Empty {@code ByteString}. */ public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY); + + /** + * An interface to efficiently copy {@code byte[]}. + * + *

One of the noticable costs of copying a byte[] into a new array using + * {@code System.arraycopy} is nullification of a new buffer before the copy. It has been shown + * the Hotspot VM is capable to intrisicfy {@code Arrays.copyOfRange} operation to avoid this + * expensive nullification and provide substantial performance gain. Unfortunately this does not + * hold on Android runtimes and could make the copy slightly slower due to additional code in + * the {@code Arrays.copyOfRange}. Thus we provide two different implementation for array copier + * for Hotspot and Android runtimes. + */ + private interface ByteArrayCopier { + /** + * Copies the specified range of the specified array into a new array + */ + byte[] copyFrom(byte[] bytes, int offset, int size); + } + + /** Implementation of {@code ByteArrayCopier} which uses {@link System#arraycopy}. */ + private static final class SystemByteArrayCopier implements ByteArrayCopier { + @Override + public byte[] copyFrom(byte[] bytes, int offset, int size) { + byte[] copy = new byte[size]; + System.arraycopy(bytes, offset, copy, 0, size); + return copy; + } + } + + /** Implementation of {@code ByteArrayCopier} which uses {@link Arrays#copyOfRange}. */ + private static final class ArraysByteArrayCopier implements ByteArrayCopier { + @Override + public byte[] copyFrom(byte[] bytes, int offset, int size) { + return Arrays.copyOfRange(bytes, offset, offset + size); + } + } + + private static final ByteArrayCopier byteArrayCopier; + static { + boolean isAndroid = true; + try { + Class.forName("android.content.Context"); + } catch (ClassNotFoundException e) { + isAndroid = false; + } + + byteArrayCopier = isAndroid ? new SystemByteArrayCopier() : new ArraysByteArrayCopier(); + } /** * Cached hash value. Intentionally accessed via a data race, which @@ -77,7 +154,7 @@ public abstract class ByteString implements Iterable, Serializable { * * @param index index of byte * @return the value - * @throws ArrayIndexOutOfBoundsException {@code index < 0 or index >= size} + * @throws IndexOutOfBoundsException {@code index < 0 or index >= size} */ public abstract byte byteAt(int index); @@ -109,7 +186,7 @@ public abstract class ByteString implements Iterable, Serializable { public byte nextByte() { try { return byteAt(position++); - } catch (ArrayIndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException e) { throw new NoSuchElementException(e.getMessage()); } } @@ -220,9 +297,7 @@ public abstract class ByteString implements Iterable, Serializable { * @return new {@code ByteString} */ public static ByteString copyFrom(byte[] bytes, int offset, int size) { - byte[] copy = new byte[size]; - System.arraycopy(bytes, offset, copy, 0, size); - return new LiteralByteString(copy); + return new LiteralByteString(byteArrayCopier.copyFrom(bytes, offset, size)); } /** @@ -559,12 +634,7 @@ public abstract class ByteString implements Iterable, Serializable { } /** - * Writes the complete contents of this byte string to - * the specified output stream argument. - * - *

It is assumed that the {@link OutputStream} will not modify the contents passed it - * it. It may be possible for a malicious {@link OutputStream} to corrupt - * the data underlying the {@link ByteString}. + * Writes a copy of the contents of this byte string to the specified output stream argument. * * @param out the output stream to which to write the data. * @throws IOException if an I/O error occurs. @@ -578,8 +648,7 @@ public abstract class ByteString implements Iterable, Serializable { * @param sourceOffset offset within these bytes * @param numberToWrite number of bytes to write * @throws IOException if an I/O error occurs. - * @throws IndexOutOfBoundsException if an offset or size is negative or too - * large + * @throws IndexOutOfBoundsException if an offset or size is negative or too large */ final void writeTo(OutputStream out, int sourceOffset, int numberToWrite) throws IOException { @@ -596,6 +665,20 @@ public abstract class ByteString implements Iterable, Serializable { abstract void writeToInternal(OutputStream out, int sourceOffset, int numberToWrite) throws IOException; + /** + * Writes this {@link ByteString} to the provided {@link ByteOutput}. Calling + * this method may result in multiple operations on the target {@link ByteOutput}. + * + *

This method may expose internal backing buffers of the {@link ByteString} to the {@link + * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious + * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution! + * + * @param byteOutput the output target to receive the bytes + * @throws IOException if an I/O error occurs + * @see UnsafeByteOperations#unsafeWriteTo(ByteString, ByteOutput) + */ + abstract void writeTo(ByteOutput byteOutput) throws IOException; + /** * Constructs a read-only {@code java.nio.ByteBuffer} whose content * is equal to the contents of this byte string. @@ -1102,7 +1185,7 @@ public abstract class ByteString implements Iterable, Serializable { * * @param index the index position to be tested * @param size the length of the array - * @throws ArrayIndexOutOfBoundsException if the index does not fall within the array. + * @throws IndexOutOfBoundsException if the index does not fall within the array. */ static void checkIndex(int index, int size) { if ((index | (size - (index + 1))) < 0) { @@ -1120,7 +1203,7 @@ public abstract class ByteString implements Iterable, Serializable { * @param endIndex the end index of the range (exclusive) * @param size the size of the array. * @return the length of the range. - * @throws ArrayIndexOutOfBoundsException some or all of the range falls outside of the array. + * @throws IndexOutOfBoundsException some or all of the range falls outside of the array. */ static int checkRange(int startIndex, int endIndex, int size) { final int length = endIndex - startIndex; @@ -1235,6 +1318,11 @@ public abstract class ByteString implements Iterable, Serializable { outputStream.write(bytes, getOffsetIntoBytes() + sourceOffset, numberToWrite); } + @Override + final void writeTo(ByteOutput output) throws IOException { + output.writeLazy(bytes, getOffsetIntoBytes(), size()); + } + @Override protected final String toStringInternal(Charset charset) { return new String(bytes, getOffsetIntoBytes(), size(), charset); diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java index b3118ee0..e8860651 100644 --- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java +++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java @@ -55,7 +55,14 @@ public final class CodedInputStream { * Create a new CodedInputStream wrapping the given InputStream. */ public static CodedInputStream newInstance(final InputStream input) { - return new CodedInputStream(input); + return new CodedInputStream(input, BUFFER_SIZE); + } + + /** + * Create a new CodedInputStream wrapping the given InputStream. + */ + static CodedInputStream newInstance(final InputStream input, int bufferSize) { + return new CodedInputStream(input, bufferSize); } /** @@ -70,14 +77,14 @@ public final class CodedInputStream { */ public static CodedInputStream newInstance(final byte[] buf, final int off, final int len) { - return newInstance(buf, off, len, false); + return newInstance(buf, off, len, false /* bufferIsImmutable */); } - + /** * Create a new CodedInputStream wrapping the given byte array slice. */ - public static CodedInputStream newInstance(final byte[] buf, final int off, - final int len, boolean bufferIsImmutable) { + static CodedInputStream newInstance( + final byte[] buf, final int off, final int len, final boolean bufferIsImmutable) { CodedInputStream result = new CodedInputStream(buf, off, len, bufferIsImmutable); try { // Some uses of CodedInputStream can be more efficient if they know @@ -361,6 +368,11 @@ public final class CodedInputStream { return result; } else if (size == 0) { return ""; + } else if (size <= bufferSize) { + refillBuffer(size); + String result = new String(buffer, bufferPos, size, Internal.UTF_8); + bufferPos += size; + return result; } else { // Slow path: Build a byte array first then copy it. return new String(readRawBytesSlowPath(size), Internal.UTF_8); @@ -375,14 +387,21 @@ public final class CodedInputStream { public String readStringRequireUtf8() throws IOException { final int size = readRawVarint32(); final byte[] bytes; - int pos = bufferPos; - if (size <= (bufferSize - pos) && size > 0) { + final int oldPos = bufferPos; + final int pos; + if (size <= (bufferSize - oldPos) && size > 0) { // Fast path: We already have the bytes in a contiguous buffer, so // just copy directly from it. bytes = buffer; - bufferPos = pos + size; + bufferPos = oldPos + size; + pos = oldPos; } else if (size == 0) { return ""; + } else if (size <= bufferSize) { + refillBuffer(size); + bytes = buffer; + pos = 0; + bufferPos = pos + size; } else { // Slow path: Build a byte array first then copy it. bytes = readRawBytesSlowPath(size); @@ -869,7 +888,8 @@ public final class CodedInputStream { private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB private static final int BUFFER_SIZE = 4096; - private CodedInputStream(final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) { + private CodedInputStream( + final byte[] buffer, final int off, final int len, boolean bufferIsImmutable) { this.buffer = buffer; bufferSize = off + len; bufferPos = off; @@ -878,8 +898,8 @@ public final class CodedInputStream { this.bufferIsImmutable = bufferIsImmutable; } - private CodedInputStream(final InputStream input) { - buffer = new byte[BUFFER_SIZE]; + private CodedInputStream(final InputStream input, int bufferSize) { + buffer = new byte[bufferSize]; bufferSize = 0; bufferPos = 0; totalBytesRetired = 0; diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java index d8ebad21..b92394b8 100644 --- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java +++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java @@ -49,13 +49,17 @@ import java.util.logging.Logger; * you are writing some other format of your own design, use the latter. * *

This class is totally unsynchronized. - * - * @author kneton@google.com Kenton Varda */ public final class CodedOutputStream { - private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName()); + private static final int LITTLE_ENDIAN_64_SIZE = 8; + + /** + * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. + */ + @Deprecated public static final int LITTLE_ENDIAN_32_SIZE = 4; + // TODO(dweis): Consider migrating to a ByteBuffer. private final byte[] buffer; private final int limit; @@ -77,12 +81,13 @@ public final class CodedOutputStream { * CodedOutputStream. */ static int computePreferredBufferSize(int dataLength) { - if (dataLength > DEFAULT_BUFFER_SIZE) return DEFAULT_BUFFER_SIZE; + if (dataLength > DEFAULT_BUFFER_SIZE) { + return DEFAULT_BUFFER_SIZE; + } return dataLength; } - private CodedOutputStream(final byte[] buffer, final int offset, - final int length) { + private CodedOutputStream(final byte[] buffer, final int offset, final int length) { output = null; this.buffer = buffer; position = offset; @@ -108,8 +113,7 @@ public final class CodedOutputStream { * Create a new {@code CodedOutputStream} wrapping the given * {@code OutputStream} with a given buffer size. */ - public static CodedOutputStream newInstance(final OutputStream output, - final int bufferSize) { + public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) { return new CodedOutputStream(output, new byte[bufferSize]); } @@ -131,9 +135,8 @@ public final class CodedOutputStream { * array is faster than writing to an {@code OutputStream}. See also * {@link ByteString#newCodedBuilder}. */ - public static CodedOutputStream newInstance(final byte[] flatArray, - final int offset, - final int length) { + public static CodedOutputStream newInstance( + final byte[] flatArray, final int offset, final int length) { return new CodedOutputStream(flatArray, offset, length); } @@ -147,13 +150,13 @@ public final class CodedOutputStream { /** * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer. */ - public static CodedOutputStream newInstance(ByteBuffer byteBuffer, - int bufferSize) { + public static CodedOutputStream newInstance(ByteBuffer byteBuffer, int bufferSize) { return newInstance(new ByteBufferOutputStream(byteBuffer), bufferSize); } private static class ByteBufferOutputStream extends OutputStream { private final ByteBuffer byteBuffer; + public ByteBufferOutputStream(ByteBuffer byteBuffer) { this.byteBuffer = byteBuffer; } @@ -171,106 +174,120 @@ public final class CodedOutputStream { // ----------------------------------------------------------------- - /** Write a {@code double} field, including tag, to the stream. */ - public void writeDouble(final int fieldNumber, final double value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeDoubleNoTag(value); - } - - /** Write a {@code float} field, including tag, to the stream. */ - public void writeFloat(final int fieldNumber, final float value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeFloatNoTag(value); - } - - /** Write a {@code uint64} field, including tag, to the stream. */ - public void writeUInt64(final int fieldNumber, final long value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeUInt64NoTag(value); - } - - /** Write an {@code int64} field, including tag, to the stream. */ - public void writeInt64(final int fieldNumber, final long value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeInt64NoTag(value); + /** Encode and write a tag. */ + public void writeTag(final int fieldNumber, final int wireType) throws IOException { + writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType)); } /** Write an {@code int32} field, including tag, to the stream. */ - public void writeInt32(final int fieldNumber, final int value) - throws IOException { + public void writeInt32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeInt32NoTag(value); } - /** Write a {@code fixed64} field, including tag, to the stream. */ - public void writeFixed64(final int fieldNumber, final long value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeFixed64NoTag(value); + /** Write a {@code uint32} field, including tag, to the stream. */ + public void writeUInt32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeUInt32NoTag(value); + } + + /** Write a {@code sint32} field, including tag, to the stream. */ + public void writeSInt32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeSInt32NoTag(value); } /** Write a {@code fixed32} field, including tag, to the stream. */ - public void writeFixed32(final int fieldNumber, final int value) - throws IOException { + public void writeFixed32(final int fieldNumber, final int value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); writeFixed32NoTag(value); } + /** Write an {@code sfixed32} field, including tag, to the stream. */ + public void writeSFixed32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); + writeSFixed32NoTag(value); + } + + /** Write an {@code int64} field, including tag, to the stream. */ + public void writeInt64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeInt64NoTag(value); + } + + /** Write a {@code uint64} field, including tag, to the stream. */ + public void writeUInt64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeUInt64NoTag(value); + } + + /** Write an {@code sint64} field, including tag, to the stream. */ + public void writeSInt64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeSInt64NoTag(value); + } + + /** Write a {@code fixed64} field, including tag, to the stream. */ + public void writeFixed64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); + writeFixed64NoTag(value); + } + + /** Write an {@code sfixed64} field, including tag, to the stream. */ + public void writeSFixed64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); + writeSFixed64NoTag(value); + } + + /** Write a {@code float} field, including tag, to the stream. */ + public void writeFloat(final int fieldNumber, final float value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); + writeFloatNoTag(value); + } + + /** Write a {@code double} field, including tag, to the stream. */ + public void writeDouble(final int fieldNumber, final double value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); + writeDoubleNoTag(value); + } + /** Write a {@code bool} field, including tag, to the stream. */ - public void writeBool(final int fieldNumber, final boolean value) - throws IOException { + public void writeBool(final int fieldNumber, final boolean value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); writeBoolNoTag(value); } + /** + * Write an enum field, including tag, to the stream. The provided value is the numeric + * value used to represent the enum value on the wire (not the enum ordinal value). + */ + public void writeEnum(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeEnumNoTag(value); + } + /** Write a {@code string} field, including tag, to the stream. */ - public void writeString(final int fieldNumber, final String value) - throws IOException { + public void writeString(final int fieldNumber, final String value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeStringNoTag(value); } - /** Write a {@code group} field, including tag, to the stream. */ - public void writeGroup(final int fieldNumber, final MessageLite value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); - writeGroupNoTag(value); - writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); - } - - - /** Write an embedded message field, including tag, to the stream. */ - public void writeMessage(final int fieldNumber, final MessageLite value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeMessageNoTag(value); - } - - /** Write a {@code bytes} field, including tag, to the stream. */ - public void writeBytes(final int fieldNumber, final ByteString value) - throws IOException { + public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeBytesNoTag(value); } /** Write a {@code bytes} field, including tag, to the stream. */ - public void writeByteArray(final int fieldNumber, final byte[] value) - throws IOException { + public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteArrayNoTag(value); } /** Write a {@code bytes} field, including tag, to the stream. */ - public void writeByteArray(final int fieldNumber, - final byte[] value, - final int offset, - final int length) - throws IOException { + public void writeByteArray( + final int fieldNumber, final byte[] value, final int offset, final int length) + throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteArrayNoTag(value, offset, length); } @@ -285,64 +302,100 @@ public final class CodedOutputStream { * of a ByteBuffer, you can call * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}. */ - public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) - throws IOException { + public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); writeByteBufferNoTag(value); } - /** Write a {@code uint32} field, including tag, to the stream. */ - public void writeUInt32(final int fieldNumber, final int value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeUInt32NoTag(value); + /** Write a single byte. */ + public void writeRawByte(final byte value) throws IOException { + if (position == limit) { + refreshBuffer(); + } + + buffer[position++] = value; + ++totalBytesWritten; + } + + /** Write a single byte, represented by an integer value. */ + public void writeRawByte(final int value) throws IOException { + writeRawByte((byte) value); + } + + /** Write an array of bytes. */ + public void writeRawBytes(final byte[] value) throws IOException { + writeRawBytes(value, 0, value.length); + } + + /** Write part of an array of bytes. */ + public void writeRawBytes(final byte[] value, int offset, int length) throws IOException { + if (limit - position >= length) { + // We have room in the current buffer. + System.arraycopy(value, offset, buffer, position, length); + position += length; + totalBytesWritten += length; + } else { + // Write extends past current buffer. Fill the rest of this buffer and + // flush. + final int bytesWritten = limit - position; + System.arraycopy(value, offset, buffer, position, bytesWritten); + offset += bytesWritten; + length -= bytesWritten; + position = limit; + totalBytesWritten += bytesWritten; + refreshBuffer(); + + // Now deal with the rest. + // Since we have an output stream, this is our buffer + // and buffer offset == 0 + if (length <= limit) { + // Fits in new buffer. + System.arraycopy(value, offset, buffer, 0, length); + position = length; + } else { + // Write is very big. Let's do it all at once. + output.write(value, offset, length); + } + totalBytesWritten += length; + } + } + + /** Write a byte string. */ + public void writeRawBytes(final ByteString value) throws IOException { + writeRawBytes(value, 0, value.size()); } /** - * Write an enum field, including tag, to the stream. Caller is responsible - * for converting the enum value to its numeric value. + * Write a ByteBuffer. This method will write all content of the ByteBuffer + * regardless of the current position and limit (i.e., the number of bytes + * to be written is value.capacity(), not value.remaining()). Furthermore, + * this method doesn't alter the state of the passed-in ByteBuffer. Its + * position, limit, mark, etc. will remain unchanged. If you only want to + * write the remaining bytes of a ByteBuffer, you can call + * {@code writeRawBytes(byteBuffer.slice())}. */ - public void writeEnum(final int fieldNumber, final int value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeEnumNoTag(value); + public void writeRawBytes(final ByteBuffer value) throws IOException { + if (value.hasArray()) { + writeRawBytes(value.array(), value.arrayOffset(), value.capacity()); + } else { + ByteBuffer duplicated = value.duplicate(); + duplicated.clear(); + writeRawBytesInternal(duplicated); + } } - /** Write an {@code sfixed32} field, including tag, to the stream. */ - public void writeSFixed32(final int fieldNumber, final int value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeSFixed32NoTag(value); - } - - /** Write an {@code sfixed64} field, including tag, to the stream. */ - public void writeSFixed64(final int fieldNumber, final long value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeSFixed64NoTag(value); - } - - /** Write an {@code sint32} field, including tag, to the stream. */ - public void writeSInt32(final int fieldNumber, final int value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeSInt32NoTag(value); - } - - /** Write an {@code sint64} field, including tag, to the stream. */ - public void writeSInt64(final int fieldNumber, final long value) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeSInt64NoTag(value); + /** Write an embedded message field, including tag, to the stream. */ + public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value); } /** * Write a MessageSet extension field to the stream. For historical reasons, * the wire format differs from normal fields. */ - public void writeMessageSetExtension(final int fieldNumber, - final MessageLite value) - throws IOException { + public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) + throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); @@ -353,9 +406,8 @@ public final class CodedOutputStream { * Write an unparsed MessageSet extension field to the stream. For * historical reasons, the wire format differs from normal fields. */ - public void writeRawMessageSetExtension(final int fieldNumber, - final ByteString value) - throws IOException { + public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) + throws IOException { writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); @@ -364,26 +416,6 @@ public final class CodedOutputStream { // ----------------------------------------------------------------- - /** Write a {@code double} field to the stream. */ - public void writeDoubleNoTag(final double value) throws IOException { - writeRawLittleEndian64(Double.doubleToRawLongBits(value)); - } - - /** Write a {@code float} field to the stream. */ - public void writeFloatNoTag(final float value) throws IOException { - writeRawLittleEndian32(Float.floatToRawIntBits(value)); - } - - /** Write a {@code uint64} field to the stream. */ - public void writeUInt64NoTag(final long value) throws IOException { - writeRawVarint64(value); - } - - /** Write an {@code int64} field to the stream. */ - public void writeInt64NoTag(final long value) throws IOException { - writeRawVarint64(value); - } - /** Write an {@code int32} field to the stream. */ public void writeInt32NoTag(final int value) throws IOException { if (value >= 0) { @@ -394,9 +426,14 @@ public final class CodedOutputStream { } } - /** Write a {@code fixed64} field to the stream. */ - public void writeFixed64NoTag(final long value) throws IOException { - writeRawLittleEndian64(value); + /** Write a {@code uint32} field to the stream. */ + public void writeUInt32NoTag(final int value) throws IOException { + writeRawVarint32(value); + } + + /** Write a {@code sint32} field to the stream. */ + public void writeSInt32NoTag(final int value) throws IOException { + writeRawVarint32(encodeZigZag32(value)); } /** Write a {@code fixed32} field to the stream. */ @@ -404,11 +441,59 @@ public final class CodedOutputStream { writeRawLittleEndian32(value); } + /** Write a {@code sfixed32} field to the stream. */ + public void writeSFixed32NoTag(final int value) throws IOException { + writeRawLittleEndian32(value); + } + + /** Write an {@code int64} field to the stream. */ + public void writeInt64NoTag(final long value) throws IOException { + writeRawVarint64(value); + } + + /** Write a {@code uint64} field to the stream. */ + public void writeUInt64NoTag(final long value) throws IOException { + writeRawVarint64(value); + } + + /** Write a {@code sint64} field to the stream. */ + public void writeSInt64NoTag(final long value) throws IOException { + writeRawVarint64(encodeZigZag64(value)); + } + + /** Write a {@code fixed64} field to the stream. */ + public void writeFixed64NoTag(final long value) throws IOException { + writeRawLittleEndian64(value); + } + + /** Write a {@code sfixed64} field to the stream. */ + public void writeSFixed64NoTag(final long value) throws IOException { + writeRawLittleEndian64(value); + } + + /** Write a {@code float} field to the stream. */ + public void writeFloatNoTag(final float value) throws IOException { + writeRawLittleEndian32(Float.floatToRawIntBits(value)); + } + + /** Write a {@code double} field to the stream. */ + public void writeDoubleNoTag(final double value) throws IOException { + writeRawLittleEndian64(Double.doubleToRawLongBits(value)); + } + /** Write a {@code bool} field to the stream. */ public void writeBoolNoTag(final boolean value) throws IOException { writeRawByte(value ? 1 : 0); } + /** + * Write an enum field to the stream. The provided value is the numeric + * value used to represent the enum value on the wire (not the enum ordinal value). + */ + public void writeEnumNoTag(final int value) throws IOException { + writeInt32NoTag(value); + } + /** Write a {@code string} field to the stream. */ // TODO(dweis): Document behavior on ill-formed UTF-16 input. public void writeStringNoTag(final String value) throws IOException { @@ -421,6 +506,523 @@ public final class CodedOutputStream { } } + /** Write a {@code bytes} field to the stream. */ + public void writeBytesNoTag(final ByteString value) throws IOException { + writeRawVarint32(value.size()); + writeRawBytes(value); + } + + /** Write a {@code bytes} field to the stream. */ + public void writeByteArrayNoTag(final byte[] value) throws IOException { + writeRawVarint32(value.length); + writeRawBytes(value); + } + + /** Write an embedded message field to the stream. */ + public void writeMessageNoTag(final MessageLite value) throws IOException { + writeRawVarint32(value.getSerializedSize()); + value.writeTo(this); + } + + // ================================================================= + // ================================================================= + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int32} field, including tag. + */ + public static int computeInt32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint32} field, including tag. + */ + public static int computeUInt32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint32} field, including tag. + */ + public static int computeSInt32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed32} field, including tag. + */ + public static int computeFixed32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed32} field, including tag. + */ + public static int computeSFixed32Size(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int64} field, including tag. + */ + public static int computeInt64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint64} field, including tag. + */ + public static int computeUInt64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint64} field, including tag. + */ + public static int computeSInt64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed64} field, including tag. + */ + public static int computeFixed64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed64} field, including tag. + */ + public static int computeSFixed64Size(final int fieldNumber, final long value) { + return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code float} field, including tag. + */ + public static int computeFloatSize(final int fieldNumber, final float value) { + return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code double} field, including tag. + */ + public static int computeDoubleSize(final int fieldNumber, final double value) { + return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bool} field, including tag. + */ + public static int computeBoolSize(final int fieldNumber, final boolean value) { + return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * enum field, including tag. The provided value is the numeric + * value used to represent the enum value on the wire (not the enum ordinal value). + */ + public static int computeEnumSize(final int fieldNumber, final int value) { + return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code string} field, including tag. + */ + public static int computeStringSize(final int fieldNumber, final String value) { + return computeTagSize(fieldNumber) + computeStringSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field, including tag. + */ + public static int computeBytesSize(final int fieldNumber, final ByteString value) { + return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field, including tag. + */ + public static int computeByteArraySize(final int fieldNumber, final byte[] value) { + return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field, including tag. + */ + public static int computeByteBufferSize(final int fieldNumber, final ByteBuffer value) { + return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * embedded message in lazy field, including tag. + */ + public static int computeLazyFieldSize(final int fieldNumber, final LazyFieldLite value) { + return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * embedded message field, including tag. + */ + public static int computeMessageSize(final int fieldNumber, final MessageLite value) { + return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * MessageSet extension to the stream. For historical reasons, + * the wire format differs from normal fields. + */ + public static int computeMessageSetExtensionSize(final int fieldNumber, final MessageLite value) { + return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + + computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * unparsed MessageSet extension field to the stream. For + * historical reasons, the wire format differs from normal fields. + */ + public static int computeRawMessageSetExtensionSize( + final int fieldNumber, final ByteString value) { + return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + + computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * lazily parsed MessageSet extension field to the stream. For + * historical reasons, the wire format differs from normal fields. + */ + public static int computeLazyFieldMessageSetExtensionSize( + final int fieldNumber, final LazyFieldLite value) { + return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + + computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + + computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value); + } + + // ----------------------------------------------------------------- + + /** Compute the number of bytes that would be needed to encode a tag. */ + public static int computeTagSize(final int fieldNumber) { + return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0)); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int32} field, including tag. + */ + public static int computeInt32SizeNoTag(final int value) { + if (value >= 0) { + return computeRawVarint32Size(value); + } else { + // Must sign-extend. + return 10; + } + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint32} field. + */ + public static int computeUInt32SizeNoTag(final int value) { + return computeRawVarint32Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint32} field. + */ + public static int computeSInt32SizeNoTag(final int value) { + return computeRawVarint32Size(encodeZigZag32(value)); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed32} field. + */ + public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed32} field. + */ + public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code int64} field, including tag. + */ + public static int computeInt64SizeNoTag(final long value) { + return computeRawVarint64Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code uint64} field, including tag. + */ + public static int computeUInt64SizeNoTag(final long value) { + return computeRawVarint64Size(value); + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sint64} field. + */ + public static int computeSInt64SizeNoTag(final long value) { + return computeRawVarint64Size(encodeZigZag64(value)); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code fixed64} field. + */ + public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode an + * {@code sfixed64} field. + */ + public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code float} field, including tag. + */ + public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) { + return LITTLE_ENDIAN_32_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code double} field, including tag. + */ + public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) { + return LITTLE_ENDIAN_64_SIZE; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bool} field. + */ + public static int computeBoolSizeNoTag(@SuppressWarnings("unused") final boolean unused) { + return 1; + } + + /** + * Compute the number of bytes that would be needed to encode an enum field. + * The provided value is the numeric value used to represent the enum value on the wire + * (not the enum ordinal value). + */ + public static int computeEnumSizeNoTag(final int value) { + return computeInt32SizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code string} field. + */ + public static int computeStringSizeNoTag(final String value) { + int length; + try { + length = Utf8.encodedLength(value); + } catch (UnpairedSurrogateException e) { + // TODO(dweis): Consider using nio Charset methods instead. + final byte[] bytes = value.getBytes(Internal.UTF_8); + length = bytes.length; + } + + return computeRawVarint32Size(length) + length; + } + + /** + * Compute the number of bytes that would be needed to encode an embedded + * message stored in lazy field. + */ + public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) { + final int size = value.getSerializedSize(); + return computeRawVarint32Size(size) + size; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field. + */ + public static int computeBytesSizeNoTag(final ByteString value) { + return computeRawVarint32Size(value.size()) + value.size(); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field. + */ + public static int computeByteArraySizeNoTag(final byte[] value) { + return computeRawVarint32Size(value.length) + value.length; + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code bytes} field. + */ + public static int computeByteBufferSizeNoTag(final ByteBuffer value) { + return computeRawVarint32Size(value.capacity()) + value.capacity(); + } + + /** + * Compute the number of bytes that would be needed to encode an embedded + * message field. + */ + public static int computeMessageSizeNoTag(final MessageLite value) { + final int size = value.getSerializedSize(); + return computeRawVarint32Size(size) + size; + } + + /** + * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers + * into values that can be efficiently encoded with varint. (Otherwise, + * negative values must be sign-extended to 64 bits to be varint encoded, + * thus always taking 10 bytes on the wire.) + * + * @param n A signed 32-bit integer. + * @return An unsigned 32-bit integer, stored in a signed int because + * Java has no explicit unsigned support. + */ + public static int encodeZigZag32(final int n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 31); + } + + /** + * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers + * into values that can be efficiently encoded with varint. (Otherwise, + * negative values must be sign-extended to 64 bits to be varint encoded, + * thus always taking 10 bytes on the wire.) + * + * @param n A signed 64-bit integer. + * @return An unsigned 64-bit integer, stored in a signed int because + * Java has no explicit unsigned support. + */ + public static long encodeZigZag64(final long n) { + // Note: the right-shift must be arithmetic + return (n << 1) ^ (n >> 63); + } + + // ================================================================= + + /** + * Flushes the stream and forces any buffered bytes to be written. This + * does not flush the underlying OutputStream. + */ + public void flush() throws IOException { + if (output != null) { + refreshBuffer(); + } + } + + /** + * If writing to a flat array, return the space left in the array. + * Otherwise, throws {@code UnsupportedOperationException}. + */ + public int spaceLeft() { + if (output == null) { + return limit - position; + } else { + throw new UnsupportedOperationException( + "spaceLeft() can only be called on CodedOutputStreams that are " + + "writing to a flat array."); + } + } + + /** + * Verifies that {@link #spaceLeft()} returns zero. It's common to create + * a byte array that is exactly big enough to hold a message, then write to + * it with a {@code CodedOutputStream}. Calling {@code checkNoSpaceLeft()} + * after writing verifies that the message was actually as big as expected, + * which can help catch bugs. + */ + public void checkNoSpaceLeft() { + if (spaceLeft() != 0) { + throw new IllegalStateException("Did not write as much data as expected."); + } + } + + /** + * If you create a CodedOutputStream around a simple flat array, you must + * not attempt to write more bytes than the array has space. Otherwise, + * this exception will be thrown. + */ + public static class OutOfSpaceException extends IOException { + private static final long serialVersionUID = -6947486886997889499L; + + private static final String MESSAGE = + "CodedOutputStream was writing to a flat byte array and ran out of space."; + + OutOfSpaceException() { + super(MESSAGE); + } + + OutOfSpaceException(Throwable cause) { + super(MESSAGE, cause); + } + } + + /** + * Get the total number of bytes successfully written to this stream. The + * returned value is not guaranteed to be accurate if exceptions have been + * found in the middle of writing. + */ + public int getTotalBytesWritten() { + return totalBytesWritten; + } + + // ================================================================= + + /** + * Internal helper that writes the current buffer to the output. The + * buffer position is reset to its initial value when this returns. + */ + private void refreshBuffer() throws IOException { + if (output == null) { + // We're writing to a single buffer. + throw new OutOfSpaceException(); + } + + // Since we have an output stream, this is our buffer + // and buffer offset == 0 + output.write(buffer, 0, position); + position = 0; + } + /** Write a {@code string} field to the stream. */ private void inefficientWriteStringNoTag(final String value) throws IOException { // Unfortunately there does not appear to be any way to tell Java to encode @@ -491,625 +1093,8 @@ public final class CodedOutputStream { } } - /** Write a {@code group} field to the stream. */ - public void writeGroupNoTag(final MessageLite value) throws IOException { - value.writeTo(this); - } - - - /** Write an embedded message field to the stream. */ - public void writeMessageNoTag(final MessageLite value) throws IOException { - writeRawVarint32(value.getSerializedSize()); - value.writeTo(this); - } - - - /** Write a {@code bytes} field to the stream. */ - public void writeBytesNoTag(final ByteString value) throws IOException { - writeRawVarint32(value.size()); - writeRawBytes(value); - } - - /** Write a {@code bytes} field to the stream. */ - public void writeByteArrayNoTag(final byte[] value) throws IOException { - writeRawVarint32(value.length); - writeRawBytes(value); - } - - /** Write a {@code bytes} field to the stream. */ - public void writeByteArrayNoTag(final byte[] value, - final int offset, - final int length) throws IOException { - writeRawVarint32(length); - writeRawBytes(value, offset, length); - } - - /** - * Write a {@code bytes} field to the stream. This method will write all - * content of the ByteBuffer regardless of the current position and limit - * (i.e., the number of bytes to be written is value.capacity(), not - * value.remaining()). Furthermore, this method doesn't alter the state of - * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain - * unchanged. If you only want to write the remaining bytes of a ByteBuffer, - * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}. - */ - public void writeByteBufferNoTag(final ByteBuffer value) throws IOException { - writeRawVarint32(value.capacity()); - writeRawBytes(value); - } - - /** Write a {@code uint32} field to the stream. */ - public void writeUInt32NoTag(final int value) throws IOException { - writeRawVarint32(value); - } - - /** - * Write an enum field to the stream. Caller is responsible - * for converting the enum value to its numeric value. - */ - public void writeEnumNoTag(final int value) throws IOException { - writeInt32NoTag(value); - } - - /** Write an {@code sfixed32} field to the stream. */ - public void writeSFixed32NoTag(final int value) throws IOException { - writeRawLittleEndian32(value); - } - - /** Write an {@code sfixed64} field to the stream. */ - public void writeSFixed64NoTag(final long value) throws IOException { - writeRawLittleEndian64(value); - } - - /** Write an {@code sint32} field to the stream. */ - public void writeSInt32NoTag(final int value) throws IOException { - writeRawVarint32(encodeZigZag32(value)); - } - - /** Write an {@code sint64} field to the stream. */ - public void writeSInt64NoTag(final long value) throws IOException { - writeRawVarint64(encodeZigZag64(value)); - } - - // ================================================================= - - /** - * Compute the number of bytes that would be needed to encode a - * {@code double} field, including tag. - */ - public static int computeDoubleSize(final int fieldNumber, - final double value) { - return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code float} field, including tag. - */ - public static int computeFloatSize(final int fieldNumber, final float value) { - return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code uint64} field, including tag. - */ - public static int computeUInt64Size(final int fieldNumber, final long value) { - return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code int64} field, including tag. - */ - public static int computeInt64Size(final int fieldNumber, final long value) { - return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code int32} field, including tag. - */ - public static int computeInt32Size(final int fieldNumber, final int value) { - return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code fixed64} field, including tag. - */ - public static int computeFixed64Size(final int fieldNumber, - final long value) { - return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code fixed32} field, including tag. - */ - public static int computeFixed32Size(final int fieldNumber, - final int value) { - return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bool} field, including tag. - */ - public static int computeBoolSize(final int fieldNumber, - final boolean value) { - return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code string} field, including tag. - */ - public static int computeStringSize(final int fieldNumber, - final String value) { - return computeTagSize(fieldNumber) + computeStringSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code group} field, including tag. - */ - public static int computeGroupSize(final int fieldNumber, - final MessageLite value) { - return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * embedded message field, including tag. - */ - public static int computeMessageSize(final int fieldNumber, - final MessageLite value) { - return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bytes} field, including tag. - */ - public static int computeBytesSize(final int fieldNumber, - final ByteString value) { - return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bytes} field, including tag. - */ - public static int computeByteArraySize(final int fieldNumber, - final byte[] value) { - return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bytes} field, including tag. - */ - public static int computeByteBufferSize(final int fieldNumber, - final ByteBuffer value) { - return computeTagSize(fieldNumber) + computeByteBufferSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * embedded message in lazy field, including tag. - */ - public static int computeLazyFieldSize(final int fieldNumber, - final LazyFieldLite value) { - return computeTagSize(fieldNumber) + computeLazyFieldSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code uint32} field, including tag. - */ - public static int computeUInt32Size(final int fieldNumber, final int value) { - return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * enum field, including tag. Caller is responsible for converting the - * enum value to its numeric value. - */ - public static int computeEnumSize(final int fieldNumber, final int value) { - return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sfixed32} field, including tag. - */ - public static int computeSFixed32Size(final int fieldNumber, - final int value) { - return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sfixed64} field, including tag. - */ - public static int computeSFixed64Size(final int fieldNumber, - final long value) { - return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sint32} field, including tag. - */ - public static int computeSInt32Size(final int fieldNumber, final int value) { - return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sint64} field, including tag. - */ - public static int computeSInt64Size(final int fieldNumber, final long value) { - return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode a - * MessageSet extension to the stream. For historical reasons, - * the wire format differs from normal fields. - */ - public static int computeMessageSetExtensionSize( - final int fieldNumber, final MessageLite value) { - return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + - computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + - computeMessageSize(WireFormat.MESSAGE_SET_MESSAGE, value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * unparsed MessageSet extension field to the stream. For - * historical reasons, the wire format differs from normal fields. - */ - public static int computeRawMessageSetExtensionSize( - final int fieldNumber, final ByteString value) { - return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + - computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + - computeBytesSize(WireFormat.MESSAGE_SET_MESSAGE, value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * lazily parsed MessageSet extension field to the stream. For - * historical reasons, the wire format differs from normal fields. - */ - public static int computeLazyFieldMessageSetExtensionSize( - final int fieldNumber, final LazyFieldLite value) { - return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 + - computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) + - computeLazyFieldSize(WireFormat.MESSAGE_SET_MESSAGE, value); - } - - // ----------------------------------------------------------------- - - /** - * Compute the number of bytes that would be needed to encode a - * {@code double} field, including tag. - */ - public static int computeDoubleSizeNoTag(final double value) { - return LITTLE_ENDIAN_64_SIZE; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code float} field, including tag. - */ - public static int computeFloatSizeNoTag(final float value) { - return LITTLE_ENDIAN_32_SIZE; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code uint64} field, including tag. - */ - public static int computeUInt64SizeNoTag(final long value) { - return computeRawVarint64Size(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code int64} field, including tag. - */ - public static int computeInt64SizeNoTag(final long value) { - return computeRawVarint64Size(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code int32} field, including tag. - */ - public static int computeInt32SizeNoTag(final int value) { - if (value >= 0) { - return computeRawVarint32Size(value); - } else { - // Must sign-extend. - return 10; - } - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code fixed64} field. - */ - public static int computeFixed64SizeNoTag(final long value) { - return LITTLE_ENDIAN_64_SIZE; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code fixed32} field. - */ - public static int computeFixed32SizeNoTag(final int value) { - return LITTLE_ENDIAN_32_SIZE; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bool} field. - */ - public static int computeBoolSizeNoTag(final boolean value) { - return 1; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code string} field. - */ - public static int computeStringSizeNoTag(final String value) { - int length; - try { - length = Utf8.encodedLength(value); - } catch (UnpairedSurrogateException e) { - // TODO(dweis): Consider using nio Charset methods instead. - final byte[] bytes = value.getBytes(Internal.UTF_8); - length = bytes.length; - } - - return computeRawVarint32Size(length) + length; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code group} field. - */ - public static int computeGroupSizeNoTag(final MessageLite value) { - return value.getSerializedSize(); - } - - /** - * Compute the number of bytes that would be needed to encode an embedded - * message field. - */ - public static int computeMessageSizeNoTag(final MessageLite value) { - final int size = value.getSerializedSize(); - return computeRawVarint32Size(size) + size; - } - - /** - * Compute the number of bytes that would be needed to encode an embedded - * message stored in lazy field. - */ - public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) { - final int size = value.getSerializedSize(); - return computeRawVarint32Size(size) + size; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bytes} field. - */ - public static int computeBytesSizeNoTag(final ByteString value) { - return computeRawVarint32Size(value.size()) + - value.size(); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bytes} field. - */ - public static int computeByteArraySizeNoTag(final byte[] value) { - return computeRawVarint32Size(value.length) + value.length; - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code bytes} field. - */ - public static int computeByteBufferSizeNoTag(final ByteBuffer value) { - return computeRawVarint32Size(value.capacity()) + value.capacity(); - } - - /** - * Compute the number of bytes that would be needed to encode a - * {@code uint32} field. - */ - public static int computeUInt32SizeNoTag(final int value) { - return computeRawVarint32Size(value); - } - - /** - * Compute the number of bytes that would be needed to encode an enum field. - * Caller is responsible for converting the enum value to its numeric value. - */ - public static int computeEnumSizeNoTag(final int value) { - return computeInt32SizeNoTag(value); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sfixed32} field. - */ - public static int computeSFixed32SizeNoTag(final int value) { - return LITTLE_ENDIAN_32_SIZE; - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sfixed64} field. - */ - public static int computeSFixed64SizeNoTag(final long value) { - return LITTLE_ENDIAN_64_SIZE; - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sint32} field. - */ - public static int computeSInt32SizeNoTag(final int value) { - return computeRawVarint32Size(encodeZigZag32(value)); - } - - /** - * Compute the number of bytes that would be needed to encode an - * {@code sint64} field. - */ - public static int computeSInt64SizeNoTag(final long value) { - return computeRawVarint64Size(encodeZigZag64(value)); - } - - // ================================================================= - - /** - * Internal helper that writes the current buffer to the output. The - * buffer position is reset to its initial value when this returns. - */ - private void refreshBuffer() throws IOException { - if (output == null) { - // We're writing to a single buffer. - throw new OutOfSpaceException(); - } - - // Since we have an output stream, this is our buffer - // and buffer offset == 0 - output.write(buffer, 0, position); - position = 0; - } - - /** - * Flushes the stream and forces any buffered bytes to be written. This - * does not flush the underlying OutputStream. - */ - public void flush() throws IOException { - if (output != null) { - refreshBuffer(); - } - } - - /** - * If writing to a flat array, return the space left in the array. - * Otherwise, throws {@code UnsupportedOperationException}. - */ - public int spaceLeft() { - if (output == null) { - return limit - position; - } else { - throw new UnsupportedOperationException( - "spaceLeft() can only be called on CodedOutputStreams that are " + - "writing to a flat array."); - } - } - - /** - * Verifies that {@link #spaceLeft()} returns zero. It's common to create - * a byte array that is exactly big enough to hold a message, then write to - * it with a {@code CodedOutputStream}. Calling {@code checkNoSpaceLeft()} - * after writing verifies that the message was actually as big as expected, - * which can help catch bugs. - */ - public void checkNoSpaceLeft() { - if (spaceLeft() != 0) { - throw new IllegalStateException( - "Did not write as much data as expected."); - } - } - - /** - * If you create a CodedOutputStream around a simple flat array, you must - * not attempt to write more bytes than the array has space. Otherwise, - * this exception will be thrown. - */ - public static class OutOfSpaceException extends IOException { - private static final long serialVersionUID = -6947486886997889499L; - - private static final String MESSAGE = - "CodedOutputStream was writing to a flat byte array and ran out of space."; - - OutOfSpaceException() { - super(MESSAGE); - } - - OutOfSpaceException(Throwable cause) { - super(MESSAGE, cause); - } - } - - /** - * Get the total number of bytes successfully written to this stream. The - * returned value is not guaranteed to be accurate if exceptions have been - * found in the middle of writing. - */ - public int getTotalBytesWritten() { - return totalBytesWritten; - } - - /** Write a single byte. */ - public void writeRawByte(final byte value) throws IOException { - if (position == limit) { - refreshBuffer(); - } - - buffer[position++] = value; - ++totalBytesWritten; - } - - /** Write a single byte, represented by an integer value. */ - public void writeRawByte(final int value) throws IOException { - writeRawByte((byte) value); - } - - /** Write a byte string. */ - public void writeRawBytes(final ByteString value) throws IOException { - writeRawBytes(value, 0, value.size()); - } - - /** Write an array of bytes. */ - public void writeRawBytes(final byte[] value) throws IOException { - writeRawBytes(value, 0, value.length); - } - - /** - * Write a ByteBuffer. This method will write all content of the ByteBuffer - * regardless of the current position and limit (i.e., the number of bytes - * to be written is value.capacity(), not value.remaining()). Furthermore, - * this method doesn't alter the state of the passed-in ByteBuffer. Its - * position, limit, mark, etc. will remain unchanged. If you only want to - * write the remaining bytes of a ByteBuffer, you can call - * {@code writeRawBytes(byteBuffer.slice())}. - */ - public void writeRawBytes(final ByteBuffer value) throws IOException { - if (value.hasArray()) { - writeRawBytes(value.array(), value.arrayOffset(), value.capacity()); - } else { - ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); - writeRawBytesInternal(duplicated); - } - } - /** Write a ByteBuffer that isn't backed by an array. */ - private void writeRawBytesInternal(final ByteBuffer value) - throws IOException { + private void writeRawBytesInternal(final ByteBuffer value) throws IOException { int length = value.remaining(); if (limit - position >= length) { // We have room in the current buffer. @@ -1143,43 +1128,29 @@ public final class CodedOutputStream { } } - /** Write part of an array of bytes. */ - public void writeRawBytes(final byte[] value, int offset, int length) - throws IOException { - if (limit - position >= length) { - // We have room in the current buffer. - System.arraycopy(value, offset, buffer, position, length); - position += length; - totalBytesWritten += length; - } else { - // Write extends past current buffer. Fill the rest of this buffer and - // flush. - final int bytesWritten = limit - position; - System.arraycopy(value, offset, buffer, position, bytesWritten); - offset += bytesWritten; - length -= bytesWritten; - position = limit; - totalBytesWritten += bytesWritten; - refreshBuffer(); + /** Write a {@code bytes} field to the stream. Visible for testing. */ + void writeByteArrayNoTag(final byte[] value, final int offset, final int length) + throws IOException { + writeRawVarint32(length); + writeRawBytes(value, offset, length); + } - // Now deal with the rest. - // Since we have an output stream, this is our buffer - // and buffer offset == 0 - if (length <= limit) { - // Fits in new buffer. - System.arraycopy(value, offset, buffer, 0, length); - position = length; - } else { - // Write is very big. Let's do it all at once. - output.write(value, offset, length); - } - totalBytesWritten += length; - } + /** + * Write a {@code bytes} field to the stream. This method will write all + * content of the ByteBuffer regardless of the current position and limit + * (i.e., the number of bytes to be written is value.capacity(), not + * value.remaining()). Furthermore, this method doesn't alter the state of + * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain + * unchanged. If you only want to write the remaining bytes of a ByteBuffer, + * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}. + */ + private void writeByteBufferNoTag(final ByteBuffer value) throws IOException { + writeRawVarint32(value.capacity()); + writeRawBytes(value); } /** Write part of a byte string. */ - public void writeRawBytes(final ByteString value, int offset, int length) - throws IOException { + private void writeRawBytes(final ByteString value, int offset, int length) throws IOException { if (limit - position >= length) { // We have room in the current buffer. value.copyTo(buffer, offset, position, length); @@ -1210,21 +1181,57 @@ public final class CodedOutputStream { } } - /** Encode and write a tag. */ - public void writeTag(final int fieldNumber, final int wireType) - throws IOException { - writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType)); + // ================================================================= + + /** + * Write a {@code group} field, including tag, to the stream. + * + * @deprecated groups are deprecated. + */ + @Deprecated + public void writeGroup(final int fieldNumber, final MessageLite value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); + writeGroupNoTag(value); + writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); } - /** Compute the number of bytes that would be needed to encode a tag. */ - public static int computeTagSize(final int fieldNumber) { - return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0)); + /** + * Write a {@code group} field to the stream. + * + * @deprecated groups are deprecated. + */ + @Deprecated + public void writeGroupNoTag(final MessageLite value) throws IOException { + value.writeTo(this); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code group} field, including tag. + * + * @deprecated groups are deprecated. + */ + @Deprecated + public static int computeGroupSize(final int fieldNumber, final MessageLite value) { + return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value); + } + + /** + * Compute the number of bytes that would be needed to encode a + * {@code group} field. + */ + @Deprecated + public static int computeGroupSizeNoTag(final MessageLite value) { + return value.getSerializedSize(); } /** * Encode and write a varint. {@code value} is treated as * unsigned, so it won't be sign-extended if negative. + * + * @deprecated use {@link #writeUInt32NoTag} instead. */ + @Deprecated public void writeRawVarint32(int value) throws IOException { while (true) { if ((value & ~0x7F) == 0) { @@ -1238,95 +1245,104 @@ public final class CodedOutputStream { } /** - * Compute the number of bytes that would be needed to encode a varint. - * {@code value} is treated as unsigned, so it won't be sign-extended if - * negative. + * Encode and write a varint. + * + * @deprecated use {@link #writeUInt64NoTag} instead. */ - public static int computeRawVarint32Size(final int value) { - if ((value & (~0 << 7)) == 0) return 1; - if ((value & (~0 << 14)) == 0) return 2; - if ((value & (~0 << 21)) == 0) return 3; - if ((value & (~0 << 28)) == 0) return 4; - return 5; - } - - /** Encode and write a varint. */ + @Deprecated public void writeRawVarint64(long value) throws IOException { while (true) { if ((value & ~0x7FL) == 0) { - writeRawByte((int)value); + writeRawByte((int) value); return; } else { - writeRawByte(((int)value & 0x7F) | 0x80); + writeRawByte(((int) value & 0x7F) | 0x80); value >>>= 7; } } } - /** Compute the number of bytes that would be needed to encode a varint. */ + /** + * Compute the number of bytes that would be needed to encode a varint. + * {@code value} is treated as unsigned, so it won't be sign-extended if + * negative. + * + * @deprecated use {@link #computeUInt32SizeNoTag(int)} instead. + */ + @Deprecated + public static int computeRawVarint32Size(final int value) { + if ((value & (~0 << 7)) == 0) { + return 1; + } + if ((value & (~0 << 14)) == 0) { + return 2; + } + if ((value & (~0 << 21)) == 0) { + return 3; + } + if ((value & (~0 << 28)) == 0) { + return 4; + } + return 5; + } + + /** + * Compute the number of bytes that would be needed to encode a varint. + * + * @deprecated use {@link #computeUInt64SizeNoTag(long)} instead. + */ + @Deprecated public static int computeRawVarint64Size(long value) { // handle two popular special cases up front ... - if ((value & (~0L << 7)) == 0L) return 1; - if (value < 0L) return 10; + if ((value & (~0L << 7)) == 0L) { + return 1; + } + if (value < 0L) { + return 10; + } // ... leaving us with 8 remaining, which we can divide and conquer int n = 2; - if ((value & (~0L << 35)) != 0L) { n += 4; value >>>= 28; } - if ((value & (~0L << 21)) != 0L) { n += 2; value >>>= 14; } - if ((value & (~0L << 14)) != 0L) { n += 1; } + if ((value & (~0L << 35)) != 0L) { + n += 4; + value >>>= 28; + } + if ((value & (~0L << 21)) != 0L) { + n += 2; + value >>>= 14; + } + if ((value & (~0L << 14)) != 0L) { + n += 1; + } return n; } - /** Write a little-endian 32-bit integer. */ + /** + * Write a little-endian 32-bit integer. + * + * @deprecated Use {@link #writeFixed32NoTag} instead. + */ + @Deprecated public void writeRawLittleEndian32(final int value) throws IOException { - writeRawByte((value ) & 0xFF); - writeRawByte((value >> 8) & 0xFF); + writeRawByte((value) & 0xFF); + writeRawByte((value >> 8) & 0xFF); writeRawByte((value >> 16) & 0xFF); writeRawByte((value >> 24) & 0xFF); } - public static final int LITTLE_ENDIAN_32_SIZE = 4; - - /** Write a little-endian 64-bit integer. */ + /** + * Write a little-endian 64-bit integer. + * + * @deprecated Use {@link #writeFixed64NoTag} instead. + */ + @Deprecated public void writeRawLittleEndian64(final long value) throws IOException { - writeRawByte((int)(value ) & 0xFF); - writeRawByte((int)(value >> 8) & 0xFF); - writeRawByte((int)(value >> 16) & 0xFF); - writeRawByte((int)(value >> 24) & 0xFF); - writeRawByte((int)(value >> 32) & 0xFF); - writeRawByte((int)(value >> 40) & 0xFF); - writeRawByte((int)(value >> 48) & 0xFF); - writeRawByte((int)(value >> 56) & 0xFF); - } - - public static final int LITTLE_ENDIAN_64_SIZE = 8; - - /** - * Encode a ZigZag-encoded 32-bit value. ZigZag encodes signed integers - * into values that can be efficiently encoded with varint. (Otherwise, - * negative values must be sign-extended to 64 bits to be varint encoded, - * thus always taking 10 bytes on the wire.) - * - * @param n A signed 32-bit integer. - * @return An unsigned 32-bit integer, stored in a signed int because - * Java has no explicit unsigned support. - */ - public static int encodeZigZag32(final int n) { - // Note: the right-shift must be arithmetic - return (n << 1) ^ (n >> 31); - } - - /** - * Encode a ZigZag-encoded 64-bit value. ZigZag encodes signed integers - * into values that can be efficiently encoded with varint. (Otherwise, - * negative values must be sign-extended to 64 bits to be varint encoded, - * thus always taking 10 bytes on the wire.) - * - * @param n A signed 64-bit integer. - * @return An unsigned 64-bit integer, stored in a signed int because - * Java has no explicit unsigned support. - */ - public static long encodeZigZag64(final long n) { - // Note: the right-shift must be arithmetic - return (n << 1) ^ (n >> 63); + writeRawByte((int) (value) & 0xFF); + writeRawByte((int) (value >> 8) & 0xFF); + writeRawByte((int) (value >> 16) & 0xFF); + writeRawByte((int) (value >> 24) & 0xFF); + writeRawByte((int) (value >> 32) & 0xFF); + writeRawByte((int) (value >> 40) & 0xFF); + writeRawByte((int) (value >> 48) & 0xFF); + writeRawByte((int) (value >> 56) & 0xFF); } } 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 5e15cfbe..e303e138 100644 --- a/java/core/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java @@ -272,7 +272,7 @@ public final class Descriptors { * because a field has an undefined type or because two messages * were defined with the same name. */ - private static FileDescriptor buildFrom( + public static FileDescriptor buildFrom( final FileDescriptorProto proto, final FileDescriptor[] dependencies, final boolean allowUnknownDependencies) throws DescriptorValidationException { @@ -1123,7 +1123,7 @@ public final class Descriptors { private JavaType javaType; public FieldDescriptorProto.Type toProto() { - return FieldDescriptorProto.Type.valueOf(ordinal() + 1); + return FieldDescriptorProto.Type.forNumber(ordinal() + 1); } public JavaType getJavaType() { return javaType; } diff --git a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java index 6f41fb81..3cd4c884 100644 --- a/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java +++ b/java/core/src/main/java/com/google/protobuf/ExperimentalApi.java @@ -1,3 +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. + package com.google.protobuf; import java.lang.annotation.Documented; 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 ceb97a4e..a50afe55 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -1019,7 +1019,9 @@ public abstract class GeneratedMessage extends AbstractMessage verifyContainingType(field); final Object value = extensions.getField(field); if (value == null) { - if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + if (field.isRepeated()) { + return Collections.emptyList(); + } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { // Lacking an ExtensionRegistry, we have no way to determine the // extension's real type, so we return a DynamicMessage. return DynamicMessage.getDefaultInstance(field.getMessageType()); diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java index 81e1862c..12a1472d 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -30,6 +30,7 @@ package com.google.protobuf; +import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream; import com.google.protobuf.Internal.BooleanList; import com.google.protobuf.Internal.DoubleList; import com.google.protobuf.Internal.FloatList; @@ -39,6 +40,7 @@ import com.google.protobuf.Internal.ProtobufList; import com.google.protobuf.WireFormat.FieldType; import java.io.IOException; +import java.io.InputStream; import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; @@ -57,10 +59,7 @@ import java.util.Map; public abstract class GeneratedMessageLite< MessageType extends GeneratedMessageLite, BuilderType extends GeneratedMessageLite.Builder> - extends AbstractMessageLite - implements Serializable { - - private static final long serialVersionUID = 1L; + extends AbstractMessageLite { /** For use by generated code only. Lazily initialized to reduce allocations. */ protected UnknownFieldSetLite unknownFields = null; @@ -83,6 +82,24 @@ public abstract class GeneratedMessageLite< return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER); } + /** + * A reflective toString function. This is primarily intended as a developer aid, while keeping + * binary size down. The first line of the {@code toString()} representation includes a commented + * version of {@code super.toString()} to act as an indicator that this should not be relied on + * for comparisons. + *

+ * NOTE: This method relies on the field getter methods not being stripped or renamed by proguard. + * If they are, the fields will not be included in the returned string representation. + *

+ * NOTE: This implementation is liable to change in the future, and should not be relied on in + * code. + */ + @Override + public String toString() { + return MessageLiteToString.toString(this, super.toString()); + } + + // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as // mutable during the parsing constructor and immutable after. This allows us to avoid // any unnecessary intermediary allocations while reducing the generated code size. @@ -303,10 +320,9 @@ public abstract class GeneratedMessageLite< throws java.io.IOException { MessageType parsedMessage = null; try { - parsedMessage = - (MessageType) getDefaultInstanceForType().getParserForType().parsePartialFrom( - input, extensionRegistry); - } catch (com.google.protobuf.InvalidProtocolBufferException e) { + parsedMessage = parsePartialFrom( + (MessageType) getDefaultInstanceForType(), input, extensionRegistry); + } catch (InvalidProtocolBufferException e) { parsedMessage = (MessageType) e.getUnfinishedMessage(); throw e; } finally { @@ -562,7 +578,6 @@ public abstract class GeneratedMessageLite< return extensions.isInitialized(); } - @Override protected final void doneParsing() { super.doneParsing(); @@ -1049,7 +1064,12 @@ public abstract class GeneratedMessageLite< * A serialized (serializable) form of the generated message. Stores the * message as a class name and a byte array. */ - static final class SerializedForm implements Serializable { + protected static final class SerializedForm implements Serializable { + + public static SerializedForm of(MessageLite message) { + return new SerializedForm(message); + } + private static final long serialVersionUID = 0L; private final String messageClassName; @@ -1093,16 +1113,6 @@ public abstract class GeneratedMessageLite< } } } - - /** - * Replaces this object in the output stream with a serialized form. - * Part of Java's serialization magic. Generated sub-classes must override - * this method by calling {@code return super.writeReplace();} - * @return a SerializedForm of this message - */ - protected Object writeReplace() throws ObjectStreamException { - return new SerializedForm(this); - } /** * Checks that the {@link Extension} is Lite and returns it as a @@ -1135,45 +1145,6 @@ public abstract class GeneratedMessageLite< message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); } - /** - * A static helper method for parsing a partial from input using the extension registry and the - * instance. - */ - static > T parsePartialFrom( - T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - try { - return (T) instance.dynamicMethod( - MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry); - } catch (RuntimeException e) { - if (e.getCause() instanceof InvalidProtocolBufferException) { - throw (InvalidProtocolBufferException) e.getCause(); - } - throw e; - } - } - - /** - * A {@link Parser} implementation that delegates to the default instance. - *

- * For use by generated code only. - */ - protected static class DefaultInstanceBasedParser> - extends AbstractParser { - - private T defaultInstance; - - public DefaultInstanceBasedParser(T defaultInstance) { - this.defaultInstance = defaultInstance; - } - - @Override - public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry); - } - } - protected static IntList newIntList() { return new IntArrayList(); } @@ -1269,8 +1240,218 @@ public abstract class GeneratedMessageLite< protected static ProtobufList emptyProtobufList() { return ProtobufArrayList.emptyList(); } - + protected static LazyStringArrayList emptyLazyStringArrayList() { return LazyStringArrayList.emptyList(); } + + /** + * A {@link Parser} implementation that delegates to the default instance. + *

+ * For use by generated code only. + */ + protected static class DefaultInstanceBasedParser> + extends AbstractParser { + + private T defaultInstance; + + public DefaultInstanceBasedParser(T defaultInstance) { + this.defaultInstance = defaultInstance; + } + + @Override + public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry); + } + } + + /** + * A static helper method for parsing a partial from input using the extension registry and the + * instance. + */ + // TODO(dweis): Should this verify that the last tag was 0? + static > T parsePartialFrom( + T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + T result; + try { + result = (T) instance.dynamicMethod( + MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry); + } catch (RuntimeException e) { + if (e.getCause() instanceof InvalidProtocolBufferException) { + throw (InvalidProtocolBufferException) e.getCause(); + } + throw e; + } + return result; + } + + protected static > T parsePartialFrom( + T defaultInstance, + CodedInputStream input) + throws InvalidProtocolBufferException { + return parsePartialFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry()); + } + + /** + * Helper method to check if message is initialized. + * + * @throws InvalidProtocolBufferException if it is not initialized. + * @return The message to check. + */ + private static > T checkMessageInitialized(T message) + throws InvalidProtocolBufferException { + if (message != null && !message.isInitialized()) { + throw message.newUninitializedMessageException() + .asInvalidProtocolBufferException() + .setUnfinishedMessage(message); + } + return message; + } + + // Validates last tag. + protected static > T parseFrom( + T defaultInstance, ByteString data) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parseFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry())); + } + + // Validates last tag. + protected static > T parseFrom( + T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry)); + } + + // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the + // ByteString. + private static > T parsePartialFrom( + T defaultInstance, ByteString data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + T message; + try { + CodedInputStream input = data.newCodedInput(); + message = parsePartialFrom(defaultInstance, input, extensionRegistry); + try { + input.checkLastTagWas(0); + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(message); + } + return message; + } catch (InvalidProtocolBufferException e) { + throw e; + } + } + + // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the + // ByteString. + private static > T parsePartialFrom( + T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + T message; + try { + CodedInputStream input = CodedInputStream.newInstance(data); + message = parsePartialFrom(defaultInstance, input, extensionRegistry); + try { + input.checkLastTagWas(0); + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(message); + } + return message; + } catch (InvalidProtocolBufferException e) { + throw e; + } + } + + // Validates last tag. + protected static > T parseFrom( + T defaultInstance, byte[] data) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialFrom(defaultInstance, data, ExtensionRegistryLite.getEmptyRegistry())); + } + + // Validates last tag. + protected static > T parseFrom( + T defaultInstance, byte[] data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry)); + } + + // Does not validate last tag. + protected static > T parseFrom( + T defaultInstance, InputStream input) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input), + ExtensionRegistryLite.getEmptyRegistry())); + } + + // Does not validate last tag. + protected static > T parseFrom( + T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialFrom(defaultInstance, CodedInputStream.newInstance(input), extensionRegistry)); + } + + // Does not validate last tag. + protected static > T parseFrom( + T defaultInstance, CodedInputStream input) + throws InvalidProtocolBufferException { + return parseFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry()); + } + + // Does not validate last tag. + protected static > T parseFrom( + T defaultInstance, CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialFrom(defaultInstance, input, extensionRegistry)); + } + + // Validates last tag. + protected static > T parseDelimitedFrom( + T defaultInstance, InputStream input) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialDelimitedFrom(defaultInstance, input, + ExtensionRegistryLite.getEmptyRegistry())); + } + + // Validates last tag. + protected static > T parseDelimitedFrom( + T defaultInstance, InputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialDelimitedFrom(defaultInstance, input, extensionRegistry)); + } + + private static > T parsePartialDelimitedFrom( + T defaultInstance, + InputStream input, + ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + int size; + try { + int firstByte = input.read(); + if (firstByte == -1) { + return null; + } + size = CodedInputStream.readRawVarint32(firstByte, input); + } catch (IOException e) { + throw new InvalidProtocolBufferException(e.getMessage()); + } + InputStream limitedInput = new LimitedInputStream(input, size); + CodedInputStream codedInput = CodedInputStream.newInstance(limitedInput); + T message = parsePartialFrom(defaultInstance, codedInput, extensionRegistry); + try { + codedInput.checkLastTagWas(0); + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(message); + } + return message; + } } diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java index e19b6dca..abf7ddd6 100644 --- a/java/core/src/main/java/com/google/protobuf/Internal.java +++ b/java/core/src/main/java/com/google/protobuf/Internal.java @@ -51,10 +51,12 @@ import java.util.Set; * * @author kenton@google.com (Kenton Varda) */ -public class Internal { +public final class Internal { - protected static final Charset UTF_8 = Charset.forName("UTF-8"); - protected static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + private Internal() {} + + static final Charset UTF_8 = Charset.forName("UTF-8"); + static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); /** * Helper called by generated code to construct default values for string @@ -406,6 +408,7 @@ public class Internal { public static final CodedInputStream EMPTY_CODED_INPUT_STREAM = CodedInputStream.newInstance(EMPTY_BYTE_ARRAY); + /** * Provides an immutable view of {@code List} around a {@code List}. * diff --git a/java/core/src/main/java/com/google/protobuf/LazyField.java b/java/core/src/main/java/com/google/protobuf/LazyField.java index 5e0a485c..3da8b900 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyField.java +++ b/java/core/src/main/java/com/google/protobuf/LazyField.java @@ -39,14 +39,14 @@ import java.util.Map.Entry; * * Most of key methods are implemented in {@link LazyFieldLite} but this class * can contain default instance of the message to provide {@code hashCode()}, - * {@code equals()} and {@code toString()}. + * {@code euqals()} and {@code toString()}. * * @author xiangl@google.com (Xiang Li) */ public class LazyField extends LazyFieldLite { /** - * Carry a message's default instance which is used by {@code hashCode()}, {@code equals()} and + * Carry a message's default instance which is used by {@code hashCode()}, {@code euqals()} and * {@code toString()}. */ private final MessageLite defaultInstance; diff --git a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java index eea1fe3c..016ec20d 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java +++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java @@ -30,14 +30,26 @@ package com.google.protobuf; +import java.io.IOException; + /** * LazyFieldLite encapsulates the logic of lazily parsing message fields. It stores - * the message in a ByteString initially and then parse it on-demand. + * the message in a ByteString initially and then parses it on-demand. * - * LazyField is thread-compatible e.g. concurrent read are safe, however, - * synchronizations are needed under read/write situations. + * LazyFieldLite is thread-compatible: concurrent reads are safe once the proto that this + * LazyFieldLite is a part of is no longer being mutated by its Builder. However, explicit + * synchronization is needed under read/write situations. * - * This class is internal implementation detail, so you don't need to use it directly. + * When a LazyFieldLite is used in the context of a MessageLite object, its behavior is considered + * to be immutable and none of the setter methods in its API are expected to be invoked. All of the + * getters are expected to be thread-safe. When used in the context of a MessageLite.Builder, + * setters can be invoked, but there is no guarantee of thread safety. + * + * TODO(yatin,dweis): Consider splitting this class's functionality and put the mutable methods + * into a separate builder class to allow us to give stronger compile-time guarantees. + * + * This class is internal implementation detail of the protobuf library, so you don't need to use it + * directly. * * @author xiangl@google.com (Xiang Li) */ @@ -46,8 +58,34 @@ public class LazyFieldLite { ExtensionRegistryLite.getEmptyRegistry(); /** - * A delayed-parsed version of the bytes. When this is non-null then {@code extensionRegistry } is - * also non-null and {@code value} and {@code memoizedBytes} are null. + * The value associated with the LazyFieldLite object is stored in one or more of the following + * three fields (delayedBytes, value, memoizedBytes). They should together be interpreted as + * follows. + * 1) delayedBytes can be non-null, while value and memoizedBytes is null. The object will be in + * this state while the value for the object has not yet been parsed. + * 2) Both delayedBytes and value are non-null. The object transitions to this state as soon as + * some caller needs to access the value (by invoking getValue()). + * 3) memoizedBytes is merely an optimization for calls to LazyFieldLite.toByteString() to avoid + * recomputing the ByteString representation on each call. Instead, when the value is parsed + * from delayedBytes, we will also assign the contents of delayedBytes to memoizedBytes (since + * that is the ByteString representation of value). + * 4) Finally, if the LazyFieldLite was created directly with a parsed MessageLite value, then + * delayedBytes will be null, and memoizedBytes will be initialized only upon the first call to + * LazyFieldLite.toByteString(). + * + * Given the above conditions, any caller that needs a serialized representation of this object + * must first check if the memoizedBytes or delayedBytes ByteString is non-null and use it + * directly; if both of those are null, it can look at the parsed value field. Similarly, any + * caller that needs a parsed value must first check if the value field is already non-null, if + * not it must parse the value from delayedBytes. + */ + + /** + * A delayed-parsed version of the contents of this field. When this field is non-null, then the + * "value" field is allowed to be null until the time that the value needs to be read. + * + * When delayedBytes is non-null then {@code extensionRegistry} is required to also be non-null. + * {@code value} and {@code memoizedBytes} will be initialized lazily. */ private ByteString delayedBytes; @@ -60,12 +98,15 @@ public class LazyFieldLite { private ExtensionRegistryLite extensionRegistry; /** - * The parsed value. When this is non-null then {@code delayedBytes} will be null. + * The parsed value. When this is null and a caller needs access to the MessageLite value, then + * {@code delayedBytes} will be parsed lazily at that time. */ protected volatile MessageLite value; /** - * The memoized bytes for {@code value}. Will be null when {@code value} is null. + * The memoized bytes for {@code value}. This is an optimization for the toByteString() method to + * not have to recompute its return-value on each invocation. + * TODO(yatin): Figure out whether this optimization is actually necessary. */ private volatile ByteString memoizedBytes; @@ -230,6 +271,46 @@ public class LazyFieldLite { return; } } + + /** + * Merges another instance's contents from a stream. + * + *

LazyField is not thread-safe for write access. Synchronizations are needed + * under read/write situations. + */ + public void mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException { + if (this.containsDefaultInstance()) { + setByteString(input.readBytes(), extensionRegistry); + return; + } + + // If the other field has an extension registry but this does not, copy over the other extension + // registry. + if (this.extensionRegistry == null) { + this.extensionRegistry = extensionRegistry; + } + + // In the case that both of them are not parsed we simply concatenate the bytes to save time. In + // the (probably rare) case that they have different extension registries there is a chance that + // some of the extensions may be dropped, but the tradeoff of making this operation fast seems + // to outway the benefits of combining the extension registries, which is not normally done for + // lite protos anyways. + if (this.delayedBytes != null) { + setByteString(this.delayedBytes.concat(input.readBytes()), this.extensionRegistry); + return; + } + + // We are parsed and both contain data. We won't drop any extensions here directly, but in the + // case that the extension registries are not the same then we might in the future if we + // need to serialize and parse a message again. + try { + setValue(value.toBuilder().mergeFrom(input, extensionRegistry).build()); + } catch (InvalidProtocolBufferException e) { + // Nothing is logged and no exceptions are thrown. Clients will be unaware that a proto + // was invalid. + } + } private static MessageLite mergeValueAndBytes( MessageLite value, ByteString otherBytes, ExtensionRegistryLite extensionRegistry) { @@ -259,10 +340,10 @@ public class LazyFieldLite { * parsed. Be careful when using this method. */ public int getSerializedSize() { - if (delayedBytes != null) { - return delayedBytes.size(); - } else if (memoizedBytes != null) { + if (memoizedBytes != null) { return memoizedBytes.size(); + } else if (delayedBytes != null) { + return delayedBytes.size(); } else if (value != null) { return value.getSerializedSize(); } else { @@ -274,12 +355,12 @@ public class LazyFieldLite { * Returns a BytesString for this field in a thread-safe way. */ public ByteString toByteString() { - if (delayedBytes != null) { - return delayedBytes; - } if (memoizedBytes != null) { return memoizedBytes; } + if (delayedBytes != null) { + return delayedBytes; + } synchronized (this) { if (memoizedBytes != null) { return memoizedBytes; @@ -311,18 +392,15 @@ public class LazyFieldLite { .parseFrom(delayedBytes, extensionRegistry); this.value = parsedValue; this.memoizedBytes = delayedBytes; - this.delayedBytes = null; } else { this.value = defaultInstance; this.memoizedBytes = ByteString.EMPTY; - this.delayedBytes = null; } } catch (InvalidProtocolBufferException e) { // Nothing is logged and no exceptions are thrown. Clients will be unaware that this proto // was invalid. this.value = defaultInstance; this.memoizedBytes = ByteString.EMPTY; - this.delayedBytes = null; } } } 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 c3be3cca..68c430cf 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java @@ -30,12 +30,12 @@ package com.google.protobuf; -import java.util.Arrays; -import java.util.List; import java.util.AbstractList; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.RandomAccess; /** diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java index e69de29b..2a6e0e30 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java +++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java @@ -0,0 +1,200 @@ +// 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. + +package com.google.protobuf; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Helps generate {@link String} representations of {@link MessageLite} protos. + */ +final class MessageLiteToString { + /** + * Suffix for *_FIELD_NUMBER fields. This is used to reflectively detect proto fields that should + * be toString()ed. + */ + private static final String FIELD_NUMBER_NAME_SUFFIX = "_FIELD_NUMBER"; + + /** + * Returns a {@link String} representation of the {@link MessageLite} object. The first line of + * the {@code String} representation representation includes a comment string to uniquely identify + * the objcet instance. This acts as an indicator that this should not be relied on for + * comparisons. + * + *

For use by generated code only. + */ + static String toString(MessageLite messageLite, String commentString) { + StringBuilder buffer = new StringBuilder(); + buffer.append("# ").append(commentString); + reflectivePrintWithIndent(messageLite, buffer, 0); + return buffer.toString(); + } + + /** + * Reflectively prints the {@link MessageLite} to the buffer at given {@code indent} level. + * + * @param buffer the buffer to write to + * @param indent the number of spaces to indent the proto by + */ + private static void reflectivePrintWithIndent( + MessageLite messageLite, StringBuilder buffer, int indent) { + // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(), and + // getFooList() which might be useful for building an object's string representation. + Map nameToNoArgMethod = new HashMap(); + for (Method method : messageLite.getClass().getDeclaredMethods()) { + if (method.getParameterTypes().length == 0) { + nameToNoArgMethod.put(method.getName(), method); + } + } + + for (Field field : messageLite.getClass().getDeclaredFields()) { + String fieldName = field.getName(); + // Skip all fields that aren't in a format like "FOO_BAR_FIELD_NUMBER" + if (!fieldName.endsWith(FIELD_NUMBER_NAME_SUFFIX)) { + continue; + } + + // For "FOO_BAR_FIELD_NUMBER" his would be "FOO_BAR" + String upperUnderscore = + fieldName.substring(0, fieldName.length() - FIELD_NUMBER_NAME_SUFFIX.length()); + + // For "FOO_BAR_FIELD_NUMBER" his would be "FooBar" + String upperCamelCaseName = upperUnderscoreToUpperCamel(upperUnderscore); + + // Try to reflectively get the value and toString() the field as if it were optional. This + // only works if the method names have not be proguarded out or renamed. + Method getMethod = nameToNoArgMethod.get("get" + upperCamelCaseName); + Method hasMethod = nameToNoArgMethod.get("has" + upperCamelCaseName); + if (getMethod != null && hasMethod != null) { + if ((Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite)) { + printField( + buffer, + indent, + upperUnderscore.toLowerCase(), + GeneratedMessageLite.invokeOrDie(getMethod, messageLite)); + } + continue; + } + + // Try to reflectively get the value and toString() the field as if it were repeated. This + // only works if the method names have not be proguarded out or renamed. + Method listMethod = nameToNoArgMethod.get("get" + upperCamelCaseName + "List"); + if (listMethod != null) { + printField( + buffer, + indent, + upperUnderscore.toLowerCase(), + GeneratedMessageLite.invokeOrDie(listMethod, messageLite)); + continue; + } + } + + if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) { + Iterator> iter = + ((GeneratedMessageLite.ExtendableMessage) messageLite).extensions.iterator(); + while (iter.hasNext()) { + Map.Entry entry = iter.next(); + printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue()); + } + } + + if (((GeneratedMessageLite) messageLite).unknownFields != null) { + ((GeneratedMessageLite) messageLite).unknownFields.printWithIndent(buffer, indent); + } + } + + /** + * Formats a text proto field. + * + *

For use by generated code only. + * + * @param buffer the buffer to write to + * @param indent the number of spaces the proto should be indented by + * @param name the field name (in lower underscore case) + * @param object the object value of the field + */ + static final void printField(StringBuilder buffer, int indent, String name, Object object) { + if (object instanceof List) { + List list = (List) object; + for (Object entry : list) { + printField(buffer, indent, name, entry); + } + return; + } + + buffer.append('\n'); + for (int i = 0; i < indent; i++) { + buffer.append(' '); + } + buffer.append(name); + + if (object instanceof String) { + buffer.append(": \"").append(TextFormatEscaper.escapeText((String) object)).append('"'); + } else if (object instanceof ByteString) { + buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString) object)).append('"'); + } else if (object instanceof GeneratedMessageLite) { + buffer.append(" {"); + reflectivePrintWithIndent((GeneratedMessageLite) object, buffer, indent + 2); + buffer.append("\n"); + for (int i = 0; i < indent; i++) { + buffer.append(' '); + } + buffer.append("}"); + } else { + buffer.append(": ").append(object.toString()); + } + } + + /** + * A Guava-less implementation of: + * {@code CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, upperUnderscore)} + */ + private static String upperUnderscoreToUpperCamel(String upperUnderscore) { + String upperCamelCaseName = ""; + boolean nextCharacterShouldBeUpper = true; + for (int i = 0; i < upperUnderscore.length(); i++) { + char ch = upperUnderscore.charAt(i); + if (ch == '_') { + nextCharacterShouldBeUpper = true; + } else if (nextCharacterShouldBeUpper){ + upperCamelCaseName += Character.toUpperCase(ch); + nextCharacterShouldBeUpper = false; + } else { + upperCamelCaseName += Character.toLowerCase(ch); + } + } + return upperCamelCaseName; + } +} diff --git a/java/core/src/main/java/com/google/protobuf/NioByteString.java b/java/core/src/main/java/com/google/protobuf/NioByteString.java index f71e41b2..6163c7b1 100644 --- a/java/core/src/main/java/com/google/protobuf/NioByteString.java +++ b/java/core/src/main/java/com/google/protobuf/NioByteString.java @@ -30,15 +30,14 @@ package com.google.protobuf; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.InvalidMarkException; -import java.nio.channels.Channels; import java.nio.charset.Charset; import java.util.Collections; import java.util.List; @@ -54,7 +53,7 @@ final class NioByteString extends ByteString.LeafByteString { throw new NullPointerException("buffer"); } - this.buffer = buffer.slice(); + this.buffer = buffer.slice().order(ByteOrder.nativeOrder()); } // ================================================================= @@ -119,7 +118,7 @@ final class NioByteString extends ByteString.LeafByteString { @Override public void writeTo(OutputStream out) throws IOException { - writeToInternal(out, buffer.position(), buffer.remaining()); + out.write(toByteArray()); } @Override @@ -137,14 +136,12 @@ final class NioByteString extends ByteString.LeafByteString { return; } - // Slow path - if (out instanceof FileOutputStream || numberToWrite >= 8192) { - // Use a channel to write out the ByteBuffer. - Channels.newChannel(out).write(slice(sourceOffset, sourceOffset + numberToWrite)); - } else { - // Just copy the data to an array and write it. - out.write(toByteArray()); - } + ByteBufferWriter.write(slice(sourceOffset, sourceOffset + numberToWrite), out); + } + + @Override + void writeTo(ByteOutput output) throws IOException { + output.writeLazy(buffer.slice()); } @Override @@ -159,46 +156,30 @@ final class NioByteString extends ByteString.LeafByteString { @Override protected String toStringInternal(Charset charset) { - byte[] bytes; - int offset; + final byte[] bytes; + final int offset; + final int length; if (buffer.hasArray()) { bytes = buffer.array(); offset = buffer.arrayOffset() + buffer.position(); + length = buffer.remaining(); } else { + // TODO(nathanmittler): Can we optimize this? bytes = toByteArray(); offset = 0; + length = bytes.length; } - return new String(bytes, offset, size(), charset); + return new String(bytes, offset, length, charset); } @Override public boolean isValidUtf8() { - // TODO(nathanmittler): add a ByteBuffer fork for Utf8.isValidUtf8 to avoid the copy - byte[] bytes; - int startIndex; - if (buffer.hasArray()) { - bytes = buffer.array(); - startIndex = buffer.arrayOffset() + buffer.position(); - } else { - bytes = toByteArray(); - startIndex = 0; - } - return Utf8.isValidUtf8(bytes, startIndex, startIndex + size()); + return Utf8.isValidUtf8(buffer); } @Override protected int partialIsValidUtf8(int state, int offset, int length) { - // TODO(nathanmittler): TODO add a ByteBuffer fork for Utf8.partialIsValidUtf8 to avoid the copy - byte[] bytes; - int startIndex; - if (buffer.hasArray()) { - bytes = buffer.array(); - startIndex = buffer.arrayOffset() + buffer.position(); - } else { - bytes = toByteArray(); - startIndex = 0; - } - return Utf8.partialIsValidUtf8(state, bytes, startIndex, startIndex + size()); + return Utf8.partialIsValidUtf8(state, buffer, offset, offset + length); } @Override diff --git a/java/core/src/main/java/com/google/protobuf/Parser.java b/java/core/src/main/java/com/google/protobuf/Parser.java index 3fa11c3b..6db69247 100644 --- a/java/core/src/main/java/com/google/protobuf/Parser.java +++ b/java/core/src/main/java/com/google/protobuf/Parser.java @@ -30,7 +30,6 @@ package com.google.protobuf; -import java.io.IOException; import java.io.InputStream; /** diff --git a/java/core/src/main/java/com/google/protobuf/RopeByteString.java b/java/core/src/main/java/com/google/protobuf/RopeByteString.java index 8badfabd..3f3e9bd1 100644 --- a/java/core/src/main/java/com/google/protobuf/RopeByteString.java +++ b/java/core/src/main/java/com/google/protobuf/RopeByteString.java @@ -48,10 +48,11 @@ import java.util.Stack; /** * Class to represent {@code ByteStrings} formed by concatenation of other * ByteStrings, without copying the data in the pieces. The concatenation is - * represented as a tree whose leaf nodes are each a {@link LiteralByteString}. + * represented as a tree whose leaf nodes are each a + * {@link com.google.protobuf.ByteString.LeafByteString}. * *

Most of the operation here is inspired by the now-famous paper + * href="https://web.archive.org/web/20060202015456/http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf"> * BAP95 Ropes: an Alternative to Strings hans-j. boehm, russ atkinson and * michael plass * @@ -139,8 +140,9 @@ final class RopeByteString extends ByteString { /** * Concatenate the given strings while performing various optimizations to * slow the growth rate of tree depth and tree node count. The result is - * either a {@link LiteralByteString} or a {@link RopeByteString} - * depending on which optimizations, if any, were applied. + * either a {@link com.google.protobuf.ByteString.LeafByteString} or a + * {@link RopeByteString} depending on which optimizations, if any, were + * applied. * *

Small pieces of length less than {@link * ByteString#CONCATENATE_BY_COPY_SIZE} may be copied by value here, as in @@ -294,8 +296,7 @@ final class RopeByteString extends ByteString { * *

Substrings of {@code length < 2} should result in at most a single * recursive call chain, terminating at a leaf node. Thus the result will be a - * {@link LiteralByteString}. {@link #RopeByteString(ByteString, - * ByteString)}. + * {@link com.google.protobuf.ByteString.LeafByteString}. * * @param beginIndex start at this index * @param endIndex the last character is the one before this index @@ -368,7 +369,7 @@ final class RopeByteString extends ByteString { @Override public List asReadOnlyByteBufferList() { - // Walk through the list of LiteralByteString's that make up this + // Walk through the list of LeafByteString's that make up this // rope, and add each one as a read-only ByteBuffer. List result = new ArrayList(); PieceIterator pieces = new PieceIterator(this); @@ -399,6 +400,12 @@ final class RopeByteString extends ByteString { } } + @Override + void writeTo(ByteOutput output) throws IOException { + left.writeTo(output); + right.writeTo(output); + } + @Override protected String toStringInternal(Charset charset) { return new String(toByteArray(), charset); @@ -709,9 +716,10 @@ final class RopeByteString extends ByteString { } /** - * Returns the next item and advances one {@code LiteralByteString}. + * Returns the next item and advances one + * {@link com.google.protobuf.ByteString.LeafByteString}. * - * @return next non-empty LiteralByteString or {@code null} + * @return next non-empty LeafByteString or {@code null} */ @Override public LeafByteString next() { diff --git a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java index 0674d2e2..dff19328 100644 --- a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java +++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java @@ -35,12 +35,12 @@ import java.util.AbstractSet; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.TreeMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.SortedMap; +import java.util.TreeMap; /** * A custom map implementation from FieldDescriptor to Object optimized to diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java index c99b5285..edf114fa 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java @@ -425,7 +425,7 @@ public final class TextFormat { case STRING: generator.print("\""); generator.print(escapeNonAscii - ? escapeText((String) value) + ? TextFormatEscaper.escapeText((String) value) : escapeDoubleQuotesAndBackslashes((String) value) .replace("\n", "\\n")); generator.print("\""); @@ -661,6 +661,14 @@ public final class TextFormat { nextToken(); } + int getLine() { + return line; + } + + int getColumn() { + return column; + } + /** Are we at the end of the input? */ public boolean atEnd() { return currentToken.length() == 0; @@ -1074,7 +1082,7 @@ public final class TextFormat { private ParseException floatParseException(final NumberFormatException e) { return parseException("Couldn't parse number: " + e.getMessage()); } - + /** * Returns a {@link UnknownFieldParseException} with the line and column * numbers of the previous token in the description, and the unknown field @@ -1133,7 +1141,7 @@ public final class TextFormat { return column; } } - + /** * Thrown when encountering an unknown field while parsing * a text format message. @@ -1257,11 +1265,14 @@ public final class TextFormat { private final boolean allowUnknownFields; private final SingularOverwritePolicy singularOverwritePolicy; + private TextFormatParseInfoTree.Builder parseInfoTreeBuilder; - private Parser(boolean allowUnknownFields, - SingularOverwritePolicy singularOverwritePolicy) { + private Parser( + boolean allowUnknownFields, SingularOverwritePolicy singularOverwritePolicy, + TextFormatParseInfoTree.Builder parseInfoTreeBuilder) { this.allowUnknownFields = allowUnknownFields; this.singularOverwritePolicy = singularOverwritePolicy; + this.parseInfoTreeBuilder = parseInfoTreeBuilder; } /** @@ -1278,6 +1289,7 @@ public final class TextFormat { private boolean allowUnknownFields = false; private SingularOverwritePolicy singularOverwritePolicy = SingularOverwritePolicy.ALLOW_SINGULAR_OVERWRITES; + private TextFormatParseInfoTree.Builder parseInfoTreeBuilder = null; /** @@ -1288,8 +1300,15 @@ public final class TextFormat { return this; } + public Builder setParseInfoTreeBuilder( + TextFormatParseInfoTree.Builder parseInfoTreeBuilder) { + this.parseInfoTreeBuilder = parseInfoTreeBuilder; + return this; + } + public Parser build() { - return new Parser(allowUnknownFields, singularOverwritePolicy); + return new Parser( + allowUnknownFields, singularOverwritePolicy, parseInfoTreeBuilder); } } @@ -1380,7 +1399,21 @@ public final class TextFormat { final ExtensionRegistry extensionRegistry, final MessageReflection.MergeTarget target) throws ParseException { + mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder); + } + + /** + * Parse a single field from {@code tokenizer} and merge it into + * {@code builder}. + */ + private void mergeField(final Tokenizer tokenizer, + final ExtensionRegistry extensionRegistry, + final MessageReflection.MergeTarget target, + TextFormatParseInfoTree.Builder parseTreeBuilder) + throws ParseException { FieldDescriptor field = null; + int startLine = tokenizer.getLine(); + int startColumn = tokenizer.getColumn(); final Descriptor type = target.getDescriptorForType(); ExtensionRegistry.ExtensionInfo extension = null; @@ -1472,14 +1505,51 @@ public final class TextFormat { // Handle potential ':'. if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { tokenizer.tryConsume(":"); // optional + if (parseTreeBuilder != null) { + TextFormatParseInfoTree.Builder childParseTreeBuilder = + parseTreeBuilder.getBuilderForSubMessageField(field); + consumeFieldValues(tokenizer, extensionRegistry, target, field, extension, + childParseTreeBuilder); + } else { + consumeFieldValues(tokenizer, extensionRegistry, target, field, extension, + parseTreeBuilder); + } } else { tokenizer.consume(":"); // required + consumeFieldValues( + tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder); } + + if (parseTreeBuilder != null) { + parseTreeBuilder.setLocation( + field, TextFormatParseLocation.create(startLine, startColumn)); + } + + // For historical reasons, fields may optionally be separated by commas or + // semicolons. + if (!tokenizer.tryConsume(";")) { + tokenizer.tryConsume(","); + } + } + + /** + * Parse a one or more field values from {@code tokenizer} and merge it into + * {@code builder}. + */ + private void consumeFieldValues( + final Tokenizer tokenizer, + final ExtensionRegistry extensionRegistry, + final MessageReflection.MergeTarget target, + final FieldDescriptor field, + final ExtensionRegistry.ExtensionInfo extension, + final TextFormatParseInfoTree.Builder parseTreeBuilder) + throws ParseException { // Support specifying repeated field values as a comma-separated list. // Ex."foo: [1, 2, 3]" if (field.isRepeated() && tokenizer.tryConsume("[")) { while (true) { - consumeFieldValue(tokenizer, extensionRegistry, target, field, extension); + consumeFieldValue(tokenizer, extensionRegistry, target, field, extension, + parseTreeBuilder); if (tokenizer.tryConsume("]")) { // End of list. break; @@ -1487,13 +1557,8 @@ public final class TextFormat { tokenizer.consume(","); } } else { - consumeFieldValue(tokenizer, extensionRegistry, target, field, extension); - } - - // For historical reasons, fields may optionally be separated by commas or - // semicolons. - if (!tokenizer.tryConsume(";")) { - tokenizer.tryConsume(","); + consumeFieldValue( + tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder); } } @@ -1506,7 +1571,8 @@ public final class TextFormat { final ExtensionRegistry extensionRegistry, final MessageReflection.MergeTarget target, final FieldDescriptor field, - final ExtensionRegistry.ExtensionInfo extension) + final ExtensionRegistry.ExtensionInfo extension, + final TextFormatParseInfoTree.Builder parseTreeBuilder) throws ParseException { Object value = null; @@ -1528,7 +1594,7 @@ public final class TextFormat { throw tokenizer.parseException( "Expected \"" + endToken + "\"."); } - mergeField(tokenizer, extensionRegistry, subField); + mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder); } value = subField.finish(); @@ -1704,11 +1770,6 @@ public final class TextFormat { // Some of these methods are package-private because Descriptors.java uses // them. - private interface ByteSequence { - int size(); - byte byteAt(int offset); - } - /** * Escapes bytes in the format used in protocol buffer text format, which * is the same as the format used for C string literals. All bytes @@ -1717,74 +1778,15 @@ public final class TextFormat { * which no defined short-hand escape sequence is defined will be escaped * using 3-digit octal sequences. */ - public static String escapeBytes(final ByteSequence input) { - final StringBuilder builder = new StringBuilder(input.size()); - for (int i = 0; i < input.size(); i++) { - final byte b = input.byteAt(i); - switch (b) { - // Java does not recognize \a or \v, apparently. - case 0x07: builder.append("\\a"); break; - case '\b': builder.append("\\b"); break; - case '\f': builder.append("\\f"); break; - case '\n': builder.append("\\n"); break; - case '\r': builder.append("\\r"); break; - case '\t': builder.append("\\t"); break; - case 0x0b: builder.append("\\v"); break; - case '\\': builder.append("\\\\"); break; - case '\'': builder.append("\\\'"); break; - case '"' : builder.append("\\\""); break; - default: - // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are - // printable. Other byte values must be escaped. - if (b >= 0x20 && b <= 0x7e) { - builder.append((char) b); - } else { - builder.append('\\'); - builder.append((char) ('0' + ((b >>> 6) & 3))); - builder.append((char) ('0' + ((b >>> 3) & 7))); - builder.append((char) ('0' + (b & 7))); - } - break; - } - } - return builder.toString(); - } - - /** - * Escapes bytes in the format used in protocol buffer text format, which - * is the same as the format used for C string literals. All bytes - * that are not printable 7-bit ASCII characters are escaped, as well as - * backslash, single-quote, and double-quote characters. Characters for - * which no defined short-hand escape sequence is defined will be escaped - * using 3-digit octal sequences. - */ - public static String escapeBytes(final ByteString input) { - return escapeBytes(new ByteSequence() { - @Override - public int size() { - return input.size(); - } - @Override - public byte byteAt(int offset) { - return input.byteAt(offset); - } - }); + public static String escapeBytes(ByteString input) { + return TextFormatEscaper.escapeBytes(input); } /** * Like {@link #escapeBytes(ByteString)}, but used for byte array. */ - public static String escapeBytes(final byte[] input) { - return escapeBytes(new ByteSequence() { - @Override - public int size() { - return input.length; - } - @Override - public byte byteAt(int offset) { - return input[offset]; - } - }); + public static String escapeBytes(byte[] input) { + return TextFormatEscaper.escapeBytes(input); } /** @@ -1868,7 +1870,9 @@ public final class TextFormat { } } - return ByteString.copyFrom(result, 0, pos); + return result.length == pos + ? ByteString.wrap(result) // This reference has not been out of our control. + : ByteString.copyFrom(result, 0, pos); } /** @@ -1896,7 +1900,7 @@ public final class TextFormat { * Escape double quotes and backslashes in a String for unicode output of a message. */ public static String escapeDoubleQuotesAndBackslashes(final String input) { - return input.replace("\\", "\\\\").replace("\"", "\\\""); + return TextFormatEscaper.escapeDoubleQuotesAndBackslashes(input); } /** diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java index e69de29b..da9ceadd 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormatEscaper.java @@ -0,0 +1,137 @@ +// 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. + +package com.google.protobuf; + +/** + * Provide text format escaping support for proto2 instances. + */ +final class TextFormatEscaper { + private TextFormatEscaper() {} + + private interface ByteSequence { + int size(); + byte byteAt(int offset); + } + + /** + * Escapes bytes in the format used in protocol buffer text format, which + * is the same as the format used for C string literals. All bytes + * that are not printable 7-bit ASCII characters are escaped, as well as + * backslash, single-quote, and double-quote characters. Characters for + * which no defined short-hand escape sequence is defined will be escaped + * using 3-digit octal sequences. + */ + static String escapeBytes(final ByteSequence input) { + final StringBuilder builder = new StringBuilder(input.size()); + for (int i = 0; i < input.size(); i++) { + final byte b = input.byteAt(i); + switch (b) { + // Java does not recognize \a or \v, apparently. + case 0x07: builder.append("\\a"); break; + case '\b': builder.append("\\b"); break; + case '\f': builder.append("\\f"); break; + case '\n': builder.append("\\n"); break; + case '\r': builder.append("\\r"); break; + case '\t': builder.append("\\t"); break; + case 0x0b: builder.append("\\v"); break; + case '\\': builder.append("\\\\"); break; + case '\'': builder.append("\\\'"); break; + case '"' : builder.append("\\\""); break; + default: + // Only ASCII characters between 0x20 (space) and 0x7e (tilde) are + // printable. Other byte values must be escaped. + if (b >= 0x20 && b <= 0x7e) { + builder.append((char) b); + } else { + builder.append('\\'); + builder.append((char) ('0' + ((b >>> 6) & 3))); + builder.append((char) ('0' + ((b >>> 3) & 7))); + builder.append((char) ('0' + (b & 7))); + } + break; + } + } + return builder.toString(); + } + + /** + * Escapes bytes in the format used in protocol buffer text format, which + * is the same as the format used for C string literals. All bytes + * that are not printable 7-bit ASCII characters are escaped, as well as + * backslash, single-quote, and double-quote characters. Characters for + * which no defined short-hand escape sequence is defined will be escaped + * using 3-digit octal sequences. + */ + static String escapeBytes(final ByteString input) { + return escapeBytes(new ByteSequence() { + @Override + public int size() { + return input.size(); + } + @Override + public byte byteAt(int offset) { + return input.byteAt(offset); + } + }); + } + + /** + * Like {@link #escapeBytes(ByteString)}, but used for byte array. + */ + static String escapeBytes(final byte[] input) { + return escapeBytes(new ByteSequence() { + @Override + public int size() { + return input.length; + } + @Override + public byte byteAt(int offset) { + return input[offset]; + } + }); + } + + /** + * Like {@link #escapeBytes(ByteString)}, but escapes a text string. + * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped + * individually as a 3-digit octal escape. Yes, it's weird. + */ + static String escapeText(final String input) { + return escapeBytes(ByteString.copyFromUtf8(input)); + } + + /** + * Escape double quotes and backslashes in a String for unicode output of a message. + */ + static String escapeDoubleQuotesAndBackslashes(final String input) { + return input.replace("\\", "\\\\").replace("\"", "\\\""); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java new file mode 100644 index 00000000..2ecf912e --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseInfoTree.java @@ -0,0 +1,225 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.FieldDescriptor; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + + +/** + * Data structure which is populated with the locations of each field value parsed from the text. + * + *

The locations of primary fields values are retrieved by {@code getLocation} or + * {@code getLocations}. The locations of sub message values are within nested + * {@code TextFormatParseInfoTree}s and are retrieve by {@getNestedTree} or {code @getNestedTrees}. + * + *

The {@code TextFormatParseInfoTree} is created by a Builder. + */ +public class TextFormatParseInfoTree { + + // Defines a mapping between each field's descriptor to the list of locations where + // its value(s) were was encountered. + private Map> locationsFromField; + + // Defines a mapping between a field's descriptor to a list of TextFormatParseInfoTrees for + // sub message location information. + Map> subtreesFromField; + + /** + * Construct a {@code TextFormatParseInfoTree}. + * + * @param locationsFromField a map of fields to location in the source code + * @param subtreeBuildersFromField a map of fields to parse tree location information builders + */ + private TextFormatParseInfoTree( + Map> locationsFromField, + Map> subtreeBuildersFromField) { + + // The maps are unmodifiable. The values in the maps are unmodifiable. + Map> locs = + new HashMap>(); + for (Entry> kv : locationsFromField.entrySet()) { + locs.put(kv.getKey(), Collections.unmodifiableList(kv.getValue())); + } + this.locationsFromField = Collections.unmodifiableMap(locs); + + Map> subs = + new HashMap>(); + for (Entry> kv : subtreeBuildersFromField.entrySet()) { + List submessagesOfField = new ArrayList(); + for (Builder subBuilder : kv.getValue()) { + submessagesOfField.add(subBuilder.build()); + } + subs.put(kv.getKey(), Collections.unmodifiableList(submessagesOfField)); + } + this.subtreesFromField = Collections.unmodifiableMap(subs); + } + + /** + * Retrieve all the locations of a field. + * + * @param fieldDescriptor the the @{link FieldDescriptor} of the desired field + * @return a list of the locations of values of the field. If there are not values + * or the field doesn't exist, an empty list is returned. + */ + public List getLocations(final FieldDescriptor fieldDescriptor) { + List result = locationsFromField.get(fieldDescriptor); + return (result == null) ? Collections.emptyList() : result; + } + + /** + * Get the location in the source of a field's value. + * + *

Returns the {@link TextFormatParseLocation} for index-th value of the field in the parsed + * text. + * + * @param fieldDescriptor the @{link FieldDescriptor} of the desired field + * @param index the index of the value. + * @return the {@link TextFormatParseLocation} of the value + * @throws IllegalArgumentException index is out of range + */ + public TextFormatParseLocation getLocation(final FieldDescriptor fieldDescriptor, int index) { + return getFromList(getLocations(fieldDescriptor), index, fieldDescriptor); + } + + /** + * Retrieve a list of all the location information trees for a sub message field. + * + * @param fieldDescriptor the @{link FieldDescriptor} of the desired field + * @return A list of {@link TextFormatParseInfoTree} + */ + public List getNestedTrees(final FieldDescriptor fieldDescriptor) { + List result = subtreesFromField.get(fieldDescriptor); + return result == null ? Collections.emptyList() : result; + } + + /** + * Returns the parse info tree for the given field, which must be a message type. + * + * @param fieldDescriptor the @{link FieldDescriptor} of the desired sub message + * @param index the index of message value. + * @return the {@code ParseInfoTree} of the message value. {@code null} is returned if the field + * doesn't exist or the index is out of range. + * @throws IllegalArgumentException if index is out of range + */ + public TextFormatParseInfoTree getNestedTree(final FieldDescriptor fieldDescriptor, int index) { + return getFromList(getNestedTrees(fieldDescriptor), index, fieldDescriptor); + } + + /** + * Create a builder for a {@code ParseInfoTree}. + * + * @return the builder + */ + public static Builder builder() { + return new Builder(); + } + + private static T getFromList(List list, int index, FieldDescriptor fieldDescriptor) { + if (index >= list.size() || index < 0) { + throw new IllegalArgumentException(String.format("Illegal index field: %s, index %d", + fieldDescriptor == null ? "" : fieldDescriptor.getName(), index)); + } + return list.get(index); + } + + /** + * Builder for a {@link TextFormatParseInfoTree}. + */ + public static class Builder { + + private Map> locationsFromField; + + // Defines a mapping between a field's descriptor to a list of ParseInfoTrees builders for + // sub message location information. + private Map> subtreeBuildersFromField; + + /** + * Create a root level {@ParseInfoTree} builder. + */ + private Builder() { + locationsFromField = new HashMap>(); + subtreeBuildersFromField = new HashMap>(); + } + + /** + * Record the starting location of a single value for a field. + * + * @param fieldDescriptor the field + * @param location source code location information + */ + public Builder setLocation( + final FieldDescriptor fieldDescriptor, TextFormatParseLocation location) { + List fieldLocations = locationsFromField.get(fieldDescriptor); + if (fieldLocations == null) { + fieldLocations = new ArrayList(); + locationsFromField.put(fieldDescriptor, fieldLocations); + } + fieldLocations.add(location); + return this; + } + + /** + * Set for a sub message. + * + *

A new builder is created for a sub message. The builder that is returned is a new builder. + * The return is not the invoked {@code builder.getBuilderForSubMessageField}. + * + * @param fieldDescriptor the field whose value is the submessage + * @return a new Builder for the sub message + */ + public Builder getBuilderForSubMessageField(final FieldDescriptor fieldDescriptor) { + List submessageBuilders = subtreeBuildersFromField.get(fieldDescriptor); + if (submessageBuilders == null) { + submessageBuilders = new ArrayList(); + subtreeBuildersFromField.put(fieldDescriptor, submessageBuilders); + } + Builder subtreeBuilder = new Builder(); + submessageBuilders.add(subtreeBuilder); + return subtreeBuilder; + } + + /** + * Build the {@code TextFormatParseInfoTree}. + * + * @return the {@code TextFormatParseInfoTree} + */ + public TextFormatParseInfoTree build() { + return new TextFormatParseInfoTree(locationsFromField, subtreeBuildersFromField); + } + } +} diff --git a/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java new file mode 100644 index 00000000..cce286e1 --- /dev/null +++ b/java/core/src/main/java/com/google/protobuf/TextFormatParseLocation.java @@ -0,0 +1,104 @@ +// 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. + +package com.google.protobuf; + +import java.util.Arrays; + +/** + * A location in the source code. + * + *

A location is the starting line number and starting column number. + */ +public final class TextFormatParseLocation { + + /** + * The empty location. + */ + public static final TextFormatParseLocation EMPTY = new TextFormatParseLocation(-1, -1); + + /** + * Create a location. + * + * @param line the starting line number + * @param column the starting column number + * @return a {@code ParseLocation} + */ + static TextFormatParseLocation create(int line, int column) { + if (line == -1 && column == -1) { + return EMPTY; + } + if (line < 0 || column < 0) { + throw new IllegalArgumentException( + String.format("line and column values must be >= 0: line %d, column: %d", line, column)); + } + return new TextFormatParseLocation(line, column); + } + + private final int line; + private final int column; + + private TextFormatParseLocation(int line, int column) { + this.line = line; + this.column = column; + } + + public int getLine() { + return line; + } + + public int getColumn() { + return column; + } + + @Override + public String toString() { + return String.format("ParseLocation{line=%d, column=%d}", line, column); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof TextFormatParseLocation)) { + return false; + } + TextFormatParseLocation that = (TextFormatParseLocation) o; + return (this.line == that.getLine()) + && (this.column == that.getColumn()); + } + + @Override + public int hashCode() { + int[] values = {line, column}; + return Arrays.hashCode(values); + } +} diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java index 435ad4d4..9500f905 100644 --- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSetLite.java @@ -61,15 +61,6 @@ public final class UnknownFieldSetLite { public static UnknownFieldSetLite getDefaultInstance() { return DEFAULT_INSTANCE; } - - /** - * Returns an empty {@code UnknownFieldSetLite.Builder}. - * - *

For use by generated code only. - */ - public static Builder newBuilder() { - return new Builder(); - } /** * Returns a new mutable instance. @@ -262,6 +253,21 @@ public final class UnknownFieldSetLite { return hashCode; } + /** + * Prints a String representation of the unknown field set. + * + *

For use by generated code only. + * + * @param buffer the buffer to write to + * @param indent the number of spaces the fields should be indented by + */ + final void printWithIndent(StringBuilder buffer, int indent) { + for (int i = 0; i < count; i++) { + int fieldNumber = WireFormat.getTagFieldNumber(tags[i]); + MessageLiteToString.printField(buffer, indent, String.valueOf(fieldNumber), objects[i]); + } + } + private void storeField(int tag, Object value) { ensureCapacity(); @@ -369,90 +375,4 @@ public final class UnknownFieldSetLite { } return this; } - - /** - * Builder for {@link UnknownFieldSetLite}s. - * - *

Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}. - * - *

For use by generated code only. - */ - // TODO(dweis): Update the mutable API to no longer need this builder and delete. - public static final class Builder { - - private UnknownFieldSetLite set; - - private Builder() { - this.set = null; - } - - /** - * Ensures internal state is initialized for use. - */ - private void ensureNotBuilt() { - if (set == null) { - set = new UnknownFieldSetLite(); - } - - set.checkMutable(); - } - - /** - * Parse a single field from {@code input} and merge it into this set. - * - *

For use by generated code only. - * - * @param tag The field's tag number, which was already parsed. - * @return {@code false} if the tag is an end group tag. - */ - boolean mergeFieldFrom(final int tag, final CodedInputStream input) throws IOException { - ensureNotBuilt(); - return set.mergeFieldFrom(tag, input); - } - - /** - * Convenience method for merging a new field containing a single varint - * value. This is used in particular when an unknown enum value is - * encountered. - * - *

For use by generated code only. - */ - Builder mergeVarintField(int fieldNumber, int value) { - ensureNotBuilt(); - set.mergeVarintField(fieldNumber, value); - return this; - } - - /** - * Convenience method for merging a length-delimited field. - * - *

For use by generated code only. - */ - public Builder mergeLengthDelimitedField(final int fieldNumber, final ByteString value) { - ensureNotBuilt(); - set.mergeLengthDelimitedField(fieldNumber, value); - return this; - } - - /** - * Build the {@link UnknownFieldSetLite} and return it. - * - *

Once {@code build()} has been called, the {@code Builder} will no - * longer be usable. Calling any method after {@code build()} will result - * in undefined behavior and can cause an - * {@code UnsupportedOperationException} to be thrown. - * - *

For use by generated code only. - */ - public UnknownFieldSetLite build() { - if (set == null) { - return DEFAULT_INSTANCE; - } - - set.checkMutable(); - set.makeImmutable(); - - return set; - } - } } diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java index f443ee39..0fbf4d40 100644 --- a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java +++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java @@ -30,6 +30,7 @@ package com.google.protobuf; +import java.io.IOException; import java.nio.ByteBuffer; /** @@ -49,8 +50,8 @@ public final class UnsafeByteOperations { /** * An unsafe operation that returns a {@link ByteString} that is backed by the provided buffer. * - * @param buffer the Java NIO buffer to be wrapped. - * @return a {@link ByteString} backed by the provided buffer. + * @param buffer the Java NIO buffer to be wrapped + * @return a {@link ByteString} backed by the provided buffer */ public static ByteString unsafeWrap(ByteBuffer buffer) { if (buffer.hasArray()) { @@ -60,4 +61,24 @@ public final class UnsafeByteOperations { return new NioByteString(buffer); } } + + /** + * Writes the given {@link ByteString} to the provided {@link ByteOutput}. Calling this method may + * result in multiple operations on the target {@link ByteOutput} + * (i.e. for roped {@link ByteString}s). + * + *

This method exposes the internal backing buffer(s) of the {@link ByteString} to the {@link + * ByteOutput} in order to avoid additional copying overhead. It would be possible for a malicious + * {@link ByteOutput} to corrupt the {@link ByteString}. Use with caution! + * + *

NOTE: The {@link ByteOutput} MUST NOT modify the provided buffers. Doing + * so may result in corrupted data, which would be difficult to debug. + * + * @param bytes the {@link ByteString} to be written + * @param output the output to receive the bytes + * @throws IOException if an I/O error occurs + */ + public static void unsafeWriteTo(ByteString bytes, ByteOutput output) throws IOException { + bytes.writeTo(output); + } } diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java index 48c7e9e6..308c69e9 100644 --- a/java/core/src/main/java/com/google/protobuf/Utf8.java +++ b/java/core/src/main/java/com/google/protobuf/Utf8.java @@ -30,6 +30,19 @@ package com.google.protobuf; +import static java.lang.Character.MAX_SURROGATE; +import static java.lang.Character.MIN_SURROGATE; +import static java.lang.Character.isSurrogatePair; +import static java.lang.Character.toCodePoint; + +import java.lang.reflect.Field; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import java.util.logging.Level; +import java.util.logging.Logger; + /** * A set of low-level, high-performance static utility methods related * to the UTF-8 character encoding. This class has no dependencies @@ -64,9 +77,24 @@ package com.google.protobuf; * * @author martinrb@google.com (Martin Buchholz) */ +// TODO(nathanmittler): Copy changes in this class back to Guava final class Utf8 { - private Utf8() {} - + private static final Logger logger = Logger.getLogger(Utf8.class.getName()); + + /** + * UTF-8 is a runtime hot spot so we attempt to provide heavily optimized implementations + * depending on what is available on the platform. The processor is the platform-optimized + * delegate for which all methods are delegated directly to. + */ + private static final Processor processor = + UnsafeProcessor.isAvailable() ? new UnsafeProcessor() : new SafeProcessor(); + + /** + * A mask used when performing unsafe reads to determine if a long value contains any non-ASCII + * characters (i.e. any byte >= 0x80). + */ + private static final long ASCII_MASK_LONG = 0x8080808080808080L; + /** * Maximum number of bytes per Java UTF-16 char in UTF-8. * @see java.nio.charset.CharsetEncoder#maxBytesPerChar() @@ -85,6 +113,18 @@ final class Utf8 { */ public static final int MALFORMED = -1; + /** + * Used by {@code Unsafe} UTF-8 string validation logic to determine the minimum string length + * above which to employ an optimized algorithm for counting ASCII characters. The reason for this + * threshold is that for small strings, the optimization may not be beneficial or may even + * negatively impact performance since it requires additional logic to avoid unaligned reads + * (when calling {@code Unsafe.getLong}). This threshold guarantees that even if the initial + * offset is unaligned, we're guaranteed to make at least one call to {@code Unsafe.getLong()} + * which provides a performance improvement that entirely subsumes the cost of the additional + * logic. + */ + private static final int UNSAFE_COUNT_ASCII_THRESHOLD = 16; + // Other state values include the partial bytes of the incomplete // character to be decoded in the simplest way: we pack the bytes // into the state int in little-endian order. For example: @@ -112,7 +152,7 @@ final class Utf8 { * isValidUtf8(bytes, 0, bytes.length)}. */ public static boolean isValidUtf8(byte[] bytes) { - return isValidUtf8(bytes, 0, bytes.length); + return processor.isValidUtf8(bytes, 0, bytes.length); } /** @@ -125,7 +165,7 @@ final class Utf8 { * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}. */ public static boolean isValidUtf8(byte[] bytes, int index, int limit) { - return partialIsValidUtf8(bytes, index, limit) == COMPLETE; + return processor.isValidUtf8(bytes, index, limit); } /** @@ -146,183 +186,8 @@ final class Utf8 { * decode the character when passed to a subsequent invocation of a * partial decoding method. */ - public static int partialIsValidUtf8( - int state, byte[] bytes, int index, int limit) { - if (state != COMPLETE) { - // The previous decoding operation was incomplete (or malformed). - // We look for a well-formed sequence consisting of bytes from - // the previous decoding operation (stored in state) together - // with bytes from the array slice. - // - // We expect such "straddler characters" to be rare. - - if (index >= limit) { // No bytes? No progress. - return state; - } - int byte1 = (byte) state; - // byte1 is never ASCII. - if (byte1 < (byte) 0xE0) { - // two-byte form - - // Simultaneously checks for illegal trailing-byte in - // leading position and overlong 2-byte form. - if (byte1 < (byte) 0xC2 || - // byte2 trailing-byte test - bytes[index++] > (byte) 0xBF) { - return MALFORMED; - } - } else if (byte1 < (byte) 0xF0) { - // three-byte form - - // Get byte2 from saved state or array - int byte2 = (byte) ~(state >> 8); - if (byte2 == 0) { - byte2 = bytes[index++]; - if (index >= limit) { - return incompleteStateFor(byte1, byte2); - } - } - if (byte2 > (byte) 0xBF || - // overlong? 5 most significant bits must not all be zero - (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) || - // illegal surrogate codepoint? - (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) || - // byte3 trailing-byte test - bytes[index++] > (byte) 0xBF) { - return MALFORMED; - } - } else { - // four-byte form - - // Get byte2 and byte3 from saved state or array - int byte2 = (byte) ~(state >> 8); - int byte3 = 0; - if (byte2 == 0) { - byte2 = bytes[index++]; - if (index >= limit) { - return incompleteStateFor(byte1, byte2); - } - } else { - byte3 = (byte) (state >> 16); - } - if (byte3 == 0) { - byte3 = bytes[index++]; - if (index >= limit) { - return incompleteStateFor(byte1, byte2, byte3); - } - } - - // If we were called with state == MALFORMED, then byte1 is 0xFF, - // which never occurs in well-formed UTF-8, and so we will return - // MALFORMED again below. - - if (byte2 > (byte) 0xBF || - // Check that 1 <= plane <= 16. Tricky optimized form of: - // if (byte1 > (byte) 0xF4 || - // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || - // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) - (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 || - // byte3 trailing-byte test - byte3 > (byte) 0xBF || - // byte4 trailing-byte test - bytes[index++] > (byte) 0xBF) { - return MALFORMED; - } - } - } - - return partialIsValidUtf8(bytes, index, limit); - } - - /** - * Tells whether the given byte array slice is a well-formed, - * malformed, or incomplete UTF-8 byte sequence. The range of bytes - * to be checked extends from index {@code index}, inclusive, to - * {@code limit}, exclusive. - * - *

This is a convenience method, equivalent to a call to {@code - * partialIsValidUtf8(Utf8.COMPLETE, bytes, index, limit)}. - * - * @return {@link #MALFORMED} if the partial byte sequence is - * definitely not well-formed, {@link #COMPLETE} if it is well-formed - * (no additional input needed), or if the byte sequence is - * "incomplete", i.e. apparently terminated in the middle of a character, - * an opaque integer "state" value containing enough information to - * decode the character when passed to a subsequent invocation of a - * partial decoding method. - */ - public static int partialIsValidUtf8( - byte[] bytes, int index, int limit) { - // Optimize for 100% ASCII. - // Hotspot loves small simple top-level loops like this. - while (index < limit && bytes[index] >= 0) { - index++; - } - - return (index >= limit) ? COMPLETE : - partialIsValidUtf8NonAscii(bytes, index, limit); - } - - private static int partialIsValidUtf8NonAscii( - byte[] bytes, int index, int limit) { - for (;;) { - int byte1, byte2; - - // Optimize for interior runs of ASCII bytes. - do { - if (index >= limit) { - return COMPLETE; - } - } while ((byte1 = bytes[index++]) >= 0); - - if (byte1 < (byte) 0xE0) { - // two-byte form - - if (index >= limit) { - return byte1; - } - - // Simultaneously checks for illegal trailing-byte in - // leading position and overlong 2-byte form. - if (byte1 < (byte) 0xC2 || - bytes[index++] > (byte) 0xBF) { - return MALFORMED; - } - } else if (byte1 < (byte) 0xF0) { - // three-byte form - - if (index >= limit - 1) { // incomplete sequence - return incompleteStateFor(bytes, index, limit); - } - if ((byte2 = bytes[index++]) > (byte) 0xBF || - // overlong? 5 most significant bits must not all be zero - (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) || - // check for illegal surrogate codepoints - (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) || - // byte3 trailing-byte test - bytes[index++] > (byte) 0xBF) { - return MALFORMED; - } - } else { - // four-byte form - - if (index >= limit - 2) { // incomplete sequence - return incompleteStateFor(bytes, index, limit); - } - if ((byte2 = bytes[index++]) > (byte) 0xBF || - // Check that 1 <= plane <= 16. Tricky optimized form of: - // if (byte1 > (byte) 0xF4 || - // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || - // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) - (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 || - // byte3 trailing-byte test - bytes[index++] > (byte) 0xBF || - // byte4 trailing-byte test - bytes[index++] > (byte) 0xBF) { - return MALFORMED; - } - } - } + public static int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) { + return processor.partialIsValidUtf8(state, bytes, index, limit); } private static int incompleteStateFor(int byte1) { @@ -352,19 +217,31 @@ final class Utf8 { default: throw new AssertionError(); } } - + + private static int incompleteStateFor( + final ByteBuffer buffer, final int byte1, final int index, final int remaining) { + switch (remaining) { + case 0: + return incompleteStateFor(byte1); + case 1: + return incompleteStateFor(byte1, buffer.get(index)); + case 2: + return incompleteStateFor(byte1, buffer.get(index), buffer.get(index + 1)); + default: + throw new AssertionError(); + } + } // These UTF-8 handling methods are copied from Guava's Utf8 class with a modification to throw // a protocol buffer local exception. This exception is then caught in CodedOutputStream so it can // fallback to more lenient behavior. static class UnpairedSurrogateException extends IllegalArgumentException { - private UnpairedSurrogateException(int index, int length) { super("Unpaired surrogate at index " + index + " of " + length); } } - + /** * Returns the number of bytes in the UTF-8-encoded form of {@code sequence}. For a string, * this method is equivalent to {@code string.getBytes(UTF_8).length}, but is more efficient in @@ -426,56 +303,1381 @@ final class Utf8 { return utf8Length; } - static int encode(CharSequence sequence, byte[] bytes, int offset, int length) { - int utf16Length = sequence.length(); - int j = offset; - int i = 0; - int limit = offset + length; - // Designed to take advantage of - // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination - for (char c; i < utf16Length && i + j < limit && (c = sequence.charAt(i)) < 0x80; i++) { - bytes[j + i] = (byte) c; - } - if (i == utf16Length) { - return j + utf16Length; - } - j += i; - for (char c; i < utf16Length; i++) { - c = sequence.charAt(i); - if (c < 0x80 && j < limit) { - bytes[j++] = (byte) c; - } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes - bytes[j++] = (byte) ((0xF << 6) | (c >>> 6)); - bytes[j++] = (byte) (0x80 | (0x3F & c)); - } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) { - // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes - bytes[j++] = (byte) ((0xF << 5) | (c >>> 12)); - bytes[j++] = (byte) (0x80 | (0x3F & (c >>> 6))); - bytes[j++] = (byte) (0x80 | (0x3F & c)); - } else if (j <= limit - 4) { - // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 bytes - final char low; - if (i + 1 == sequence.length() - || !Character.isSurrogatePair(c, (low = sequence.charAt(++i)))) { - throw new UnpairedSurrogateException((i - 1), utf16Length); - } - int codePoint = Character.toCodePoint(c, low); - bytes[j++] = (byte) ((0xF << 4) | (codePoint >>> 18)); - bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12))); - bytes[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6))); - bytes[j++] = (byte) (0x80 | (0x3F & codePoint)); - } else { - // If we are surrogates and we're not a surrogate pair, always throw an - // IllegalArgumentException instead of an ArrayOutOfBoundsException. - if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) - && (i + 1 == sequence.length() - || !Character.isSurrogatePair(c, sequence.charAt(i + 1)))) { - throw new UnpairedSurrogateException(i, utf16Length); - } - throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j); - } - } - return j; + static int encode(CharSequence in, byte[] out, int offset, int length) { + return processor.encodeUtf8(in, out, offset, length); } // End Guava UTF-8 methods. + + /** + * Determines if the given {@link ByteBuffer} is a valid UTF-8 string. + * + *

Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct) + * and the capabilities of the platform. + * + * @param buffer the buffer to check. + * @see Utf8#isValidUtf8(byte[], int, int) + */ + static boolean isValidUtf8(ByteBuffer buffer) { + return processor.isValidUtf8(buffer, buffer.position(), buffer.remaining()); + } + + /** + * Determines if the given {@link ByteBuffer} is a partially valid UTF-8 string. + * + *

Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct) + * and the capabilities of the platform. + * + * @param buffer the buffer to check. + * @see Utf8#partialIsValidUtf8(int, byte[], int, int) + */ + static int partialIsValidUtf8(int state, ByteBuffer buffer, int index, int limit) { + return processor.partialIsValidUtf8(state, buffer, index, limit); + } + + /** + * Encodes the given characters to the target {@link ByteBuffer} using UTF-8 encoding. + * + *

Selects an optimal algorithm based on the type of {@link ByteBuffer} (i.e. heap or direct) + * and the capabilities of the platform. + * + * @param in the source string to be encoded + * @param out the target buffer to receive the encoded string. + * @see Utf8#encode(CharSequence, byte[], int, int) + */ + static void encodeUtf8(CharSequence in, ByteBuffer out) { + processor.encodeUtf8(in, out); + } + + /** + * Counts (approximately) the number of consecutive ASCII characters in the given buffer. + * The byte order of the {@link ByteBuffer} does not matter, so performance can be improved if + * native byte order is used (i.e. no byte-swapping in {@link ByteBuffer#getLong(int)}). + * + * @param buffer the buffer to be scanned for ASCII chars + * @param index the starting index of the scan + * @param limit the limit within buffer for the scan + * @return the number of ASCII characters found. The stopping position will be at or + * before the first non-ASCII byte. + */ + private static int estimateConsecutiveAscii(ByteBuffer buffer, int index, int limit) { + int i = index; + final int lim = limit - 7; + // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII). + // To speed things up further, we're reading longs instead of bytes so we use a mask to + // determine if any byte in the current long is non-ASCII. + for (; i < lim && (buffer.getLong(i) & ASCII_MASK_LONG) == 0; i += 8) {} + return i - index; + } + + /** + * A processor of UTF-8 strings, providing methods for checking validity and encoding. + */ + // TODO(nathanmittler): Add support for Memory/MemoryBlock on Android. + abstract static class Processor { + /** + * Returns {@code true} if the given byte array slice is a + * well-formed UTF-8 byte sequence. The range of bytes to be + * checked extends from index {@code index}, inclusive, to {@code + * limit}, exclusive. + * + *

This is a convenience method, equivalent to {@code + * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}. + */ + final boolean isValidUtf8(byte[] bytes, int index, int limit) { + return partialIsValidUtf8(COMPLETE, bytes, index, limit) == COMPLETE; + } + + /** + * Tells whether the given byte array slice is a well-formed, + * malformed, or incomplete UTF-8 byte sequence. The range of bytes + * to be checked extends from index {@code index}, inclusive, to + * {@code limit}, exclusive. + * + * @param state either {@link Utf8#COMPLETE} (if this is the initial decoding + * operation) or the value returned from a call to a partial decoding method + * for the previous bytes + * + * @return {@link #MALFORMED} if the partial byte sequence is + * definitely not well-formed, {@link #COMPLETE} if it is well-formed + * (no additional input needed), or if the byte sequence is + * "incomplete", i.e. apparently terminated in the middle of a character, + * an opaque integer "state" value containing enough information to + * decode the character when passed to a subsequent invocation of a + * partial decoding method. + */ + abstract int partialIsValidUtf8(int state, byte[] bytes, int index, int limit); + + /** + * Returns {@code true} if the given portion of the {@link ByteBuffer} is a + * well-formed UTF-8 byte sequence. The range of bytes to be + * checked extends from index {@code index}, inclusive, to {@code + * limit}, exclusive. + * + *

This is a convenience method, equivalent to {@code + * partialIsValidUtf8(bytes, index, limit) == Utf8.COMPLETE}. + */ + final boolean isValidUtf8(ByteBuffer buffer, int index, int limit) { + return partialIsValidUtf8(COMPLETE, buffer, index, limit) == COMPLETE; + } + + /** + * Indicates whether or not the given buffer contains a valid UTF-8 string. + * + * @param buffer the buffer to check. + * @return {@code true} if the given buffer contains a valid UTF-8 string. + */ + final int partialIsValidUtf8( + final int state, final ByteBuffer buffer, int index, final int limit) { + if (buffer.hasArray()) { + final int offset = buffer.arrayOffset(); + return partialIsValidUtf8(state, buffer.array(), offset + index, offset + limit); + } else if (buffer.isDirect()){ + return partialIsValidUtf8Direct(state, buffer, index, limit); + } + return partialIsValidUtf8Default(state, buffer, index, limit); + } + + /** + * Performs validation for direct {@link ByteBuffer} instances. + */ + abstract int partialIsValidUtf8Direct( + final int state, final ByteBuffer buffer, int index, final int limit); + + /** + * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather + * than potentially faster approaches. This first completes validation for the current + * character (provided by {@code state}) and then finishes validation for the sequence. + */ + final int partialIsValidUtf8Default( + final int state, final ByteBuffer buffer, int index, final int limit) { + if (state != COMPLETE) { + // The previous decoding operation was incomplete (or malformed). + // We look for a well-formed sequence consisting of bytes from + // the previous decoding operation (stored in state) together + // with bytes from the array slice. + // + // We expect such "straddler characters" to be rare. + + if (index >= limit) { // No bytes? No progress. + return state; + } + + byte byte1 = (byte) state; + // byte1 is never ASCII. + if (byte1 < (byte) 0xE0) { + // two-byte form + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 + // byte2 trailing-byte test + || buffer.get(index++) > (byte) 0xBF) { + return MALFORMED; + } + } else if (byte1 < (byte) 0xF0) { + // three-byte form + + // Get byte2 from saved state or array + byte byte2 = (byte) ~(state >> 8); + if (byte2 == 0) { + byte2 = buffer.get(index++); + if (index >= limit) { + return incompleteStateFor(byte1, byte2); + } + } + if (byte2 > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // illegal surrogate codepoint? + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || buffer.get(index++) > (byte) 0xBF) { + return MALFORMED; + } + } else { + // four-byte form + + // Get byte2 and byte3 from saved state or array + byte byte2 = (byte) ~(state >> 8); + byte byte3 = 0; + if (byte2 == 0) { + byte2 = buffer.get(index++); + if (index >= limit) { + return incompleteStateFor(byte1, byte2); + } + } else { + byte3 = (byte) (state >> 16); + } + if (byte3 == 0) { + byte3 = buffer.get(index++); + if (index >= limit) { + return incompleteStateFor(byte1, byte2, byte3); + } + } + + // If we were called with state == MALFORMED, then byte1 is 0xFF, + // which never occurs in well-formed UTF-8, and so we will return + // MALFORMED again below. + + if (byte2 > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || byte3 > (byte) 0xBF + // byte4 trailing-byte test + || buffer.get(index++) > (byte) 0xBF) { + return MALFORMED; + } + } + } + + // Finish validation for the sequence. + return partialIsValidUtf8(buffer, index, limit); + } + + /** + * Performs validation for {@link ByteBuffer} instances using the {@link ByteBuffer} API rather + * than potentially faster approaches. + */ + private static int partialIsValidUtf8(final ByteBuffer buffer, int index, final int limit) { + index += estimateConsecutiveAscii(buffer, index, limit); + + for (;;) { + // Optimize for interior runs of ASCII bytes. + // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold? + // Maybe after seeing a few in a row that are ASCII, go back to fast mode? + int byte1; + do { + if (index >= limit) { + return COMPLETE; + } + } while ((byte1 = buffer.get(index++)) >= 0); + + // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms. + if (byte1 < (byte) 0xE0) { + // Two-byte form (110xxxxx 10xxxxxx) + if (index >= limit) { + // Incomplete sequence + return byte1; + } + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 || buffer.get(index) > (byte) 0xBF) { + return MALFORMED; + } + index++; + } else if (byte1 < (byte) 0xF0) { + // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx) + if (index >= limit - 1) { + // Incomplete sequence + return incompleteStateFor(buffer, byte1, index, limit - index); + } + + final byte byte2 = buffer.get(index++); + if (byte2 > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // check for illegal surrogate codepoints + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || buffer.get(index) > (byte) 0xBF) { + return MALFORMED; + } + index++; + } else { + // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx) + if (index >= limit - 2) { + // Incomplete sequence + return incompleteStateFor(buffer, byte1, index, limit - index); + } + + // TODO(nathanmittler): Consider using getInt() to improve performance. + final int byte2 = buffer.get(index++); + if (byte2 > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || buffer.get(index++) > (byte) 0xBF + // byte4 trailing-byte test + || buffer.get(index++) > (byte) 0xBF) { + return MALFORMED; + } + } + } + } + + /** + * Encodes an input character sequence ({@code in}) to UTF-8 in the target array ({@code out}). + * For a string, this method is similar to + *

{@code
+     * byte[] a = string.getBytes(UTF_8);
+     * System.arraycopy(a, 0, bytes, offset, a.length);
+     * return offset + a.length;
+     * }
+ * + * but is more efficient in both time and space. One key difference is that this method + * requires paired surrogates, and therefore does not support chunking. + * While {@code String.getBytes(UTF_8)} replaces unpaired surrogates with the default + * replacement character, this method throws {@link UnpairedSurrogateException}. + * + *

To ensure sufficient space in the output buffer, either call {@link #encodedLength} to + * compute the exact amount needed, or leave room for + * {@code Utf8.MAX_BYTES_PER_CHAR * sequence.length()}, which is the largest possible number + * of bytes that any input can be encoded to. + * + * @param in the input character sequence to be encoded + * @param out the target array + * @param offset the starting offset in {@code bytes} to start writing at + * @param length the length of the {@code bytes}, starting from {@code offset} + * @throws UnpairedSurrogateException if {@code sequence} contains ill-formed UTF-16 (unpaired + * surrogates) + * @throws ArrayIndexOutOfBoundsException if {@code sequence} encoded in UTF-8 is longer than + * {@code bytes.length - offset} + * @return the new offset, equivalent to {@code offset + Utf8.encodedLength(sequence)} + */ + abstract int encodeUtf8(CharSequence in, byte[] out, int offset, int length); + + /** + * Encodes an input character sequence ({@code in}) to UTF-8 in the target buffer ({@code out}). + * Upon returning from this method, the {@code out} position will point to the position after + * the last encoded byte. This method requires paired surrogates, and therefore does not + * support chunking. + * + *

To ensure sufficient space in the output buffer, either call {@link #encodedLength} to + * compute the exact amount needed, or leave room for + * {@code Utf8.MAX_BYTES_PER_CHAR * in.length()}, which is the largest possible number + * of bytes that any input can be encoded to. + * + * @param in the source character sequence to be encoded + * @param out the target buffer + * @throws UnpairedSurrogateException if {@code in} contains ill-formed UTF-16 (unpaired + * surrogates) + * @throws ArrayIndexOutOfBoundsException if {@code in} encoded in UTF-8 is longer than + * {@code out.remaining()} + */ + final void encodeUtf8(CharSequence in, ByteBuffer out) { + if (out.hasArray()) { + final int offset = out.arrayOffset(); + int endIndex = + Utf8.encode(in, out.array(), offset + out.position(), out.remaining()); + out.position(endIndex - offset); + } else if (out.isDirect()) { + encodeUtf8Direct(in, out); + } else { + encodeUtf8Default(in, out); + } + } + + /** + * Encodes the input character sequence to a direct {@link ByteBuffer} instance. + */ + abstract void encodeUtf8Direct(CharSequence in, ByteBuffer out); + + /** + * Encodes the input character sequence to a {@link ByteBuffer} instance using the {@link + * ByteBuffer} API, rather than potentially faster approaches. + */ + final void encodeUtf8Default(CharSequence in, ByteBuffer out) { + final int inLength = in.length(); + int outIx = out.position(); + int inIx = 0; + + // Since ByteBuffer.putXXX() already checks boundaries for us, no need to explicitly check + // access. Assume the buffer is big enough and let it handle the out of bounds exception + // if it occurs. + try { + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; inIx < inLength && (c = in.charAt(inIx)) < 0x80; ++inIx) { + out.put(outIx + inIx, (byte) c); + } + if (inIx == inLength) { + // Successfully encoded the entire string. + out.position(outIx + inIx); + return; + } + + outIx += inIx; + for (char c; inIx < inLength; ++inIx, ++outIx) { + c = in.charAt(inIx); + if (c < 0x80) { + // One byte (0xxx xxxx) + out.put(outIx, (byte) c); + } else if (c < 0x800) { + // Two bytes (110x xxxx 10xx xxxx) + + // Benchmarks show put performs better than putShort here (for HotSpot). + out.put(outIx++, (byte) (0xC0 | (c >>> 6))); + out.put(outIx, (byte) (0x80 | (0x3F & c))); + } else if (c < MIN_SURROGATE || MAX_SURROGATE < c) { + // Three bytes (1110 xxxx 10xx xxxx 10xx xxxx) + // Maximum single-char code point is 0xFFFF, 16 bits. + + // Benchmarks show put performs better than putShort here (for HotSpot). + out.put(outIx++, (byte) (0xE0 | (c >>> 12))); + out.put(outIx++, (byte) (0x80 | (0x3F & (c >>> 6)))); + out.put(outIx, (byte) (0x80 | (0x3F & c))); + } else { + // Four bytes (1111 xxxx 10xx xxxx 10xx xxxx 10xx xxxx) + + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 + // bytes + final char low; + if (inIx + 1 == inLength || !isSurrogatePair(c, (low = in.charAt(++inIx)))) { + throw new UnpairedSurrogateException(inIx, inLength); + } + // TODO(nathanmittler): Consider using putInt() to improve performance. + int codePoint = toCodePoint(c, low); + out.put(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18))); + out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12)))); + out.put(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6)))); + out.put(outIx, (byte) (0x80 | (0x3F & codePoint))); + } + } + + // Successfully encoded the entire string. + out.position(outIx); + } catch (IndexOutOfBoundsException e) { + // TODO(nathanmittler): Consider making the API throw IndexOutOfBoundsException instead. + + // If we failed in the outer ASCII loop, outIx will not have been updated. In this case, + // use inIx to determine the bad write index. + int badWriteIndex = out.position() + Math.max(inIx, outIx - out.position() + 1); + throw new ArrayIndexOutOfBoundsException( + "Failed writing " + in.charAt(inIx) + " at index " + badWriteIndex); + } + } + } + + /** + * {@link Processor} implementation that does not use any {@code sun.misc.Unsafe} methods. + */ + static final class SafeProcessor extends Processor { + @Override + int partialIsValidUtf8(int state, byte[] bytes, int index, int limit) { + if (state != COMPLETE) { + // The previous decoding operation was incomplete (or malformed). + // We look for a well-formed sequence consisting of bytes from + // the previous decoding operation (stored in state) together + // with bytes from the array slice. + // + // We expect such "straddler characters" to be rare. + + if (index >= limit) { // No bytes? No progress. + return state; + } + int byte1 = (byte) state; + // byte1 is never ASCII. + if (byte1 < (byte) 0xE0) { + // two-byte form + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 + // byte2 trailing-byte test + || bytes[index++] > (byte) 0xBF) { + return MALFORMED; + } + } else if (byte1 < (byte) 0xF0) { + // three-byte form + + // Get byte2 from saved state or array + int byte2 = (byte) ~(state >> 8); + if (byte2 == 0) { + byte2 = bytes[index++]; + if (index >= limit) { + return incompleteStateFor(byte1, byte2); + } + } + if (byte2 > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // illegal surrogate codepoint? + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || bytes[index++] > (byte) 0xBF) { + return MALFORMED; + } + } else { + // four-byte form + + // Get byte2 and byte3 from saved state or array + int byte2 = (byte) ~(state >> 8); + int byte3 = 0; + if (byte2 == 0) { + byte2 = bytes[index++]; + if (index >= limit) { + return incompleteStateFor(byte1, byte2); + } + } else { + byte3 = (byte) (state >> 16); + } + if (byte3 == 0) { + byte3 = bytes[index++]; + if (index >= limit) { + return incompleteStateFor(byte1, byte2, byte3); + } + } + + // If we were called with state == MALFORMED, then byte1 is 0xFF, + // which never occurs in well-formed UTF-8, and so we will return + // MALFORMED again below. + + if (byte2 > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || byte3 > (byte) 0xBF + // byte4 trailing-byte test + || bytes[index++] > (byte) 0xBF) { + return MALFORMED; + } + } + } + + return partialIsValidUtf8(bytes, index, limit); + } + + @Override + int partialIsValidUtf8Direct(int state, ByteBuffer buffer, int index, int limit) { + // For safe processing, we have to use the ByteBuffer API. + return partialIsValidUtf8Default(state, buffer, index, limit); + } + + @Override + int encodeUtf8(CharSequence in, byte[] out, int offset, int length) { + int utf16Length = in.length(); + int j = offset; + int i = 0; + int limit = offset + length; + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + for (char c; i < utf16Length && i + j < limit && (c = in.charAt(i)) < 0x80; i++) { + out[j + i] = (byte) c; + } + if (i == utf16Length) { + return j + utf16Length; + } + j += i; + for (char c; i < utf16Length; i++) { + c = in.charAt(i); + if (c < 0x80 && j < limit) { + out[j++] = (byte) c; + } else if (c < 0x800 && j <= limit - 2) { // 11 bits, two UTF-8 bytes + out[j++] = (byte) ((0xF << 6) | (c >>> 6)); + out[j++] = (byte) (0x80 | (0x3F & c)); + } else if ((c < Character.MIN_SURROGATE || Character.MAX_SURROGATE < c) && j <= limit - 3) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + out[j++] = (byte) ((0xF << 5) | (c >>> 12)); + out[j++] = (byte) (0x80 | (0x3F & (c >>> 6))); + out[j++] = (byte) (0x80 | (0x3F & c)); + } else if (j <= limit - 4) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, + // four UTF-8 bytes + final char low; + if (i + 1 == in.length() + || !Character.isSurrogatePair(c, (low = in.charAt(++i)))) { + throw new UnpairedSurrogateException((i - 1), utf16Length); + } + int codePoint = Character.toCodePoint(c, low); + out[j++] = (byte) ((0xF << 4) | (codePoint >>> 18)); + out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 12))); + out[j++] = (byte) (0x80 | (0x3F & (codePoint >>> 6))); + out[j++] = (byte) (0x80 | (0x3F & codePoint)); + } else { + // If we are surrogates and we're not a surrogate pair, always throw an + // UnpairedSurrogateException instead of an ArrayOutOfBoundsException. + if ((Character.MIN_SURROGATE <= c && c <= Character.MAX_SURROGATE) + && (i + 1 == in.length() + || !Character.isSurrogatePair(c, in.charAt(i + 1)))) { + throw new UnpairedSurrogateException(i, utf16Length); + } + throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + j); + } + } + return j; + } + + @Override + void encodeUtf8Direct(CharSequence in, ByteBuffer out) { + // For safe processing, we have to use the ByteBuffer API. + encodeUtf8Default(in, out); + } + + private static int partialIsValidUtf8(byte[] bytes, int index, int limit) { + // Optimize for 100% ASCII (Hotspot loves small simple top-level loops like this). + // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII). + while (index < limit && bytes[index] >= 0) { + index++; + } + + return (index >= limit) ? COMPLETE : partialIsValidUtf8NonAscii(bytes, index, limit); + } + + private static int partialIsValidUtf8NonAscii(byte[] bytes, int index, int limit) { + for (;;) { + int byte1, byte2; + + // Optimize for interior runs of ASCII bytes. + do { + if (index >= limit) { + return COMPLETE; + } + } while ((byte1 = bytes[index++]) >= 0); + + if (byte1 < (byte) 0xE0) { + // two-byte form + + if (index >= limit) { + // Incomplete sequence + return byte1; + } + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 + || bytes[index++] > (byte) 0xBF) { + return MALFORMED; + } + } else if (byte1 < (byte) 0xF0) { + // three-byte form + + if (index >= limit - 1) { // incomplete sequence + return incompleteStateFor(bytes, index, limit); + } + if ((byte2 = bytes[index++]) > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // check for illegal surrogate codepoints + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || bytes[index++] > (byte) 0xBF) { + return MALFORMED; + } + } else { + // four-byte form + + if (index >= limit - 2) { // incomplete sequence + return incompleteStateFor(bytes, index, limit); + } + if ((byte2 = bytes[index++]) > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || bytes[index++] > (byte) 0xBF + // byte4 trailing-byte test + || bytes[index++] > (byte) 0xBF) { + return MALFORMED; + } + } + } + } + } + + /** + * {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance. + */ + static final class UnsafeProcessor extends Processor { + private static final sun.misc.Unsafe UNSAFE = getUnsafe(); + private static final long BUFFER_ADDRESS_OFFSET = + fieldOffset(field(Buffer.class, "address")); + private static final int ARRAY_BASE_OFFSET = byteArrayBaseOffset(); + + /** + * We only use Unsafe operations if we have access to direct {@link ByteBuffer}'s address + * and the array base offset is a multiple of 8 (needed by Unsafe.getLong()). + */ + private static final boolean AVAILABLE = + BUFFER_ADDRESS_OFFSET != -1 && ARRAY_BASE_OFFSET % 8 == 0; + + /** + * Indicates whether or not all required unsafe operations are supported on this platform. + */ + static boolean isAvailable() { + return AVAILABLE; + } + + @Override + int partialIsValidUtf8(int state, byte[] bytes, final int index, final int limit) { + if ((index | limit | bytes.length - limit) < 0) { + throw new ArrayIndexOutOfBoundsException( + String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit)); + } + long offset = ARRAY_BASE_OFFSET + index; + final long offsetLimit = ARRAY_BASE_OFFSET + limit; + if (state != COMPLETE) { + // The previous decoding operation was incomplete (or malformed). + // We look for a well-formed sequence consisting of bytes from + // the previous decoding operation (stored in state) together + // with bytes from the array slice. + // + // We expect such "straddler characters" to be rare. + + if (offset >= offsetLimit) { // No bytes? No progress. + return state; + } + int byte1 = (byte) state; + // byte1 is never ASCII. + if (byte1 < (byte) 0xE0) { + // two-byte form + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 + // byte2 trailing-byte test + || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) { + return MALFORMED; + } + } else if (byte1 < (byte) 0xF0) { + // three-byte form + + // Get byte2 from saved state or array + int byte2 = (byte) ~(state >> 8); + if (byte2 == 0) { + byte2 = UNSAFE.getByte(bytes, offset++); + if (offset >= offsetLimit) { + return incompleteStateFor(byte1, byte2); + } + } + if (byte2 > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // illegal surrogate codepoint? + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) { + return MALFORMED; + } + } else { + // four-byte form + + // Get byte2 and byte3 from saved state or array + int byte2 = (byte) ~(state >> 8); + int byte3 = 0; + if (byte2 == 0) { + byte2 = UNSAFE.getByte(bytes, offset++); + if (offset >= offsetLimit) { + return incompleteStateFor(byte1, byte2); + } + } else { + byte3 = (byte) (state >> 16); + } + if (byte3 == 0) { + byte3 = UNSAFE.getByte(bytes, offset++); + if (offset >= offsetLimit) { + return incompleteStateFor(byte1, byte2, byte3); + } + } + + // If we were called with state == MALFORMED, then byte1 is 0xFF, + // which never occurs in well-formed UTF-8, and so we will return + // MALFORMED again below. + + if (byte2 > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || byte3 > (byte) 0xBF + // byte4 trailing-byte test + || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) { + return MALFORMED; + } + } + } + + return partialIsValidUtf8(bytes, offset, (int) (offsetLimit - offset)); + } + + @Override + int partialIsValidUtf8Direct( + final int state, ByteBuffer buffer, final int index, final int limit) { + if ((index | limit | buffer.limit() - limit) < 0) { + throw new ArrayIndexOutOfBoundsException( + String.format("buffer limit=%d, index=%d, limit=%d", buffer.limit(), index, limit)); + } + long address = addressOffset(buffer) + index; + final long addressLimit = address + (limit - index); + if (state != COMPLETE) { + // The previous decoding operation was incomplete (or malformed). + // We look for a well-formed sequence consisting of bytes from + // the previous decoding operation (stored in state) together + // with bytes from the array slice. + // + // We expect such "straddler characters" to be rare. + + if (address >= addressLimit) { // No bytes? No progress. + return state; + } + + final int byte1 = (byte) state; + // byte1 is never ASCII. + if (byte1 < (byte) 0xE0) { + // two-byte form + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 + // byte2 trailing-byte test + || UNSAFE.getByte(address++) > (byte) 0xBF) { + return MALFORMED; + } + } else if (byte1 < (byte) 0xF0) { + // three-byte form + + // Get byte2 from saved state or array + int byte2 = (byte) ~(state >> 8); + if (byte2 == 0) { + byte2 = UNSAFE.getByte(address++); + if (address >= addressLimit) { + return incompleteStateFor(byte1, byte2); + } + } + if (byte2 > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // illegal surrogate codepoint? + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || UNSAFE.getByte(address++) > (byte) 0xBF) { + return MALFORMED; + } + } else { + // four-byte form + + // Get byte2 and byte3 from saved state or array + int byte2 = (byte) ~(state >> 8); + int byte3 = 0; + if (byte2 == 0) { + byte2 = UNSAFE.getByte(address++); + if (address >= addressLimit) { + return incompleteStateFor(byte1, byte2); + } + } else { + byte3 = (byte) (state >> 16); + } + if (byte3 == 0) { + byte3 = UNSAFE.getByte(address++); + if (address >= addressLimit) { + return incompleteStateFor(byte1, byte2, byte3); + } + } + + // If we were called with state == MALFORMED, then byte1 is 0xFF, + // which never occurs in well-formed UTF-8, and so we will return + // MALFORMED again below. + + if (byte2 > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || byte3 > (byte) 0xBF + // byte4 trailing-byte test + || UNSAFE.getByte(address++) > (byte) 0xBF) { + return MALFORMED; + } + } + } + + return partialIsValidUtf8(address, (int) (addressLimit - address)); + } + + @Override + int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) { + long outIx = ARRAY_BASE_OFFSET + offset; + final long outLimit = outIx + length; + final int inLimit = in.length(); + if (inLimit > length || out.length - length < offset) { + // Not even enough room for an ASCII-encoded string. + throw new ArrayIndexOutOfBoundsException( + "Failed writing " + in.charAt(inLimit - 1) + " at index " + (offset + length)); + } + + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + int inIx = 0; + for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) { + UNSAFE.putByte(out, outIx++, (byte) c); + } + if (inIx == inLimit) { + // We're done, it was ASCII encoded. + return (int) (outIx - ARRAY_BASE_OFFSET); + } + + for (char c; inIx < inLimit; ++inIx) { + c = in.charAt(inIx); + if (c < 0x80 && outIx < outLimit) { + UNSAFE.putByte(out, outIx++, (byte) c); + } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes + UNSAFE.putByte(out, outIx++, (byte) ((0xF << 6) | (c >>> 6))); + UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c))); + } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + UNSAFE.putByte(out, outIx++, (byte) ((0xF << 5) | (c >>> 12))); + UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (c >>> 6)))); + UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c))); + } else if (outIx <= outLimit - 4L) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 + // bytes + final char low; + if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) { + throw new UnpairedSurrogateException((inIx - 1), inLimit); + } + int codePoint = toCodePoint(c, low); + UNSAFE.putByte(out, outIx++, (byte) ((0xF << 4) | (codePoint >>> 18))); + UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12)))); + UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6)))); + UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & codePoint))); + } else { + if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE) + && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) { + // We are surrogates and we're not a surrogate pair. + throw new UnpairedSurrogateException(inIx, inLimit); + } + // Not enough space in the output buffer. + throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx); + } + } + + // All bytes have been encoded. + return (int) (outIx - ARRAY_BASE_OFFSET); + } + + @Override + void encodeUtf8Direct(CharSequence in, ByteBuffer out) { + final long address = addressOffset(out); + long outIx = address + out.position(); + final long outLimit = address + out.limit(); + final int inLimit = in.length(); + if (inLimit > outLimit - outIx) { + // Not even enough room for an ASCII-encoded string. + throw new ArrayIndexOutOfBoundsException( + "Failed writing " + in.charAt(inLimit - 1) + " at index " + out.limit()); + } + + // Designed to take advantage of + // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination + int inIx = 0; + for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) { + UNSAFE.putByte(outIx++, (byte) c); + } + if (inIx == inLimit) { + // We're done, it was ASCII encoded. + out.position((int) (outIx - address)); + return; + } + + for (char c; inIx < inLimit; ++inIx) { + c = in.charAt(inIx); + if (c < 0x80 && outIx < outLimit) { + UNSAFE.putByte(outIx++, (byte) c); + } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes + UNSAFE.putByte(outIx++, (byte) ((0xF << 6) | (c >>> 6))); + UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c))); + } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) { + // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes + UNSAFE.putByte(outIx++, (byte) ((0xF << 5) | (c >>> 12))); + UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (c >>> 6)))); + UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c))); + } else if (outIx <= outLimit - 4L) { + // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8 + // bytes + final char low; + if (inIx + 1 == inLimit || !isSurrogatePair(c, (low = in.charAt(++inIx)))) { + throw new UnpairedSurrogateException((inIx - 1), inLimit); + } + int codePoint = toCodePoint(c, low); + UNSAFE.putByte(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18))); + UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12)))); + UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6)))); + UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & codePoint))); + } else { + if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE) + && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) { + // We are surrogates and we're not a surrogate pair. + throw new UnpairedSurrogateException(inIx, inLimit); + } + // Not enough space in the output buffer. + throw new ArrayIndexOutOfBoundsException("Failed writing " + c + " at index " + outIx); + } + } + + // All bytes have been encoded. + out.position((int) (outIx - address)); + } + + /** + * Counts (approximately) the number of consecutive ASCII characters starting from the given + * position, using the most efficient method available to the platform. + * + * @param bytes the array containing the character sequence + * @param offset the offset position of the index (same as index + arrayBaseOffset) + * @param maxChars the maximum number of characters to count + * @return the number of ASCII characters found. The stopping position will be at or + * before the first non-ASCII byte. + */ + private static int unsafeEstimateConsecutiveAscii( + byte[] bytes, long offset, final int maxChars) { + int remaining = maxChars; + if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) { + // Don't bother with small strings. + return 0; + } + + // Read bytes until 8-byte aligned so that we can read longs in the loop below. + // Byte arrays are already either 8 or 16-byte aligned, so we just need to make sure that + // the index (relative to the start of the array) is also 8-byte aligned. We do this by + // ANDing the index with 7 to determine the number of bytes that need to be read before + // we're 8-byte aligned. + final int unaligned = (int) offset & 7; + for (int j = unaligned; j > 0; j--) { + if (UNSAFE.getByte(bytes, offset++) < 0) { + return unaligned - j; + } + } + + // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII). + // To speed things up further, we're reading longs instead of bytes so we use a mask to + // determine if any byte in the current long is non-ASCII. + remaining -= unaligned; + for (; remaining >= 8 && (UNSAFE.getLong(bytes, offset) & ASCII_MASK_LONG) == 0; + offset += 8, remaining -= 8) {} + return maxChars - remaining; + } + + /** + * Same as {@link Utf8#estimateConsecutiveAscii(ByteBuffer, int, int)} except that it uses the + * most efficient method available to the platform. + */ + private static int unsafeEstimateConsecutiveAscii(long address, final int maxChars) { + int remaining = maxChars; + if (remaining < UNSAFE_COUNT_ASCII_THRESHOLD) { + // Don't bother with small strings. + return 0; + } + + // Read bytes until 8-byte aligned so that we can read longs in the loop below. + // We do this by ANDing the address with 7 to determine the number of bytes that need to + // be read before we're 8-byte aligned. + final int unaligned = (int) address & 7; + for (int j = unaligned; j > 0; j--) { + if (UNSAFE.getByte(address++) < 0) { + return unaligned - j; + } + } + + // This simple loop stops when we encounter a byte >= 0x80 (i.e. non-ASCII). + // To speed things up further, we're reading longs instead of bytes so we use a mask to + // determine if any byte in the current long is non-ASCII. + remaining -= unaligned; + for (; remaining >= 8 && (UNSAFE.getLong(address) & ASCII_MASK_LONG) == 0; + address += 8, remaining -= 8) {} + return maxChars - remaining; + } + + private static int partialIsValidUtf8(final byte[] bytes, long offset, int remaining) { + // Skip past ASCII characters as quickly as possible. + final int skipped = unsafeEstimateConsecutiveAscii(bytes, offset, remaining); + remaining -= skipped; + offset += skipped; + + for (;;) { + // Optimize for interior runs of ASCII bytes. + // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold? + // Maybe after seeing a few in a row that are ASCII, go back to fast mode? + int byte1 = 0; + for (; remaining > 0 && (byte1 = UNSAFE.getByte(bytes, offset++)) >= 0; --remaining) { + } + if (remaining == 0) { + return COMPLETE; + } + remaining--; + + // If we're here byte1 is not ASCII. Only need to handle 2-4 byte forms. + if (byte1 < (byte) 0xE0) { + // Two-byte form (110xxxxx 10xxxxxx) + if (remaining == 0) { + // Incomplete sequence + return byte1; + } + remaining--; + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 + || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) { + return MALFORMED; + } + } else if (byte1 < (byte) 0xF0) { + // Three-byte form (1110xxxx 10xxxxxx 10xxxxxx) + if (remaining < 2) { + // Incomplete sequence + return unsafeIncompleteStateFor(bytes, byte1, offset, remaining); + } + remaining -= 2; + + final int byte2; + if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // check for illegal surrogate codepoints + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) { + return MALFORMED; + } + } else { + // Four-byte form (1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx) + if (remaining < 3) { + // Incomplete sequence + return unsafeIncompleteStateFor(bytes, byte1, offset, remaining); + } + remaining -= 3; + + final int byte2; + if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF + // byte4 trailing-byte test + || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) { + return MALFORMED; + } + } + } + } + + private static int partialIsValidUtf8(long address, int remaining) { + // Skip past ASCII characters as quickly as possible. + final int skipped = unsafeEstimateConsecutiveAscii(address, remaining); + address += skipped; + remaining -= skipped; + + for (;;) { + // Optimize for interior runs of ASCII bytes. + // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold? + // Maybe after seeing a few in a row that are ASCII, go back to fast mode? + int byte1 = 0; + for (; remaining > 0 && (byte1 = UNSAFE.getByte(address++)) >= 0; --remaining) { + } + if (remaining == 0) { + return COMPLETE; + } + remaining--; + + if (byte1 < (byte) 0xE0) { + // Two-byte form + + if (remaining == 0) { + // Incomplete sequence + return byte1; + } + remaining--; + + // Simultaneously checks for illegal trailing-byte in + // leading position and overlong 2-byte form. + if (byte1 < (byte) 0xC2 || UNSAFE.getByte(address++) > (byte) 0xBF) { + return MALFORMED; + } + } else if (byte1 < (byte) 0xF0) { + // Three-byte form + + if (remaining < 2) { + // Incomplete sequence + return unsafeIncompleteStateFor(address, byte1, remaining); + } + remaining -= 2; + + final byte byte2 = UNSAFE.getByte(address++); + if (byte2 > (byte) 0xBF + // overlong? 5 most significant bits must not all be zero + || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0) + // check for illegal surrogate codepoints + || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0) + // byte3 trailing-byte test + || UNSAFE.getByte(address++) > (byte) 0xBF) { + return MALFORMED; + } + } else { + // Four-byte form + + if (remaining < 3) { + // Incomplete sequence + return unsafeIncompleteStateFor(address, byte1, remaining); + } + remaining -= 3; + + final byte byte2 = UNSAFE.getByte(address++); + if (byte2 > (byte) 0xBF + // Check that 1 <= plane <= 16. Tricky optimized form of: + // if (byte1 > (byte) 0xF4 || + // byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 || + // byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F) + || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0 + // byte3 trailing-byte test + || UNSAFE.getByte(address++) > (byte) 0xBF + // byte4 trailing-byte test + || UNSAFE.getByte(address++) > (byte) 0xBF) { + return MALFORMED; + } + } + } + } + + private static int unsafeIncompleteStateFor(byte[] bytes, int byte1, long offset, + int remaining) { + switch (remaining) { + case 0: { + return incompleteStateFor(byte1); + } + case 1: { + return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset)); + } + case 2: { + return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset), + UNSAFE.getByte(bytes, offset + 1)); + } + default: { + throw new AssertionError(); + } + } + } + + private static int unsafeIncompleteStateFor(long address, final int byte1, int remaining) { + switch (remaining) { + case 0: { + return incompleteStateFor(byte1); + } + case 1: { + return incompleteStateFor(byte1, UNSAFE.getByte(address)); + } + case 2: { + return incompleteStateFor(byte1, UNSAFE.getByte(address), UNSAFE.getByte(address + 1)); + } + default: { + throw new AssertionError(); + } + } + } + + /** + * Gets the field with the given name within the class, or {@code null} if not found. If + * found, the field is made accessible. + */ + private static Field field(Class clazz, String fieldName) { + Field field; + try { + field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + } catch (Throwable t) { + // Failed to access the fields. + field = null; + } + logger.log(Level.FINEST, "{0}.{1}: {2}", + new Object[] {clazz.getName(), fieldName, (field != null ? "available" : "unavailable")}); + return field; + } + + /** + * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not + * available. + */ + private static long fieldOffset(Field field) { + return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field); + } + + /** + * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not + * available. + */ + private static int byteArrayBaseOffset() { + return UNSAFE == null ? -1 : UNSAFE.arrayBaseOffset(byte[].class); + } + + /** + * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}. + */ + private static long addressOffset(ByteBuffer buffer) { + return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET); + } + + /** + * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this + * platform. + */ + private static sun.misc.Unsafe getUnsafe() { + sun.misc.Unsafe unsafe = null; + try { + unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public sun.misc.Unsafe run() throws Exception { + Class k = sun.misc.Unsafe.class; + + // Check that this platform supports all of the required unsafe methods. + checkRequiredMethods(k); + + for (Field f : k.getDeclaredFields()) { + f.setAccessible(true); + Object x = f.get(null); + if (k.isInstance(x)) { + return k.cast(x); + } + } + // The sun.misc.Unsafe field does not exist. + return null; + } + }); + } catch (Throwable e) { + // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError + // for Unsafe. + } + + logger.log(Level.FINEST, "sun.misc.Unsafe: {}", + unsafe != null ? "available" : "unavailable"); + return unsafe; + } + + /** + * Verifies that all required methods of {@code sun.misc.Unsafe} are available on this platform. + */ + private static void checkRequiredMethods(Class clazz) + throws NoSuchMethodException, SecurityException { + // Needed for Unsafe byte[] access + clazz.getMethod("arrayBaseOffset", Class.class); + clazz.getMethod("getByte", Object.class, long.class); + clazz.getMethod("putByte", Object.class, long.class, byte.class); + clazz.getMethod("getLong", Object.class, long.class); + + // Needed for Unsafe Direct ByteBuffer access + clazz.getMethod("objectFieldOffset", Field.class); + clazz.getMethod("getByte", long.class); + clazz.getMethod("getLong", Object.class, long.class); + clazz.getMethod("putByte", long.class, byte.class); + clazz.getMethod("getLong", long.class); + } + } + + private Utf8() {} } diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java index d964ef59..1e57b647 100644 --- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java @@ -40,7 +40,6 @@ import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestRequiredForeign; import protobuf_unittest.UnittestProto.TestUnpackedTypes; - import junit.framework.TestCase; import java.util.Map; diff --git a/java/core/src/test/java/com/google/protobuf/AnyTest.java b/java/core/src/test/java/com/google/protobuf/AnyTest.java index e169f69d..cf91ed91 100644 --- a/java/core/src/test/java/com/google/protobuf/AnyTest.java +++ b/java/core/src/test/java/com/google/protobuf/AnyTest.java @@ -75,6 +75,51 @@ public class AnyTest extends TestCase { } } + public void testCustomTypeUrls() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + TestUtil.setAllFields(builder); + TestAllTypes message = builder.build(); + + TestAny container = TestAny.newBuilder() + .setValue(Any.pack(message, "xxx.com")).build(); + + assertEquals( + "xxx.com/" + TestAllTypes.getDescriptor().getFullName(), + container.getValue().getTypeUrl()); + + assertTrue(container.getValue().is(TestAllTypes.class)); + assertFalse(container.getValue().is(TestAny.class)); + + TestAllTypes result = container.getValue().unpack(TestAllTypes.class); + TestUtil.assertAllFieldsSet(result); + + container = TestAny.newBuilder() + .setValue(Any.pack(message, "yyy.com/")).build(); + + assertEquals( + "yyy.com/" + TestAllTypes.getDescriptor().getFullName(), + container.getValue().getTypeUrl()); + + assertTrue(container.getValue().is(TestAllTypes.class)); + assertFalse(container.getValue().is(TestAny.class)); + + result = container.getValue().unpack(TestAllTypes.class); + TestUtil.assertAllFieldsSet(result); + + container = TestAny.newBuilder() + .setValue(Any.pack(message, "")).build(); + + assertEquals( + "/" + TestAllTypes.getDescriptor().getFullName(), + container.getValue().getTypeUrl()); + + assertTrue(container.getValue().is(TestAllTypes.class)); + assertFalse(container.getValue().is(TestAny.class)); + + result = container.getValue().unpack(TestAllTypes.class); + TestUtil.assertAllFieldsSet(result); + } + public void testCachedUnpackResult() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TestUtil.setAllFields(builder); diff --git a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java index 7a8a0a5e..db10ee74 100644 --- a/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java +++ b/java/core/src/test/java/com/google/protobuf/BoundedByteStringTest.java @@ -37,7 +37,6 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; - /** * This class tests {@link BoundedByteString}, which extends {@link LiteralByteString}, * by inheriting the tests from {@link LiteralByteStringTest}. The only method which diff --git a/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java new file mode 100644 index 00000000..cbe742e5 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/ByteBufferWriterTest.java @@ -0,0 +1,81 @@ +// 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. + +package com.google.protobuf; + +import junit.framework.TestCase; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Random; + +/** + * Tests for {@link ByteBufferWriter}. + */ +public class ByteBufferWriterTest extends TestCase { + + public void testHeapBuffer() throws IOException { + // Test a small and large buffer. + testWrite(ByteBuffer.allocate(100)); + testWrite(ByteBuffer.allocate(1024 * 100)); + } + + public void testDirectBuffer() throws IOException { + // Test a small and large buffer. + testWrite(ByteBuffer.allocateDirect(100)); + testWrite(ByteBuffer.allocateDirect(1024 * 100)); + } + + private void testWrite(ByteBuffer buffer) throws IOException { + fillRandom(buffer); + ByteArrayOutputStream os = new ByteArrayOutputStream(buffer.remaining()); + ByteBufferWriter.write(buffer, os); + assertEquals(0, buffer.position()); + assertTrue(Arrays.equals(toArray(buffer), os.toByteArray())); + } + + private void fillRandom(ByteBuffer buf) { + byte[] bytes = new byte[buf.remaining()]; + new Random().nextBytes(bytes); + buf.put(bytes); + buf.flip(); + return; + } + + private byte[] toArray(ByteBuffer buf) { + int originalPosition = buf.position(); + byte[] bytes = new byte[buf.remaining()]; + buf.get(bytes); + buf.position(originalPosition); + return bytes; + } +} diff --git a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java index 5267c160..ad9f266e 100644 --- a/java/core/src/test/java/com/google/protobuf/ByteStringTest.java +++ b/java/core/src/test/java/com/google/protobuf/ByteStringTest.java @@ -39,6 +39,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; @@ -757,4 +758,17 @@ public class ByteStringTest extends TestCase { assertEquals((byte) 2, result[dataSize - dataSize / 2]); assertEquals((byte) 2, result[dataSize - 1]); } + + /** + * Tests ByteString uses Arrays based byte copier when running under Hotstop VM. + */ + public void testByteArrayCopier() throws Exception { + Field field = ByteString.class.getDeclaredField("byteArrayCopier"); + field.setAccessible(true); + Object byteArrayCopier = field.get(null); + assertNotNull(byteArrayCopier); + assertTrue( + byteArrayCopier.toString(), + byteArrayCopier.getClass().getSimpleName().endsWith("ArraysByteArrayCopier")); + } } diff --git a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java index 3d6381c9..cc65d19a 100644 --- a/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java +++ b/java/core/src/test/java/com/google/protobuf/CheckUtf8Test.java @@ -34,6 +34,7 @@ import proto2_test_check_utf8.TestCheckUtf8.BytesWrapper; import proto2_test_check_utf8.TestCheckUtf8.StringWrapper; import proto2_test_check_utf8_size.TestCheckUtf8Size.BytesWrapperSize; import proto2_test_check_utf8_size.TestCheckUtf8Size.StringWrapperSize; + import junit.framework.TestCase; /** diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java index 18d8142c..a1d6f1be 100644 --- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java +++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java @@ -547,6 +547,56 @@ public class CodedInputStreamTest extends TestCase { } } + public void testReadString() throws Exception { + String lorem = "Lorem ipsum dolor sit amet "; + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 4096; i += lorem.length()) { + builder.append(lorem); + } + lorem = builder.toString().substring(0, 4096); + byte[] bytes = lorem.getBytes("UTF-8"); + ByteString.Output rawOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length); + + int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); + output.writeRawVarint32(tag); + output.writeRawVarint32(bytes.length); + output.writeRawBytes(bytes); + output.flush(); + + CodedInputStream input = + CodedInputStream.newInstance( + new ByteArrayInputStream(rawOutput.toByteString().toByteArray())); + assertEquals(tag, input.readTag()); + String text = input.readString(); + assertEquals(lorem, text); + } + + public void testReadStringRequireUtf8() throws Exception { + String lorem = "Lorem ipsum dolor sit amet "; + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 4096; i += lorem.length()) { + builder.append(lorem); + } + lorem = builder.toString().substring(0, 4096); + byte[] bytes = lorem.getBytes("UTF-8"); + ByteString.Output rawOutput = ByteString.newOutput(); + CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length); + + int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); + output.writeRawVarint32(tag); + output.writeRawVarint32(bytes.length); + output.writeRawBytes(bytes); + output.flush(); + + CodedInputStream input = + CodedInputStream.newInstance( + new ByteArrayInputStream(rawOutput.toByteString().toByteArray())); + assertEquals(tag, input.readTag()); + String text = input.readStringRequireUtf8(); + assertEquals(lorem, text); + } + /** * Tests that if we readString invalid UTF-8 bytes, no exception * is thrown. Instead, the invalid bytes are replaced with the Unicode diff --git a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java index e7905f79..ce85ae2e 100644 --- a/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java +++ b/java/core/src/test/java/com/google/protobuf/DeprecatedFieldTest.java @@ -36,6 +36,7 @@ import junit.framework.TestCase; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Method; + /** * Test field deprecation * 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 82ff34af..ef89b389 100644 --- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -59,7 +59,6 @@ import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges; import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestReservedFields; import protobuf_unittest.UnittestProto.TestService; - import junit.framework.TestCase; import java.util.Arrays; @@ -573,6 +572,42 @@ public class DescriptorsTest extends TestCase { } } + public void testUnknownFieldsDenied() throws Exception { + FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() + .setName("foo.proto") + .addMessageType(DescriptorProto.newBuilder() + .setName("Foo") + .addField(FieldDescriptorProto.newBuilder() + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .setTypeName("Bar") + .setName("bar") + .setNumber(1))) + .build(); + + try { + Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]); + fail("DescriptorValidationException expected"); + } catch (DescriptorValidationException e) { + assertTrue(e.getMessage().indexOf("Bar") != -1); + assertTrue(e.getMessage().indexOf("is not defined") != -1); + } + } + + public void testUnknownFieldsAllowed() throws Exception { + FileDescriptorProto fooProto = FileDescriptorProto.newBuilder() + .setName("foo.proto") + .addDependency("bar.proto") + .addMessageType(DescriptorProto.newBuilder() + .setName("Foo") + .addField(FieldDescriptorProto.newBuilder() + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .setTypeName("Bar") + .setName("bar") + .setNumber(1))) + .build(); + Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true); + } + public void testHiddenDependency() throws Exception { FileDescriptorProto barProto = FileDescriptorProto.newBuilder() .setName("bar.proto") diff --git a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java index 55144e7c..8f3a74c1 100644 --- a/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java @@ -33,13 +33,13 @@ package com.google.protobuf; import com.google.protobuf.Descriptors.EnumDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.Descriptors.OneofDescriptor; - import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestEmptyMessage; import protobuf_unittest.UnittestProto.TestPackedTypes; import junit.framework.TestCase; + import java.util.Arrays; /** diff --git a/java/core/src/test/java/com/google/protobuf/EnumTest.java b/java/core/src/test/java/com/google/protobuf/EnumTest.java new file mode 100644 index 00000000..14c7406b --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/EnumTest.java @@ -0,0 +1,76 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.UnittestLite.ForeignEnumLite; +import com.google.protobuf.UnittestLite.TestAllTypesLite; +import protobuf_unittest.UnittestProto.ForeignEnum; +import protobuf_unittest.UnittestProto.TestAllTypes; + +import junit.framework.TestCase; + +public class EnumTest extends TestCase { + + public void testForNumber() { + ForeignEnum e = ForeignEnum.forNumber(ForeignEnum.FOREIGN_BAR.getNumber()); + assertEquals(ForeignEnum.FOREIGN_BAR, e); + + e = ForeignEnum.forNumber(1000); + assertEquals(null, e); + } + + public void testForNumber_oneof() { + TestAllTypes.OneofFieldCase e = TestAllTypes.OneofFieldCase.forNumber( + TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber()); + assertEquals(TestAllTypes.OneofFieldCase.ONEOF_NESTED_MESSAGE, e); + + e = TestAllTypes.OneofFieldCase.forNumber(1000); + assertEquals(null, e); + } + + public void testForNumberLite() { + ForeignEnumLite e = ForeignEnumLite.forNumber(ForeignEnumLite.FOREIGN_LITE_BAR.getNumber()); + assertEquals(ForeignEnumLite.FOREIGN_LITE_BAR, e); + + e = ForeignEnumLite.forNumber(1000); + assertEquals(null, e); + } + + public void testForNumberLite_oneof() { + TestAllTypesLite.OneofFieldCase e = TestAllTypesLite.OneofFieldCase.forNumber( + TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE.getNumber()); + assertEquals(TestAllTypesLite.OneofFieldCase.ONEOF_NESTED_MESSAGE, e); + + e = TestAllTypesLite.OneofFieldCase.forNumber(1000); + assertEquals(null, e); + } +} + diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java index eaeec0b8..304cec4f 100644 --- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java +++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java @@ -44,9 +44,9 @@ import junit.framework.TestCase; * non-message fields. */ public class FieldPresenceTest extends TestCase { - private static boolean hasMethod(Class clazz, String name) { + private static boolean hasMethod(Class clazz, String name) { try { - if (clazz.getMethod(name, new Class[]{}) != null) { + if (clazz.getMethod(name) != null) { return true; } else { return false; @@ -56,90 +56,90 @@ public class FieldPresenceTest extends TestCase { } } - private static boolean isHasMethodRemoved( - Class classWithFieldPresence, - Class classWithoutFieldPresence, + private static void assertHasMethodRemoved( + Class classWithFieldPresence, + Class classWithoutFieldPresence, String camelName) { - return hasMethod(classWithFieldPresence, "get" + camelName) - && hasMethod(classWithFieldPresence, "has" + camelName) - && hasMethod(classWithoutFieldPresence, "get" + camelName) - && !hasMethod(classWithoutFieldPresence, "has" + camelName); + assertTrue(hasMethod(classWithFieldPresence, "get" + camelName)); + assertTrue(hasMethod(classWithFieldPresence, "has" + camelName)); + assertTrue(hasMethod(classWithoutFieldPresence, "get" + camelName)); + assertFalse(hasMethod(classWithoutFieldPresence, "has" + camelName)); } public void testHasMethod() { // Optional non-message fields don't have a hasFoo() method generated. - assertTrue(isHasMethodRemoved( + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OptionalInt32")); - assertTrue(isHasMethodRemoved( + "OptionalInt32"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OptionalString")); - assertTrue(isHasMethodRemoved( + "OptionalString"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OptionalBytes")); - assertTrue(isHasMethodRemoved( + "OptionalBytes"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OptionalNestedEnum")); + "OptionalNestedEnum"); - assertTrue(isHasMethodRemoved( + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OptionalInt32")); - assertTrue(isHasMethodRemoved( + "OptionalInt32"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OptionalString")); - assertTrue(isHasMethodRemoved( + "OptionalString"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OptionalBytes")); - assertTrue(isHasMethodRemoved( + "OptionalBytes"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OptionalNestedEnum")); + "OptionalNestedEnum"); // message fields still have the hasFoo() method generated. assertFalse(TestAllTypes.newBuilder().build().hasOptionalNestedMessage()); assertFalse(TestAllTypes.newBuilder().hasOptionalNestedMessage()); // oneof fields don't have hasFoo() methods (even for message types). - assertTrue(isHasMethodRemoved( + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OneofUint32")); - assertTrue(isHasMethodRemoved( + "OneofUint32"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OneofString")); - assertTrue(isHasMethodRemoved( + "OneofString"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OneofBytes")); - assertTrue(isHasMethodRemoved( + "OneofBytes"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.class, TestAllTypes.class, - "OneofNestedMessage")); + "OneofNestedMessage"); - assertTrue(isHasMethodRemoved( + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OneofUint32")); - assertTrue(isHasMethodRemoved( + "OneofUint32"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OneofString")); - assertTrue(isHasMethodRemoved( + "OneofString"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OneofBytes")); - assertTrue(isHasMethodRemoved( + "OneofBytes"); + assertHasMethodRemoved( UnittestProto.TestAllTypes.Builder.class, TestAllTypes.Builder.class, - "OneofNestedMessage")); + "OneofNestedMessage"); } public void testOneofEquals() throws Exception { @@ -232,24 +232,24 @@ public class FieldPresenceTest extends TestCase { assertTrue(message.hasField(optionalNestedEnumField)); assertEquals(4, message.getAllFields().size()); } - + public void testMessageField() { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); assertFalse(builder.hasOptionalNestedMessage()); assertFalse(builder.build().hasOptionalNestedMessage()); - + TestAllTypes.NestedMessage.Builder nestedBuilder = builder.getOptionalNestedMessageBuilder(); assertTrue(builder.hasOptionalNestedMessage()); assertTrue(builder.build().hasOptionalNestedMessage()); - + nestedBuilder.setValue(1); assertEquals(1, builder.build().getOptionalNestedMessage().getValue()); - + builder.clearOptionalNestedMessage(); assertFalse(builder.hasOptionalNestedMessage()); assertFalse(builder.build().hasOptionalNestedMessage()); - + // Unlike non-message fields, if we set a message field to its default value (i.e., // default instance), the field should be seen as present. builder.setOptionalNestedMessage(TestAllTypes.NestedMessage.getDefaultInstance()); @@ -340,7 +340,7 @@ public class FieldPresenceTest extends TestCase { assertTrue(builder.buildPartial().isInitialized()); } - + // Test that unknown fields are dropped. public void testUnknownFields() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -348,7 +348,7 @@ public class FieldPresenceTest extends TestCase { builder.addRepeatedInt32(5678); TestAllTypes message = builder.build(); ByteString data = message.toByteString(); - + TestOptionalFieldsOnly optionalOnlyMessage = TestOptionalFieldsOnly.parseFrom(data); // UnknownFieldSet should be empty. @@ -360,7 +360,7 @@ public class FieldPresenceTest extends TestCase { // The repeated field is discarded because it's unknown to the optional-only // message. assertEquals(0, message.getRepeatedInt32Count()); - + DynamicMessage dynamicOptionalOnlyMessage = DynamicMessage.getDefaultInstance( TestOptionalFieldsOnly.getDescriptor()) diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 70812b95..8cd1f38d 100644 --- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -620,6 +620,21 @@ public class GeneratedMessageTest extends TestCase { TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build()); } + public void testUnsetRepeatedExtensionGetField() { + TestAllExtensions message = TestAllExtensions.getDefaultInstance(); + Object value; + + value = message.getField(UnittestProto.repeatedStringExtension.getDescriptor()); + assertTrue(value instanceof List); + assertTrue(((List) value).isEmpty()); + assertIsUnmodifiable((List) value); + + value = message.getField(UnittestProto.repeatedNestedMessageExtension.getDescriptor()); + assertTrue(value instanceof List); + assertTrue(((List) value).isEmpty()); + assertIsUnmodifiable((List) value); + } + public void testExtensionReflectionGetters() throws Exception { TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); TestUtil.setAllExtensions(builder); diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java index 8751baae..756049b4 100644 --- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java +++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8Test.java @@ -30,12 +30,18 @@ package com.google.protobuf; +import static com.google.protobuf.IsValidUtf8TestUtil.DIRECT_NIO_FACTORY; +import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT; +import static com.google.protobuf.IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT; +import static com.google.protobuf.IsValidUtf8TestUtil.HEAP_NIO_FACTORY; +import static com.google.protobuf.IsValidUtf8TestUtil.LITERAL_FACTORY; +import static com.google.protobuf.IsValidUtf8TestUtil.testBytes; + +import com.google.protobuf.IsValidUtf8TestUtil.ByteStringFactory; import com.google.protobuf.IsValidUtf8TestUtil.Shard; import junit.framework.TestCase; -import java.io.UnsupportedEncodingException; - /** * Tests cases for {@link ByteString#isValidUtf8()}. This includes three * brute force tests that actually test every permutation of one byte, two byte, @@ -51,31 +57,33 @@ import java.io.UnsupportedEncodingException; * @author martinrb@google.com (Martin Buchholz) */ public class IsValidUtf8Test extends TestCase { - /** * Tests that round tripping of all two byte permutations work. */ - public void testIsValidUtf8_1Byte() throws UnsupportedEncodingException { - IsValidUtf8TestUtil.testBytes(1, - IsValidUtf8TestUtil.EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); + public void testIsValidUtf8_1Byte() { + testBytes(LITERAL_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(HEAP_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(DIRECT_NIO_FACTORY, 1, EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT); } /** * Tests that round tripping of all two byte permutations work. */ - public void testIsValidUtf8_2Bytes() throws UnsupportedEncodingException { - IsValidUtf8TestUtil.testBytes(2, - IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); + public void testIsValidUtf8_2Bytes() { + testBytes(LITERAL_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(HEAP_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(DIRECT_NIO_FACTORY, 2, IsValidUtf8TestUtil.EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT); } /** * Tests that round tripping of all three byte permutations work. */ - public void testIsValidUtf8_3Bytes() throws UnsupportedEncodingException { + public void testIsValidUtf8_3Bytes() { // Travis' OOM killer doesn't like this test if (System.getenv("TRAVIS") == null) { - IsValidUtf8TestUtil.testBytes(3, - IsValidUtf8TestUtil.EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(LITERAL_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(HEAP_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); + testBytes(DIRECT_NIO_FACTORY, 3, EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT); } } @@ -85,8 +93,7 @@ public class IsValidUtf8Test extends TestCase { * {@link IsValidUtf8FourByteTest} is used for full coverage. This method * tests specific four-byte cases. */ - public void testIsValidUtf8_4BytesSamples() - throws UnsupportedEncodingException { + public void testIsValidUtf8_4BytesSamples() { // Valid 4 byte. assertValidUtf8(0xF0, 0xA4, 0xAD, 0xA2); @@ -119,9 +126,7 @@ public class IsValidUtf8Test extends TestCase { assertTrue(asBytes("\u024B62\u024B62").isValidUtf8()); // Mixed string - assertTrue( - asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62") - .isValidUtf8()); + assertTrue(asBytes("a\u020ac\u00a2b\\u024B62u020acc\u00a2de\u024B62").isValidUtf8()); // Not a valid string assertInvalidUtf8(-1, 0, -1, 0); @@ -135,36 +140,35 @@ public class IsValidUtf8Test extends TestCase { return realBytes; } - private ByteString toByteString(int... bytes) { - return ByteString.copyFrom(toByteArray(bytes)); - } - - private void assertValidUtf8(int[] bytes, boolean not) { + private void assertValidUtf8(ByteStringFactory factory, int[] bytes, boolean not) { byte[] realBytes = toByteArray(bytes); assertTrue(not ^ Utf8.isValidUtf8(realBytes)); assertTrue(not ^ Utf8.isValidUtf8(realBytes, 0, bytes.length)); - ByteString lit = ByteString.copyFrom(realBytes); - ByteString sub = lit.substring(0, bytes.length); - assertTrue(not ^ lit.isValidUtf8()); + ByteString leaf = factory.newByteString(realBytes); + ByteString sub = leaf.substring(0, bytes.length); + assertTrue(not ^ leaf.isValidUtf8()); assertTrue(not ^ sub.isValidUtf8()); ByteString[] ropes = { - RopeByteString.newInstanceForTest(ByteString.EMPTY, lit), - RopeByteString.newInstanceForTest(ByteString.EMPTY, sub), - RopeByteString.newInstanceForTest(lit, ByteString.EMPTY), - RopeByteString.newInstanceForTest(sub, ByteString.EMPTY), - RopeByteString.newInstanceForTest(sub, lit) - }; + RopeByteString.newInstanceForTest(ByteString.EMPTY, leaf), + RopeByteString.newInstanceForTest(ByteString.EMPTY, sub), + RopeByteString.newInstanceForTest(leaf, ByteString.EMPTY), + RopeByteString.newInstanceForTest(sub, ByteString.EMPTY), + RopeByteString.newInstanceForTest(sub, leaf)}; for (ByteString rope : ropes) { assertTrue(not ^ rope.isValidUtf8()); } } private void assertValidUtf8(int... bytes) { - assertValidUtf8(bytes, false); + assertValidUtf8(LITERAL_FACTORY, bytes, false); + assertValidUtf8(HEAP_NIO_FACTORY, bytes, false); + assertValidUtf8(DIRECT_NIO_FACTORY, bytes, false); } private void assertInvalidUtf8(int... bytes) { - assertValidUtf8(bytes, true); + assertValidUtf8(LITERAL_FACTORY, bytes, true); + assertValidUtf8(HEAP_NIO_FACTORY, bytes, true); + assertValidUtf8(DIRECT_NIO_FACTORY, bytes, true); } private static ByteString asBytes(String s) { @@ -177,7 +181,6 @@ public class IsValidUtf8Test extends TestCase { for (Shard shard : IsValidUtf8TestUtil.FOUR_BYTE_SHARDS) { actual += shard.expected; } - assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, - actual); + assertEquals(IsValidUtf8TestUtil.EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT, actual); } } diff --git a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java index 321669f3..16a808bf 100644 --- a/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java +++ b/java/core/src/test/java/com/google/protobuf/IsValidUtf8TestUtil.java @@ -30,9 +30,13 @@ package com.google.protobuf; -import static junit.framework.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import java.io.UnsupportedEncodingException; +import java.lang.ref.SoftReference; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; @@ -52,64 +56,105 @@ import java.util.logging.Logger; * @author jonp@google.com (Jon Perlow) * @author martinrb@google.com (Martin Buchholz) */ -class IsValidUtf8TestUtil { - private static Logger logger = Logger.getLogger( - IsValidUtf8TestUtil.class.getName()); +final class IsValidUtf8TestUtil { + private static Logger logger = Logger.getLogger(IsValidUtf8TestUtil.class.getName()); + + private IsValidUtf8TestUtil() {} + + static interface ByteStringFactory { + ByteString newByteString(byte[] bytes); + } + + static final ByteStringFactory LITERAL_FACTORY = new ByteStringFactory() { + @Override + public ByteString newByteString(byte[] bytes) { + return ByteString.wrap(bytes); + } + }; + + static final ByteStringFactory HEAP_NIO_FACTORY = new ByteStringFactory() { + @Override + public ByteString newByteString(byte[] bytes) { + return new NioByteString(ByteBuffer.wrap(bytes)); + } + }; + + private static ThreadLocal> directBuffer = + new ThreadLocal>(); + + /** + * Factory for direct {@link ByteBuffer} instances. To reduce direct memory usage, this + * uses a thread local direct buffer. This means that each call will overwrite the buffer's + * contents from the previous call, so the calling code must be careful not to continue using + * a buffer returned from a previous invocation. + */ + static final ByteStringFactory DIRECT_NIO_FACTORY = new ByteStringFactory() { + @Override + public ByteString newByteString(byte[] bytes) { + SoftReference ref = directBuffer.get(); + ByteBuffer buffer = ref == null ? null : ref.get(); + if (buffer == null || buffer.capacity() < bytes.length) { + buffer = ByteBuffer.allocateDirect(bytes.length); + directBuffer.set(new SoftReference(buffer)); + } + buffer.clear(); + buffer.put(bytes); + buffer.flip(); + return new NioByteString(buffer); + } + }; // 128 - [chars 0x0000 to 0x007f] - static long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1; + static final long ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x007f - 0x0000 + 1; // 128 - static long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT = - ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS; + static final long EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT = ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS; // 1920 [chars 0x0080 to 0x07FF] - static long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1; + static final long TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x07FF - 0x0080 + 1; // 18,304 - static long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT = + static final long EXPECTED_TWO_BYTE_ROUNDTRIPPABLE_COUNT = // Both bytes are one byte characters (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 2) + // The possible number of two byte characters TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS; // 2048 - static long THREE_BYTE_SURROGATES = 2 * 1024; + static final long THREE_BYTE_SURROGATES = 2 * 1024; // 61,440 [chars 0x0800 to 0xFFFF, minus surrogates] - static long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS = + static final long THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0xFFFF - 0x0800 + 1 - THREE_BYTE_SURROGATES; // 2,650,112 - static long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT = + static final long EXPECTED_THREE_BYTE_ROUNDTRIPPABLE_COUNT = // All one byte characters (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 3) + // One two byte character and a one byte character - 2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * - ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS + - // Three byte characters + 2 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS + + // Three byte characters THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS; // 1,048,576 [chars 0x10000L to 0x10FFFF] - static long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1; + static final long FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS = 0x10FFFF - 0x10000L + 1; // 289,571,839 - static long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT = + static final long EXPECTED_FOUR_BYTE_ROUNDTRIPPABLE_COUNT = // All one byte characters (long) Math.pow(EXPECTED_ONE_BYTE_ROUNDTRIPPABLE_COUNT, 4) + // One and three byte characters - 2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS * - ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS + + 2 * THREE_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS + // Two two byte characters TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS + // Permutations of one and two byte characters - 3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * - ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS * - ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS + + 3 * TWO_BYTE_ROUNDTRIPPABLE_CHARACTERS * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS + * ONE_BYTE_ROUNDTRIPPABLE_CHARACTERS + + // Four byte characters FOUR_BYTE_ROUNDTRIPPABLE_CHARACTERS; - static class Shard { + static final class Shard { final long index; final long start; final long lim; @@ -138,7 +183,7 @@ class IsValidUtf8TestUtil { // 97-111 are all 2342912 for (int i = 97; i <= 111; i++) { - expected[i] = 2342912; + expected[i] = 2342912; } // 113-117 are all 1048576 @@ -158,22 +203,18 @@ class IsValidUtf8TestUtil { return expected; } - static final List FOUR_BYTE_SHARDS = generateFourByteShards( - 128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES); + static final List FOUR_BYTE_SHARDS = + generateFourByteShards(128, FOUR_BYTE_SHARDS_EXPECTED_ROUNTRIPPABLES); - private static List generateFourByteShards( - int numShards, long[] expected) { + private static List generateFourByteShards(int numShards, long[] expected) { assertEquals(numShards, expected.length); List shards = new ArrayList(numShards); long LIM = 1L << 32; long increment = LIM / numShards; assertTrue(LIM % numShards == 0); for (int i = 0; i < numShards; i++) { - shards.add(new Shard(i, - increment * i, - increment * (i + 1), - expected[i])); + shards.add(new Shard(i, increment * i, increment * (i + 1), expected[i])); } return shards; } @@ -182,12 +223,12 @@ class IsValidUtf8TestUtil { * Helper to run the loop to test all the permutations for the number of bytes * specified. * + * @param factory the factory for {@link ByteString} instances. * @param numBytes the number of bytes in the byte array * @param expectedCount the expected number of roundtrippable permutations */ - static void testBytes(int numBytes, long expectedCount) - throws UnsupportedEncodingException { - testBytes(numBytes, expectedCount, 0, -1); + static void testBytes(ByteStringFactory factory, int numBytes, long expectedCount) { + testBytes(factory, numBytes, expectedCount, 0, -1); } /** @@ -195,14 +236,15 @@ class IsValidUtf8TestUtil { * specified. This overload is useful for debugging to get the loop to start * at a certain character. * + * @param factory the factory for {@link ByteString} instances. * @param numBytes the number of bytes in the byte array * @param expectedCount the expected number of roundtrippable permutations * @param start the starting bytes encoded as a long as big-endian * @param lim the limit of bytes to process encoded as a long as big-endian, * or -1 to mean the max limit for numBytes */ - static void testBytes(int numBytes, long expectedCount, long start, long lim) - throws UnsupportedEncodingException { + static void testBytes( + ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) { Random rnd = new Random(); byte[] bytes = new byte[numBytes]; @@ -217,7 +259,7 @@ class IsValidUtf8TestUtil { bytes[bytes.length - i - 1] = (byte) tmpByteChar; tmpByteChar = tmpByteChar >> 8; } - ByteString bs = ByteString.copyFrom(bytes); + ByteString bs = factory.newByteString(bytes); boolean isRoundTrippable = bs.isValidUtf8(); String s = new String(bytes, Internal.UTF_8); byte[] bytesReencoded = s.getBytes(Internal.UTF_8); @@ -236,14 +278,15 @@ class IsValidUtf8TestUtil { int i = rnd.nextInt(numBytes); int j = rnd.nextInt(numBytes); if (j < i) { - int tmp = i; i = j; j = tmp; + int tmp = i; + i = j; + j = tmp; } int state1 = Utf8.partialIsValidUtf8(Utf8.COMPLETE, bytes, 0, i); int state2 = Utf8.partialIsValidUtf8(state1, bytes, i, j); int state3 = Utf8.partialIsValidUtf8(state2, bytes, j, numBytes); if (isRoundTrippable != (state3 == Utf8.COMPLETE)) { - System.out.printf("state=%04x %04x %04x i=%d j=%d%n", - state1, state2, state3, i, j); + System.out.printf("state=%04x %04x %04x i=%d j=%d%n", state1, state2, state3, i, j); outputFailure(byteChar, bytes, bytesReencoded); } assertEquals(isRoundTrippable, (state3 == Utf8.COMPLETE)); @@ -251,36 +294,24 @@ class IsValidUtf8TestUtil { // Test ropes built out of small partial sequences ByteString rope = RopeByteString.newInstanceForTest( bs.substring(0, i), - RopeByteString.newInstanceForTest( - bs.substring(i, j), - bs.substring(j, numBytes))); + RopeByteString.newInstanceForTest(bs.substring(i, j), bs.substring(j, numBytes))); assertSame(RopeByteString.class, rope.getClass()); - ByteString[] byteStrings = { bs, bs.substring(0, numBytes), rope }; + ByteString[] byteStrings = {bs, bs.substring(0, numBytes), rope}; for (ByteString x : byteStrings) { - assertEquals(isRoundTrippable, - x.isValidUtf8()); - assertEquals(state3, - x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes)); + assertEquals(isRoundTrippable, x.isValidUtf8()); + assertEquals(state3, x.partialIsValidUtf8(Utf8.COMPLETE, 0, numBytes)); - assertEquals(state1, - x.partialIsValidUtf8(Utf8.COMPLETE, 0, i)); - assertEquals(state1, - x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i)); - assertEquals(state2, - x.partialIsValidUtf8(state1, i, j - i)); - assertEquals(state2, - x.substring(i, j).partialIsValidUtf8(state1, 0, j - i)); - assertEquals(state3, - x.partialIsValidUtf8(state2, j, numBytes - j)); - assertEquals(state3, - x.substring(j, numBytes) - .partialIsValidUtf8(state2, 0, numBytes - j)); + assertEquals(state1, x.partialIsValidUtf8(Utf8.COMPLETE, 0, i)); + assertEquals(state1, x.substring(0, i).partialIsValidUtf8(Utf8.COMPLETE, 0, i)); + assertEquals(state2, x.partialIsValidUtf8(state1, i, j - i)); + assertEquals(state2, x.substring(i, j).partialIsValidUtf8(state1, 0, j - i)); + assertEquals(state3, x.partialIsValidUtf8(state2, j, numBytes - j)); + assertEquals(state3, x.substring(j, numBytes).partialIsValidUtf8(state2, 0, numBytes - j)); } // ByteString reduplication should not affect its UTF-8 validity. - ByteString ropeADope = - RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes)); + ByteString ropeADope = RopeByteString.newInstanceForTest(bs, bs.substring(0, numBytes)); assertEquals(isRoundTrippable, ropeADope.isValidUtf8()); if (isRoundTrippable) { @@ -288,8 +319,7 @@ class IsValidUtf8TestUtil { } count++; if (byteChar != 0 && byteChar % 1000000L == 0) { - logger.info("Processed " + (byteChar / 1000000L) + - " million characters"); + logger.info("Processed " + (byteChar / 1000000L) + " million characters"); } } logger.info("Round tripped " + countRoundTripped + " of " + count); @@ -303,25 +333,26 @@ class IsValidUtf8TestUtil { * actual String class, it's possible for incompatibilities to develop * (although unlikely). * + * @param factory the factory for {@link ByteString} instances. * @param numBytes the number of bytes in the byte array * @param expectedCount the expected number of roundtrippable permutations * @param start the starting bytes encoded as a long as big-endian * @param lim the limit of bytes to process encoded as a long as big-endian, * or -1 to mean the max limit for numBytes */ - void testBytesUsingByteBuffers( - int numBytes, long expectedCount, long start, long lim) - throws UnsupportedEncodingException { - CharsetDecoder decoder = Internal.UTF_8.newDecoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - CharsetEncoder encoder = Internal.UTF_8.newEncoder() - .onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); + static void testBytesUsingByteBuffers( + ByteStringFactory factory, int numBytes, long expectedCount, long start, long lim) { + CharsetDecoder decoder = + Internal.UTF_8.newDecoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); + CharsetEncoder encoder = + Internal.UTF_8.newEncoder() + .onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); byte[] bytes = new byte[numBytes]; int maxChars = (int) (decoder.maxCharsPerByte() * numBytes) + 1; - char[] charsDecoded = - new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1]; + char[] charsDecoded = new char[(int) (decoder.maxCharsPerByte() * numBytes) + 1]; int maxBytes = (int) (encoder.maxBytesPerChar() * maxChars) + 1; byte[] bytesReencoded = new byte[maxBytes]; @@ -347,7 +378,7 @@ class IsValidUtf8TestUtil { bytes[bytes.length - i - 1] = (byte) tmpByteChar; tmpByteChar = tmpByteChar >> 8; } - boolean isRoundTrippable = ByteString.copyFrom(bytes).isValidUtf8(); + boolean isRoundTrippable = factory.newByteString(bytes).isValidUtf8(); CoderResult result = decoder.decode(bb, cb, true); assertFalse(result.isError()); result = decoder.flush(cb); @@ -382,8 +413,7 @@ class IsValidUtf8TestUtil { countRoundTripped++; } if (byteChar != 0 && byteChar % 1000000 == 0) { - logger.info("Processed " + (byteChar / 1000000) + - " million characters"); + logger.info("Processed " + (byteChar / 1000000) + " million characters"); } } logger.info("Round tripped " + countRoundTripped + " of " + count); @@ -394,10 +424,9 @@ class IsValidUtf8TestUtil { outputFailure(byteChar, bytes, after, after.length); } - private static void outputFailure(long byteChar, byte[] bytes, byte[] after, - int len) { - fail("Failure: (" + Long.toHexString(byteChar) + ") " + - toHexString(bytes) + " => " + toHexString(after, len)); + private static void outputFailure(long byteChar, byte[] bytes, byte[] after, int len) { + fail("Failure: (" + Long.toHexString(byteChar) + ") " + toHexString(bytes) + " => " + + toHexString(after, len)); } private static String toHexString(byte[] b) { @@ -416,5 +445,4 @@ class IsValidUtf8TestUtil { s.append("\""); return s.toString(); } - } diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java index 211b5697..8d1de6dc 100644 --- a/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java +++ b/java/core/src/test/java/com/google/protobuf/LazyFieldLiteTest.java @@ -36,9 +36,10 @@ import static protobuf_unittest.UnittestProto.optionalInt64Extension; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; -import java.io.IOException; import junit.framework.TestCase; +import java.io.IOException; + /** * Unit test for {@link LazyFieldLite}. * diff --git a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java index 2b900065..ce473ae9 100644 --- a/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java +++ b/java/core/src/test/java/com/google/protobuf/LazyFieldTest.java @@ -33,9 +33,10 @@ package com.google.protobuf; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; -import java.io.IOException; import junit.framework.TestCase; +import java.io.IOException; + /** * Unit test for {@link LazyField}. * diff --git a/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java index 035917c8..29e8d875 100644 --- a/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java +++ b/java/core/src/test/java/com/google/protobuf/LiteEqualsAndHashTest.java @@ -33,6 +33,8 @@ package com.google.protobuf; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime; import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof; import junit.framework.TestCase; @@ -83,6 +85,16 @@ public class LiteEqualsAndHashTest extends TestCase { assertFalse(bar.equals(barPrime)); } + public void testOneofEquals() throws Exception { + TestOneofEquals.Builder builder = TestOneofEquals.newBuilder(); + TestOneofEquals message1 = builder.build(); + // Set message2's name field to default value. The two messages should be different when we + // check with the oneof case. + builder.setName(""); + TestOneofEquals message2 = builder.build(); + assertFalse(message1.equals(message2)); + } + public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException { Foo fooWithOnlyValue = Foo.newBuilder() .setValue(1) @@ -105,4 +117,9 @@ public class LiteEqualsAndHashTest extends TestCase { assertFalse(o1.equals(o2)); assertFalse(o1.hashCode() == o2.hashCode()); } + + public void testRecursiveHashcode() { + // This tests that we don't infinite loop. + TestRecursiveOneof.getDefaultInstance().hashCode(); + } } diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java index b1f298ff..9e503cc3 100644 --- a/java/core/src/test/java/com/google/protobuf/LiteTest.java +++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java @@ -49,6 +49,7 @@ import junit.framework.TestCase; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.NotSerializableException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -128,33 +129,7 @@ public class LiteTest extends TestCase { assertEquals(7, message2.getExtension( UnittestLite.optionalNestedMessageExtensionLite).getBb()); } - - public void testSerialize() throws Exception { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - TestAllTypesLite expected = - TestAllTypesLite.newBuilder() - .setOptionalInt32(123) - .addRepeatedString("hello") - .setOptionalNestedMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(7)) - .build(); - ObjectOutputStream out = new ObjectOutputStream(baos); - try { - out.writeObject(expected); - } finally { - out.close(); - } - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); - ObjectInputStream in = new ObjectInputStream(bais); - TestAllTypesLite actual = (TestAllTypesLite) in.readObject(); - assertEquals(expected.getOptionalInt32(), actual.getOptionalInt32()); - assertEquals(expected.getRepeatedStringCount(), - actual.getRepeatedStringCount()); - assertEquals(expected.getRepeatedString(0), - actual.getRepeatedString(0)); - assertEquals(expected.getOptionalNestedMessage().getBb(), - actual.getOptionalNestedMessage().getBb()); - } + public void testClone() { TestAllTypesLite.Builder expected = TestAllTypesLite.newBuilder() @@ -1459,4 +1434,168 @@ public class LiteTest extends TestCase { 11, (int) extendableMessage.getExtension( UnittestLite.optionalFixed32ExtensionLite)); } + + public void testToStringDefaultInstance() throws Exception { + assertToStringEquals("", TestAllTypesLite.getDefaultInstance()); + } + + public void testToStringPrimitives() throws Exception { + TestAllTypesLite proto = TestAllTypesLite.newBuilder() + .setOptionalInt32(1) + .setOptionalInt64(9223372036854775807L) + .build(); + assertToStringEquals("optional_int32: 1\noptional_int64: 9223372036854775807", proto); + + proto = TestAllTypesLite.newBuilder() + .setOptionalBool(true) + .setOptionalNestedEnum(TestAllTypesLite.NestedEnum.BAZ) + .build(); + assertToStringEquals("optional_bool: true\noptional_nested_enum: BAZ", proto); + + proto = TestAllTypesLite.newBuilder() + .setOptionalFloat(2.72f) + .setOptionalDouble(3.14) + .build(); + assertToStringEquals("optional_float: 2.72\noptional_double: 3.14", proto); + } + + public void testToStringStringFields() throws Exception { + TestAllTypesLite proto = TestAllTypesLite.newBuilder() + .setOptionalString("foo\"bar\nbaz\\") + .build(); + assertToStringEquals("optional_string: \"foo\\\"bar\\nbaz\\\\\"", proto); + + proto = TestAllTypesLite.newBuilder() + .setOptionalString("\u6587") + .build(); + assertToStringEquals("optional_string: \"\\346\\226\\207\"", proto); + } + + public void testToStringNestedMessage() throws Exception { + TestAllTypesLite proto = TestAllTypesLite.newBuilder() + .setOptionalNestedMessage(TestAllTypesLite.NestedMessage.getDefaultInstance()) + .build(); + assertToStringEquals("optional_nested_message {\n}", proto); + + proto = TestAllTypesLite.newBuilder() + .setOptionalNestedMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(7)) + .build(); + assertToStringEquals("optional_nested_message {\n bb: 7\n}", proto); + } + + public void testToStringRepeatedFields() throws Exception { + TestAllTypesLite proto = TestAllTypesLite.newBuilder() + .addRepeatedInt32(32) + .addRepeatedInt32(32) + .addRepeatedInt64(64) + .build(); + assertToStringEquals("repeated_int32: 32\nrepeated_int32: 32\nrepeated_int64: 64", proto); + + proto = TestAllTypesLite.newBuilder() + .addRepeatedLazyMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(7)) + .addRepeatedLazyMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(8)) + .build(); + assertToStringEquals( + "repeated_lazy_message {\n bb: 7\n}\nrepeated_lazy_message {\n bb: 8\n}", + proto); + } + + public void testToStringForeignFields() throws Exception { + TestAllTypesLite proto = TestAllTypesLite.newBuilder() + .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR) + .setOptionalForeignMessage( + ForeignMessageLite.newBuilder() + .setC(3)) + .build(); + assertToStringEquals( + "optional_foreign_message {\n c: 3\n}\noptional_foreign_enum: FOREIGN_LITE_BAR", + proto); + } + + public void testToStringExtensions() throws Exception { + TestAllExtensionsLite message = TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalInt32ExtensionLite, 123) + .addExtension(UnittestLite.repeatedStringExtensionLite, "spam") + .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs") + .setExtension(UnittestLite.optionalNestedEnumExtensionLite, + TestAllTypesLite.NestedEnum.BAZ) + .setExtension(UnittestLite.optionalNestedMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build()) + .build(); + assertToStringEquals( + "[1]: 123\n[18] {\n bb: 7\n}\n[21]: 3\n[44]: \"spam\"\n[44]: \"eggs\"", + message); + } + + public void testToStringUnknownFields() throws Exception { + TestAllExtensionsLite messageWithExtensions = TestAllExtensionsLite.newBuilder() + .setExtension(UnittestLite.optionalInt32ExtensionLite, 123) + .addExtension(UnittestLite.repeatedStringExtensionLite, "spam") + .addExtension(UnittestLite.repeatedStringExtensionLite, "eggs") + .setExtension(UnittestLite.optionalNestedEnumExtensionLite, + TestAllTypesLite.NestedEnum.BAZ) + .setExtension(UnittestLite.optionalNestedMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build()) + .build(); + TestAllExtensionsLite messageWithUnknownFields = TestAllExtensionsLite.parseFrom( + messageWithExtensions.toByteArray()); + assertToStringEquals( + "1: 123\n18: \"\\b\\a\"\n21: 3\n44: \"spam\"\n44: \"eggs\"", + messageWithUnknownFields); + } + + // Asserts that the toString() representation of the message matches the expected. This verifies + // the first line starts with a comment; but, does not factor in said comment as part of the + // comparison as it contains unstable addresses. + private static void assertToStringEquals(String expected, MessageLite message) { + String toString = message.toString(); + assertEquals('#', toString.charAt(0)); + if (toString.indexOf("\n") >= 0) { + toString = toString.substring(toString.indexOf("\n") + 1); + } else { + toString = ""; + } + assertEquals(expected, toString); + } + + public void testParseLazy() throws Exception { + ByteString bb = TestAllTypesLite.newBuilder() + .setOptionalLazyMessage(NestedMessage.newBuilder() + .setBb(11) + .build()) + .build().toByteString(); + ByteString cc = TestAllTypesLite.newBuilder() + .setOptionalLazyMessage(NestedMessage.newBuilder() + .setCc(22) + .build()) + .build().toByteString(); + + ByteString concat = bb.concat(cc); + TestAllTypesLite message = TestAllTypesLite.parseFrom(concat); + + assertEquals(11, message.getOptionalLazyMessage().getBb()); + assertEquals(22L, message.getOptionalLazyMessage().getCc()); + } + + public void testParseLazy_oneOf() throws Exception { + ByteString bb = TestAllTypesLite.newBuilder() + .setOneofLazyNestedMessage(NestedMessage.newBuilder() + .setBb(11) + .build()) + .build().toByteString(); + ByteString cc = TestAllTypesLite.newBuilder() + .setOneofLazyNestedMessage(NestedMessage.newBuilder() + .setCc(22) + .build()) + .build().toByteString(); + + ByteString concat = bb.concat(cc); + TestAllTypesLite message = TestAllTypesLite.parseFrom(concat); + + assertEquals(11, message.getOneofLazyNestedMessage().getBb()); + assertEquals(22L, message.getOneofLazyNestedMessage().getCc()); + } } diff --git a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java index 68b55ceb..2e7792a8 100644 --- a/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java +++ b/java/core/src/test/java/com/google/protobuf/LiteralByteStringTest.java @@ -47,9 +47,9 @@ import java.util.List; import java.util.NoSuchElementException; /** - * Test {@link LiteralByteString} by setting up a reference string in {@link #setUp()}. - * This class is designed to be extended for testing extensions of {@link LiteralByteString} - * such as {@link BoundedByteString}, see {@link BoundedByteStringTest}. + * Test {@code LiteralByteString} by setting up a reference string in {@link #setUp()}. + * This class is designed to be extended for testing extensions of {@code LiteralByteString} + * such as {@code BoundedByteString}, see {@link BoundedByteStringTest}. * * @author carlanton@google.com (Carl Haverl) */ @@ -304,25 +304,75 @@ public class LiteralByteStringTest extends TestCase { Arrays.equals(referenceBytes, roundTripBytes)); } - public void testWriteTo_mutating() throws IOException { + public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException { OutputStream os = new OutputStream() { @Override public void write(byte[] b, int off, int len) { - for (int x = 0; x < len; ++x) { - b[off + x] = (byte) 0; - } + Arrays.fill(b, off, off + len, (byte) 0); } @Override public void write(int b) { - // Purposefully left blank. + throw new UnsupportedOperationException(); } }; stringUnderTest.writeTo(os); - byte[] newBytes = stringUnderTest.toByteArray(); assertTrue(classUnderTest + ".writeTo() must not grant access to underlying array", - Arrays.equals(referenceBytes, newBytes)); + Arrays.equals(referenceBytes, stringUnderTest.toByteArray())); + } + + public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException { + OutputStream os = new OutputStream() { + @Override + public void write(byte[] b, int off, int len) { + Arrays.fill(b, off, off + len, (byte) 0); + } + + @Override + public void write(int b) { + throw new UnsupportedOperationException(); + } + }; + + stringUnderTest.writeToInternal(os, 0, stringUnderTest.size()); + byte[] allZeros = new byte[stringUnderTest.size()]; + assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array", + Arrays.equals(allZeros, stringUnderTest.toByteArray())); + } + + public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException { + ByteOutput out = new ByteOutput() { + @Override + public void write(byte value) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void write(byte[] value, int offset, int length) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void writeLazy(byte[] value, int offset, int length) throws IOException { + Arrays.fill(value, offset, offset + length, (byte) 0); + } + + @Override + public void write(ByteBuffer value) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void writeLazy(ByteBuffer value) throws IOException { + throw new UnsupportedOperationException(); + } + }; + + stringUnderTest.writeTo(out); + byte[] allZeros = new byte[stringUnderTest.size()]; + assertTrue(classUnderTest + ".writeToInternal() must grant access to underlying array", + Arrays.equals(allZeros, stringUnderTest.toByteArray())); } public void testNewOutput() throws IOException { diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java index 3d8c9bc4..d79d0029 100644 --- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java +++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java @@ -432,7 +432,7 @@ public class MapForProto2LiteTest extends TestCase { assertEquals(1, messageWithUnknownEnums.getInt32ToInt32Field().get(1).intValue()); assertEquals(54321, messageWithUnknownEnums.getInt32ToInt32Field().get(2).intValue()); } - + public void testIterationOrder() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java index 1fa3cbdb..73154c0f 100644 --- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java +++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java @@ -36,7 +36,6 @@ import map_test.MapForProto2TestProto.TestMap.MessageValue; import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields; import map_test.MapForProto2TestProto.TestRecursiveMap; import map_test.MapForProto2TestProto.TestUnknownEnumValue; - import junit.framework.TestCase; import java.util.ArrayList; diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java index 0e5c1284..1dc5787d 100644 --- a/java/core/src/test/java/com/google/protobuf/MapTest.java +++ b/java/core/src/test/java/com/google/protobuf/MapTest.java @@ -37,7 +37,6 @@ import com.google.protobuf.Descriptors.FieldDescriptor; import map_test.MapTestProto.TestMap; import map_test.MapTestProto.TestMap.MessageValue; import map_test.MapTestProto.TestOnChangeEventPropagation; - import junit.framework.TestCase; import java.util.ArrayList; diff --git a/java/core/src/test/java/com/google/protobuf/MessageTest.java b/java/core/src/test/java/com/google/protobuf/MessageTest.java index abcd3a1d..dcd1aba7 100644 --- a/java/core/src/test/java/com/google/protobuf/MessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/MessageTest.java @@ -30,11 +30,11 @@ package com.google.protobuf; -import protobuf_unittest.UnittestProto.TestAllTypes; +import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.TestAllExtensions; +import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestRequired; import protobuf_unittest.UnittestProto.TestRequiredForeign; -import protobuf_unittest.UnittestProto.ForeignMessage; import junit.framework.TestCase; diff --git a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java index 23653126..542e28c0 100644 --- a/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java +++ b/java/core/src/test/java/com/google/protobuf/NestedBuildersTest.java @@ -35,8 +35,8 @@ import protobuf_unittest.Wheel; import junit.framework.TestCase; -import java.util.List; import java.util.ArrayList; +import java.util.List; /** * Test cases that exercise end-to-end use cases involving diff --git a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java index e40a3662..6be5b93c 100644 --- a/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java +++ b/java/core/src/test/java/com/google/protobuf/NioByteStringTest.java @@ -41,6 +41,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; @@ -56,11 +57,12 @@ public class NioByteStringTest extends TestCase { private static final String CLASSNAME = NioByteString.class.getSimpleName(); private static final byte[] BYTES = ByteStringTest.getTestBytes(1234, 11337766L); private static final int EXPECTED_HASH = ByteString.wrap(BYTES).hashCode(); - private static final ByteBuffer BUFFER = ByteBuffer.wrap(BYTES.clone()); - private static final ByteString TEST_STRING = new NioByteString(BUFFER); + + private final ByteBuffer backingBuffer = ByteBuffer.wrap(BYTES.clone()); + private final ByteString testString = new NioByteString(backingBuffer); public void testExpectedType() { - String actualClassName = getActualClassName(TEST_STRING); + String actualClassName = getActualClassName(testString); assertEquals(CLASSNAME + " should match type exactly", CLASSNAME, actualClassName); } @@ -73,14 +75,14 @@ public class NioByteStringTest extends TestCase { public void testByteAt() { boolean stillEqual = true; for (int i = 0; stillEqual && i < BYTES.length; ++i) { - stillEqual = (BYTES[i] == TEST_STRING.byteAt(i)); + stillEqual = (BYTES[i] == testString.byteAt(i)); } assertTrue(CLASSNAME + " must capture the right bytes", stillEqual); } public void testByteIterator() { boolean stillEqual = true; - ByteString.ByteIterator iter = TEST_STRING.iterator(); + ByteString.ByteIterator iter = testString.iterator(); for (int i = 0; stillEqual && i < BYTES.length; ++i) { stillEqual = (iter.hasNext() && BYTES[i] == iter.nextByte()); } @@ -98,7 +100,7 @@ public class NioByteStringTest extends TestCase { public void testByteIterable() { boolean stillEqual = true; int j = 0; - for (byte quantum : TEST_STRING) { + for (byte quantum : testString) { stillEqual = (BYTES[j] == quantum); ++j; } @@ -108,15 +110,15 @@ public class NioByteStringTest extends TestCase { public void testSize() { assertEquals(CLASSNAME + " must have the expected size", BYTES.length, - TEST_STRING.size()); + testString.size()); } public void testGetTreeDepth() { - assertEquals(CLASSNAME + " must have depth 0", 0, TEST_STRING.getTreeDepth()); + assertEquals(CLASSNAME + " must have depth 0", 0, testString.getTreeDepth()); } public void testIsBalanced() { - assertTrue(CLASSNAME + " is technically balanced", TEST_STRING.isBalanced()); + assertTrue(CLASSNAME + " is technically balanced", testString.isBalanced()); } public void testCopyTo_ByteArrayOffsetLength() { @@ -124,7 +126,7 @@ public class NioByteStringTest extends TestCase { int length = 100; byte[] destination = new byte[destinationOffset + length]; int sourceOffset = 213; - TEST_STRING.copyTo(destination, sourceOffset, destinationOffset, length); + testString.copyTo(destination, sourceOffset, destinationOffset, length); boolean stillEqual = true; for (int i = 0; stillEqual && i < length; ++i) { stillEqual = BYTES[i + sourceOffset] == destination[i + destinationOffset]; @@ -139,7 +141,7 @@ public class NioByteStringTest extends TestCase { try { // Copy one too many bytes - TEST_STRING.copyTo(destination, TEST_STRING.size() + 1 - length, + testString.copyTo(destination, testString.size() + 1 - length, destinationOffset, length); fail("Should have thrown an exception when copying too many bytes of a " + CLASSNAME); @@ -149,7 +151,7 @@ public class NioByteStringTest extends TestCase { try { // Copy with illegal negative sourceOffset - TEST_STRING.copyTo(destination, -1, destinationOffset, length); + testString.copyTo(destination, -1, destinationOffset, length); fail("Should have thrown an exception when given a negative sourceOffset in " + CLASSNAME); } catch (IndexOutOfBoundsException expected) { @@ -158,7 +160,7 @@ public class NioByteStringTest extends TestCase { try { // Copy with illegal negative destinationOffset - TEST_STRING.copyTo(destination, 0, -1, length); + testString.copyTo(destination, 0, -1, length); fail("Should have thrown an exception when given a negative destinationOffset in " + CLASSNAME); } catch (IndexOutOfBoundsException expected) { @@ -167,7 +169,7 @@ public class NioByteStringTest extends TestCase { try { // Copy with illegal negative size - TEST_STRING.copyTo(destination, 0, 0, -1); + testString.copyTo(destination, 0, 0, -1); fail("Should have thrown an exception when given a negative size in " + CLASSNAME); } catch (IndexOutOfBoundsException expected) { @@ -176,7 +178,7 @@ public class NioByteStringTest extends TestCase { try { // Copy with illegal too-large sourceOffset - TEST_STRING.copyTo(destination, 2 * TEST_STRING.size(), 0, length); + testString.copyTo(destination, 2 * testString.size(), 0, length); fail("Should have thrown an exception when the destinationOffset is too large in " + CLASSNAME); } catch (IndexOutOfBoundsException expected) { @@ -185,7 +187,7 @@ public class NioByteStringTest extends TestCase { try { // Copy with illegal too-large destinationOffset - TEST_STRING.copyTo(destination, 0, 2 * destination.length, length); + testString.copyTo(destination, 0, 2 * destination.length, length); fail("Should have thrown an exception when the destinationOffset is too large in " + CLASSNAME); } catch (IndexOutOfBoundsException expected) { @@ -196,21 +198,21 @@ public class NioByteStringTest extends TestCase { public void testCopyTo_ByteBuffer() { // Same length. ByteBuffer myBuffer = ByteBuffer.allocate(BYTES.length); - TEST_STRING.copyTo(myBuffer); + testString.copyTo(myBuffer); myBuffer.flip(); assertEquals(CLASSNAME + ".copyTo(ByteBuffer) must give back the same bytes", - BUFFER, myBuffer); + backingBuffer, myBuffer); // Target buffer bigger than required. - myBuffer = ByteBuffer.allocate(TEST_STRING.size() + 1); - TEST_STRING.copyTo(myBuffer); + myBuffer = ByteBuffer.allocate(testString.size() + 1); + testString.copyTo(myBuffer); myBuffer.flip(); - assertEquals(BUFFER, myBuffer); + assertEquals(backingBuffer, myBuffer); // Target buffer has no space. myBuffer = ByteBuffer.allocate(0); try { - TEST_STRING.copyTo(myBuffer); + testString.copyTo(myBuffer); fail("Should have thrown an exception when target ByteBuffer has insufficient capacity"); } catch (BufferOverflowException e) { // Expected. @@ -219,7 +221,7 @@ public class NioByteStringTest extends TestCase { // Target buffer too small. myBuffer = ByteBuffer.allocate(1); try { - TEST_STRING.copyTo(myBuffer); + testString.copyTo(myBuffer); fail("Should have thrown an exception when target ByteBuffer has insufficient capacity"); } catch (BufferOverflowException e) { // Expected. @@ -227,26 +229,26 @@ public class NioByteStringTest extends TestCase { } public void testMarkSupported() { - InputStream stream = TEST_STRING.newInput(); + InputStream stream = testString.newInput(); assertTrue(CLASSNAME + ".newInput() must support marking", stream.markSupported()); } public void testMarkAndReset() throws IOException { - int fraction = TEST_STRING.size() / 3; + int fraction = testString.size() / 3; - InputStream stream = TEST_STRING.newInput(); - stream.mark(TEST_STRING.size()); // First, mark() the end. + InputStream stream = testString.newInput(); + stream.mark(testString.size()); // First, mark() the end. skipFully(stream, fraction); // Skip a large fraction, but not all. assertEquals( CLASSNAME + ": after skipping to the 'middle', half the bytes are available", - (TEST_STRING.size() - fraction), stream.available()); + (testString.size() - fraction), stream.available()); stream.reset(); assertEquals( CLASSNAME + ": after resetting, all bytes are available", - TEST_STRING.size(), stream.available()); + testString.size(), stream.available()); - skipFully(stream, TEST_STRING.size()); // Skip to the end. + skipFully(stream, testString.size()); // Skip to the end. assertEquals( CLASSNAME + ": after skipping to the end, no more bytes are available", 0, stream.available()); @@ -284,7 +286,7 @@ public class NioByteStringTest extends TestCase { } public void testAsReadOnlyByteBuffer() { - ByteBuffer byteBuffer = TEST_STRING.asReadOnlyByteBuffer(); + ByteBuffer byteBuffer = testString.asReadOnlyByteBuffer(); byte[] roundTripBytes = new byte[BYTES.length]; assertTrue(byteBuffer.remaining() == BYTES.length); assertTrue(byteBuffer.isReadOnly()); @@ -294,7 +296,7 @@ public class NioByteStringTest extends TestCase { } public void testAsReadOnlyByteBufferList() { - List byteBuffers = TEST_STRING.asReadOnlyByteBufferList(); + List byteBuffers = testString.asReadOnlyByteBufferList(); int bytesSeen = 0; byte[] roundTripBytes = new byte[BYTES.length]; for (ByteBuffer byteBuffer : byteBuffers) { @@ -310,25 +312,98 @@ public class NioByteStringTest extends TestCase { } public void testToByteArray() { - byte[] roundTripBytes = TEST_STRING.toByteArray(); + byte[] roundTripBytes = testString.toByteArray(); assertTrue(CLASSNAME + ".toByteArray() must give back the same bytes", Arrays.equals(BYTES, roundTripBytes)); } public void testWriteTo() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); - TEST_STRING.writeTo(bos); + testString.writeTo(bos); byte[] roundTripBytes = bos.toByteArray(); assertTrue(CLASSNAME + ".writeTo() must give back the same bytes", Arrays.equals(BYTES, roundTripBytes)); } + public void testWriteToShouldNotExposeInternalBufferToOutputStream() throws IOException { + OutputStream os = new OutputStream() { + @Override + public void write(byte[] b, int off, int len) { + Arrays.fill(b, off, off + len, (byte) 0); + } + + @Override + public void write(int b) { + throw new UnsupportedOperationException(); + } + }; + + byte[] original = Arrays.copyOf(BYTES, BYTES.length); + testString.writeTo(os); + assertTrue(CLASSNAME + ".writeTo() must NOT grant access to underlying buffer", + Arrays.equals(original, BYTES)); + } + + public void testWriteToInternalShouldExposeInternalBufferToOutputStream() throws IOException { + OutputStream os = new OutputStream() { + @Override + public void write(byte[] b, int off, int len) { + Arrays.fill(b, off, off + len, (byte) 0); + } + + @Override + public void write(int b) { + throw new UnsupportedOperationException(); + } + }; + + testString.writeToInternal(os, 0, testString.size()); + byte[] allZeros = new byte[testString.size()]; + assertTrue(CLASSNAME + ".writeToInternal() must grant access to underlying buffer", + Arrays.equals(allZeros, backingBuffer.array())); + } + + public void testWriteToShouldExposeInternalBufferToByteOutput() throws IOException { + ByteOutput out = new ByteOutput() { + @Override + public void write(byte value) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void write(byte[] value, int offset, int length) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void writeLazy(byte[] value, int offset, int length) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void write(ByteBuffer value) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void writeLazy(ByteBuffer value) throws IOException { + Arrays.fill(value.array(), value.arrayOffset(), value.arrayOffset() + value.limit(), + (byte) 0); + } + }; + + testString.writeTo(out); + byte[] allZeros = new byte[testString.size()]; + assertTrue(CLASSNAME + ".writeTo() must grant access to underlying buffer", + Arrays.equals(allZeros, backingBuffer.array())); + } + public void testNewOutput() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ByteString.Output output = ByteString.newOutput(); - TEST_STRING.writeTo(output); + testString.writeTo(output); assertEquals("Output Size returns correct result", - output.size(), TEST_STRING.size()); + output.size(), testString.size()); output.writeTo(bos); assertTrue("Output.writeTo() must give back the same bytes", Arrays.equals(BYTES, bos.toByteArray())); @@ -336,7 +411,7 @@ public class NioByteStringTest extends TestCase { // write the output stream to itself! This should cause it to double output.writeTo(output); assertEquals("Writing an output stream to itself is successful", - TEST_STRING.concat(TEST_STRING), output.toByteString()); + testString.concat(testString), output.toByteString()); output.reset(); assertEquals("Output.reset() resets the output", 0, output.size()); @@ -373,7 +448,7 @@ public class NioByteStringTest extends TestCase { } try { - TEST_STRING.toString("invalid"); + testString.toString("invalid"); fail("Should have thrown an exception."); } catch (UnsupportedEncodingException expected) { // This is success @@ -381,36 +456,36 @@ public class NioByteStringTest extends TestCase { } public void testEquals() { - assertEquals(CLASSNAME + " must not equal null", false, TEST_STRING.equals(null)); - assertEquals(CLASSNAME + " must equal self", TEST_STRING, TEST_STRING); + assertEquals(CLASSNAME + " must not equal null", false, testString.equals(null)); + assertEquals(CLASSNAME + " must equal self", testString, testString); assertFalse(CLASSNAME + " must not equal the empty string", - TEST_STRING.equals(EMPTY)); + testString.equals(EMPTY)); assertEquals(CLASSNAME + " empty strings must be equal", - EMPTY, TEST_STRING.substring(55, 55)); + EMPTY, testString.substring(55, 55)); assertEquals(CLASSNAME + " must equal another string with the same value", - TEST_STRING, new NioByteString(BUFFER)); + testString, new NioByteString(backingBuffer)); byte[] mungedBytes = mungedBytes(); assertFalse(CLASSNAME + " must not equal every string with the same length", - TEST_STRING.equals(new NioByteString(ByteBuffer.wrap(mungedBytes)))); + testString.equals(new NioByteString(ByteBuffer.wrap(mungedBytes)))); } public void testEqualsLiteralByteString() { ByteString literal = ByteString.copyFrom(BYTES); assertEquals(CLASSNAME + " must equal LiteralByteString with same value", literal, - TEST_STRING); - assertEquals(CLASSNAME + " must equal LiteralByteString with same value", TEST_STRING, + testString); + assertEquals(CLASSNAME + " must equal LiteralByteString with same value", testString, literal); assertFalse(CLASSNAME + " must not equal the empty string", - TEST_STRING.equals(ByteString.EMPTY)); + testString.equals(ByteString.EMPTY)); assertEquals(CLASSNAME + " empty strings must be equal", - ByteString.EMPTY, TEST_STRING.substring(55, 55)); + ByteString.EMPTY, testString.substring(55, 55)); literal = ByteString.copyFrom(mungedBytes()); assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length", - TEST_STRING.equals(literal)); + testString.equals(literal)); assertFalse(CLASSNAME + " must not equal every LiteralByteString with the same length", - literal.equals(TEST_STRING)); + literal.equals(testString)); } public void testEqualsRopeByteString() { @@ -419,22 +494,22 @@ public class NioByteStringTest extends TestCase { ByteString rope = p1.concat(p2); assertEquals(CLASSNAME + " must equal RopeByteString with same value", rope, - TEST_STRING); - assertEquals(CLASSNAME + " must equal RopeByteString with same value", TEST_STRING, + testString); + assertEquals(CLASSNAME + " must equal RopeByteString with same value", testString, rope); assertFalse(CLASSNAME + " must not equal the empty string", - TEST_STRING.equals(ByteString.EMPTY.concat(ByteString.EMPTY))); + testString.equals(ByteString.EMPTY.concat(ByteString.EMPTY))); assertEquals(CLASSNAME + " empty strings must be equal", - ByteString.EMPTY.concat(ByteString.EMPTY), TEST_STRING.substring(55, 55)); + ByteString.EMPTY.concat(ByteString.EMPTY), testString.substring(55, 55)); byte[] mungedBytes = mungedBytes(); p1 = ByteString.copyFrom(mungedBytes, 0, 5); p2 = ByteString.copyFrom(mungedBytes, 5, mungedBytes.length - 5); rope = p1.concat(p2); assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length", - TEST_STRING.equals(rope)); + testString.equals(rope)); assertFalse(CLASSNAME + " must not equal every RopeByteString with the same length", - rope.equals(TEST_STRING)); + rope.equals(testString)); } private byte[] mungedBytes() { @@ -445,12 +520,12 @@ public class NioByteStringTest extends TestCase { } public void testHashCode() { - int hash = TEST_STRING.hashCode(); + int hash = testString.hashCode(); assertEquals(CLASSNAME + " must have expected hashCode", EXPECTED_HASH, hash); } public void testPeekCachedHashCode() { - ByteString newString = new NioByteString(BUFFER); + ByteString newString = new NioByteString(backingBuffer); assertEquals(CLASSNAME + ".peekCachedHashCode() should return zero at first", 0, newString.peekCachedHashCode()); newString.hashCode(); @@ -461,15 +536,15 @@ public class NioByteStringTest extends TestCase { public void testPartialHash() { // partialHash() is more strenuously tested elsewhere by testing hashes of substrings. // This test would fail if the expected hash were 1. It's not. - int hash = TEST_STRING.partialHash(TEST_STRING.size(), 0, TEST_STRING.size()); + int hash = testString.partialHash(testString.size(), 0, testString.size()); assertEquals(CLASSNAME + ".partialHash() must yield expected hashCode", EXPECTED_HASH, hash); } public void testNewInput() throws IOException { - InputStream input = TEST_STRING.newInput(); + InputStream input = testString.newInput(); assertEquals("InputStream.available() returns correct value", - TEST_STRING.size(), input.available()); + testString.size(), input.available()); boolean stillEqual = true; for (byte referenceByte : BYTES) { int expectedInt = (referenceByte & 0xFF); @@ -482,8 +557,8 @@ public class NioByteStringTest extends TestCase { } public void testNewInput_skip() throws IOException { - InputStream input = TEST_STRING.newInput(); - int stringSize = TEST_STRING.size(); + InputStream input = testString.newInput(); + int stringSize = testString.size(); int nearEndIndex = stringSize * 2 / 3; long skipped1 = input.skip(nearEndIndex); assertEquals("InputStream.skip()", skipped1, nearEndIndex); @@ -492,7 +567,7 @@ public class NioByteStringTest extends TestCase { assertTrue("InputStream.mark() is available", input.markSupported()); input.mark(0); assertEquals("InputStream.skip(), read()", - TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read()); + testString.byteAt(nearEndIndex) & 0xFF, input.read()); assertEquals("InputStream.available()", stringSize - skipped1 - 1, input.available()); long skipped2 = input.skip(stringSize); @@ -504,11 +579,11 @@ public class NioByteStringTest extends TestCase { assertEquals("InputStream.reset() succeded", stringSize - skipped1, input.available()); assertEquals("InputStream.reset(), read()", - TEST_STRING.byteAt(nearEndIndex) & 0xFF, input.read()); + testString.byteAt(nearEndIndex) & 0xFF, input.read()); } public void testNewCodedInput() throws IOException { - CodedInputStream cis = TEST_STRING.newCodedInput(); + CodedInputStream cis = testString.newCodedInput(); byte[] roundTripBytes = cis.readRawBytes(BYTES.length); assertTrue(CLASSNAME + " must give the same bytes back from the CodedInputStream", Arrays.equals(BYTES, roundTripBytes)); @@ -521,22 +596,22 @@ public class NioByteStringTest extends TestCase { */ public void testConcat_empty() { assertSame(CLASSNAME + " concatenated with empty must give " + CLASSNAME, - TEST_STRING.concat(EMPTY), TEST_STRING); + testString.concat(EMPTY), testString); assertSame("empty concatenated with " + CLASSNAME + " must give " + CLASSNAME, - EMPTY.concat(TEST_STRING), TEST_STRING); + EMPTY.concat(testString), testString); } public void testJavaSerialization() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); - oos.writeObject(TEST_STRING); + oos.writeObject(testString); oos.close(); byte[] pickled = out.toByteArray(); InputStream in = new ByteArrayInputStream(pickled); ObjectInputStream ois = new ObjectInputStream(in); Object o = ois.readObject(); assertTrue("Didn't get a ByteString back", o instanceof ByteString); - assertEquals("Should get an equal ByteString back", TEST_STRING, o); + assertEquals("Should get an equal ByteString back", testString, o); } private static ByteString forString(String str) { diff --git a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java index 37fa242d..bf1f1d71 100644 --- a/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java +++ b/java/core/src/test/java/com/google/protobuf/ParseExceptionsTest.java @@ -1,18 +1,52 @@ -package com.google.protobuf; +// 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. -import com.google.protobuf.DescriptorProtos.DescriptorProto; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import org.junit.Test; +package com.google.protobuf; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import com.google.protobuf.DescriptorProtos.DescriptorProto; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + /** * Tests the exceptions thrown when parsing from a stream. The methods on the {@link Parser} * interface are specified to only throw {@link InvalidProtocolBufferException}. But we really want @@ -22,6 +56,7 @@ import static org.junit.Assert.fail; * * @author jh@squareup.com (Joshua Humphries) */ +@RunWith(JUnit4.class) public class ParseExceptionsTest { private interface ParseTester { @@ -46,116 +81,143 @@ public class ParseExceptionsTest { @Test public void message_parseFrom_InputStream() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.parseFrom(in); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.parseFrom(in); + } + }); } @Test public void message_parseFrom_InputStreamAndExtensionRegistry() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance()); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.parseFrom(in, ExtensionRegistry.newInstance()); + } + }); } @Test public void message_parseFrom_CodedInputStream() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.parseFrom(CodedInputStream.newInstance(in)); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.parseFrom(CodedInputStream.newInstance(in)); + } + }); } @Test public void message_parseFrom_CodedInputStreamAndExtensionRegistry() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.parseFrom(CodedInputStream.newInstance(in), - ExtensionRegistry.newInstance()); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.parseFrom( + CodedInputStream.newInstance(in), ExtensionRegistry.newInstance()); + } + }); } @Test public void message_parseDelimitedFrom_InputStream() { setupDelimited(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.parseDelimitedFrom(in); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.parseDelimitedFrom(in); + } + }); } @Test public void message_parseDelimitedFrom_InputStreamAndExtensionRegistry() { setupDelimited(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance()); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.parseDelimitedFrom(in, ExtensionRegistry.newInstance()); + } + }); } @Test public void messageBuilder_mergeFrom_InputStream() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.newBuilder().mergeFrom(in).build(); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.newBuilder().mergeFrom(in).build(); + } + }); } @Test public void messageBuilder_mergeFrom_InputStreamAndExtensionRegistry() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.newBuilder().mergeFrom(in, ExtensionRegistry.newInstance()).build(); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.newBuilder() + .mergeFrom(in, ExtensionRegistry.newInstance()) + .build(); + } + }); } @Test public void messageBuilder_mergeFrom_CodedInputStream() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build(); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.newBuilder().mergeFrom(CodedInputStream.newInstance(in)).build(); + } + }); } @Test public void messageBuilder_mergeFrom_CodedInputStreamAndExtensionRegistry() { setup(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - return DescriptorProto.newBuilder() - .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance()).build(); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + return DescriptorProto.newBuilder() + .mergeFrom(CodedInputStream.newInstance(in), ExtensionRegistry.newInstance()) + .build(); + } + }); } @Test public void messageBuilder_mergeDelimitedFrom_InputStream() { setupDelimited(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - DescriptorProto.Builder builder = DescriptorProto.newBuilder(); - builder.mergeDelimitedFrom(in); - return builder.build(); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + DescriptorProto.Builder builder = DescriptorProto.newBuilder(); + builder.mergeDelimitedFrom(in); + return builder.build(); + } + }); } @Test public void messageBuilder_mergeDelimitedFrom_InputStreamAndExtensionRegistry() { setupDelimited(); - verifyExceptions(new ParseTester() { - public DescriptorProto parse(InputStream in) throws IOException { - DescriptorProto.Builder builder = DescriptorProto.newBuilder(); - builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance()); - return builder.build(); - } - }); + verifyExceptions( + new ParseTester() { + @Override + public DescriptorProto parse(InputStream in) throws IOException { + DescriptorProto.Builder builder = DescriptorProto.newBuilder(); + builder.mergeDelimitedFrom(in, ExtensionRegistry.newInstance()); + return builder.build(); + } + }); } private void verifyExceptions(ParseTester parseTester) { diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java index 5a92bacf..9d4b6b94 100644 --- a/java/core/src/test/java/com/google/protobuf/ParserTest.java +++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java @@ -33,15 +33,15 @@ package com.google.protobuf; import com.google.protobuf.UnittestLite.TestAllTypesLite; import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; import com.google.protobuf.UnittestLite.TestParsingMergeLite; +import protobuf_unittest.UnittestOptimizeFor; import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize; -import protobuf_unittest.UnittestOptimizeFor; +import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestEmptyMessage; import protobuf_unittest.UnittestProto.TestParsingMerge; import protobuf_unittest.UnittestProto.TestRequired; -import protobuf_unittest.UnittestProto; import junit.framework.TestCase; diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java index ff980d66..7f3439d0 100644 --- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java +++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java @@ -35,22 +35,22 @@ import com.google.protobuf.Descriptors.MethodDescriptor; import google.protobuf.no_generic_services_test.UnittestNoGenericServices; import protobuf_unittest.MessageWithNoOuter; import protobuf_unittest.ServiceWithNoOuter; -import protobuf_unittest.UnittestProto.TestAllTypes; -import protobuf_unittest.UnittestProto.TestService; -import protobuf_unittest.UnittestProto.FooRequest; -import protobuf_unittest.UnittestProto.FooResponse; import protobuf_unittest.UnittestProto.BarRequest; import protobuf_unittest.UnittestProto.BarResponse; +import protobuf_unittest.UnittestProto.FooRequest; +import protobuf_unittest.UnittestProto.FooResponse; +import protobuf_unittest.UnittestProto.TestAllTypes; +import protobuf_unittest.UnittestProto.TestService; + +import junit.framework.TestCase; import org.easymock.classextension.EasyMock; -import org.easymock.classextension.IMocksControl; import org.easymock.IArgumentMatcher; +import org.easymock.classextension.IMocksControl; import java.util.HashSet; import java.util.Set; -import junit.framework.TestCase; - /** * Tests services and stubs. * diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java index 01acb884..53d65428 100644 --- a/java/core/src/test/java/com/google/protobuf/TestUtil.java +++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java @@ -30,205 +30,207 @@ package com.google.protobuf; -import protobuf_unittest.UnittestProto; -import com.google.protobuf.UnittestLite; - +import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite; +import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite; +import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite; +import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite; +import static com.google.protobuf.UnittestLite.defaultCordExtensionLite; +import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite; +import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite; +import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite; +import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultStringExtensionLite; +import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite; +import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite; +import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite; +import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite; +import static com.google.protobuf.UnittestLite.oneofStringExtensionLite; +import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite; +import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite; +import static com.google.protobuf.UnittestLite.optionalCordExtensionLite; +import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite; +import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite; +import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite; +import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite; +import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalStringExtensionLite; +import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite; +import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedBoolExtensionLite; +import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.packedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedFloatExtensionLite; +import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite; +import static protobuf_unittest.UnittestProto.OptionalGroup_extension; +import static protobuf_unittest.UnittestProto.RepeatedGroup_extension; +import static protobuf_unittest.UnittestProto.defaultBoolExtension; +import static protobuf_unittest.UnittestProto.defaultBytesExtension; +import static protobuf_unittest.UnittestProto.defaultCordExtension; +import static protobuf_unittest.UnittestProto.defaultDoubleExtension; +import static protobuf_unittest.UnittestProto.defaultFixed32Extension; +import static protobuf_unittest.UnittestProto.defaultFixed64Extension; +import static protobuf_unittest.UnittestProto.defaultFloatExtension; +import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension; +import static protobuf_unittest.UnittestProto.defaultImportEnumExtension; // The static imports are to avoid 100+ char lines. The following is roughly equivalent to // import static protobuf_unittest.UnittestProto.*; import static protobuf_unittest.UnittestProto.defaultInt32Extension; import static protobuf_unittest.UnittestProto.defaultInt64Extension; -import static protobuf_unittest.UnittestProto.defaultUint32Extension; -import static protobuf_unittest.UnittestProto.defaultUint64Extension; -import static protobuf_unittest.UnittestProto.defaultSint32Extension; -import static protobuf_unittest.UnittestProto.defaultSint64Extension; -import static protobuf_unittest.UnittestProto.defaultFixed32Extension; -import static protobuf_unittest.UnittestProto.defaultFixed64Extension; +import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension; import static protobuf_unittest.UnittestProto.defaultSfixed32Extension; import static protobuf_unittest.UnittestProto.defaultSfixed64Extension; -import static protobuf_unittest.UnittestProto.defaultFloatExtension; -import static protobuf_unittest.UnittestProto.defaultDoubleExtension; -import static protobuf_unittest.UnittestProto.defaultBoolExtension; +import static protobuf_unittest.UnittestProto.defaultSint32Extension; +import static protobuf_unittest.UnittestProto.defaultSint64Extension; import static protobuf_unittest.UnittestProto.defaultStringExtension; -import static protobuf_unittest.UnittestProto.defaultBytesExtension; -import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension; -import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension; -import static protobuf_unittest.UnittestProto.defaultImportEnumExtension; import static protobuf_unittest.UnittestProto.defaultStringPieceExtension; -import static protobuf_unittest.UnittestProto.defaultCordExtension; - -import static protobuf_unittest.UnittestProto.oneofUint32Extension; +import static protobuf_unittest.UnittestProto.defaultUint32Extension; +import static protobuf_unittest.UnittestProto.defaultUint64Extension; +import static protobuf_unittest.UnittestProto.oneofBytesExtension; import static protobuf_unittest.UnittestProto.oneofNestedMessageExtension; import static protobuf_unittest.UnittestProto.oneofStringExtension; -import static protobuf_unittest.UnittestProto.oneofBytesExtension; - -import static protobuf_unittest.UnittestProto.optionalInt32Extension; -import static protobuf_unittest.UnittestProto.optionalInt64Extension; -import static protobuf_unittest.UnittestProto.optionalUint32Extension; -import static protobuf_unittest.UnittestProto.optionalUint64Extension; -import static protobuf_unittest.UnittestProto.optionalSint32Extension; -import static protobuf_unittest.UnittestProto.optionalSint64Extension; +import static protobuf_unittest.UnittestProto.oneofUint32Extension; +import static protobuf_unittest.UnittestProto.optionalBoolExtension; +import static protobuf_unittest.UnittestProto.optionalBytesExtension; +import static protobuf_unittest.UnittestProto.optionalCordExtension; +import static protobuf_unittest.UnittestProto.optionalDoubleExtension; import static protobuf_unittest.UnittestProto.optionalFixed32Extension; import static protobuf_unittest.UnittestProto.optionalFixed64Extension; -import static protobuf_unittest.UnittestProto.optionalSfixed32Extension; -import static protobuf_unittest.UnittestProto.optionalSfixed64Extension; import static protobuf_unittest.UnittestProto.optionalFloatExtension; -import static protobuf_unittest.UnittestProto.optionalDoubleExtension; -import static protobuf_unittest.UnittestProto.optionalBoolExtension; -import static protobuf_unittest.UnittestProto.optionalStringExtension; -import static protobuf_unittest.UnittestProto.optionalBytesExtension; -import static protobuf_unittest.UnittestProto.optionalGroupExtension; -import static protobuf_unittest.UnittestProto.optionalCordExtension; import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension; import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension; +import static protobuf_unittest.UnittestProto.optionalGroupExtension; import static protobuf_unittest.UnittestProto.optionalImportEnumExtension; import static protobuf_unittest.UnittestProto.optionalImportMessageExtension; +import static protobuf_unittest.UnittestProto.optionalInt32Extension; +import static protobuf_unittest.UnittestProto.optionalInt64Extension; +import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension; import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension; import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension; import static protobuf_unittest.UnittestProto.optionalPublicImportMessageExtension; -import static protobuf_unittest.UnittestProto.optionalLazyMessageExtension; +import static protobuf_unittest.UnittestProto.optionalSfixed32Extension; +import static protobuf_unittest.UnittestProto.optionalSfixed64Extension; +import static protobuf_unittest.UnittestProto.optionalSint32Extension; +import static protobuf_unittest.UnittestProto.optionalSint64Extension; +import static protobuf_unittest.UnittestProto.optionalStringExtension; import static protobuf_unittest.UnittestProto.optionalStringPieceExtension; - -import static protobuf_unittest.UnittestProto.repeatedInt32Extension; -import static protobuf_unittest.UnittestProto.repeatedInt64Extension; -import static protobuf_unittest.UnittestProto.repeatedUint32Extension; -import static protobuf_unittest.UnittestProto.repeatedUint64Extension; -import static protobuf_unittest.UnittestProto.repeatedSint32Extension; -import static protobuf_unittest.UnittestProto.repeatedSint64Extension; -import static protobuf_unittest.UnittestProto.repeatedFixed32Extension; -import static protobuf_unittest.UnittestProto.repeatedFixed64Extension; -import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension; -import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension; -import static protobuf_unittest.UnittestProto.repeatedFloatExtension; -import static protobuf_unittest.UnittestProto.repeatedDoubleExtension; -import static protobuf_unittest.UnittestProto.repeatedBoolExtension; -import static protobuf_unittest.UnittestProto.repeatedStringExtension; -import static protobuf_unittest.UnittestProto.repeatedBytesExtension; -import static protobuf_unittest.UnittestProto.repeatedGroupExtension; -import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension; -import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension; -import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension; -import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension; -import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension; -import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension; -import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension; -import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension; -import static protobuf_unittest.UnittestProto.repeatedCordExtension; - -import static protobuf_unittest.UnittestProto.OptionalGroup_extension; -import static protobuf_unittest.UnittestProto.RepeatedGroup_extension; - -import static protobuf_unittest.UnittestProto.packedInt32Extension; -import static protobuf_unittest.UnittestProto.packedInt64Extension; -import static protobuf_unittest.UnittestProto.packedUint32Extension; -import static protobuf_unittest.UnittestProto.packedUint64Extension; -import static protobuf_unittest.UnittestProto.packedSint32Extension; -import static protobuf_unittest.UnittestProto.packedSint64Extension; +import static protobuf_unittest.UnittestProto.optionalUint32Extension; +import static protobuf_unittest.UnittestProto.optionalUint64Extension; +import static protobuf_unittest.UnittestProto.packedBoolExtension; +import static protobuf_unittest.UnittestProto.packedDoubleExtension; +import static protobuf_unittest.UnittestProto.packedEnumExtension; import static protobuf_unittest.UnittestProto.packedFixed32Extension; import static protobuf_unittest.UnittestProto.packedFixed64Extension; +import static protobuf_unittest.UnittestProto.packedFloatExtension; +import static protobuf_unittest.UnittestProto.packedInt32Extension; +import static protobuf_unittest.UnittestProto.packedInt64Extension; import static protobuf_unittest.UnittestProto.packedSfixed32Extension; import static protobuf_unittest.UnittestProto.packedSfixed64Extension; -import static protobuf_unittest.UnittestProto.packedFloatExtension; -import static protobuf_unittest.UnittestProto.packedDoubleExtension; -import static protobuf_unittest.UnittestProto.packedBoolExtension; -import static protobuf_unittest.UnittestProto.packedEnumExtension; - -import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite; -import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite; -import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite; -import static com.google.protobuf.UnittestLite.defaultStringExtensionLite; -import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite; -import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite; -import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite; -import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite; -import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite; -import static com.google.protobuf.UnittestLite.defaultCordExtensionLite; - -import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite; -import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite; -import static com.google.protobuf.UnittestLite.oneofStringExtensionLite; -import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite; - -import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite; -import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite; -import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite; -import static com.google.protobuf.UnittestLite.optionalStringExtensionLite; -import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite; -import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite; -import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite; -import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite; -import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite; -import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite; -import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite; -import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite; -import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite; -import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite; -import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite; -import static com.google.protobuf.UnittestLite.optionalCordExtensionLite; - -import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite; -import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite; - -import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite; -import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite; - -import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite; -import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite; -import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite; -import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite; -import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite; -import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite; -import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite; -import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite; -import static com.google.protobuf.UnittestLite.packedFloatExtensionLite; -import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite; -import static com.google.protobuf.UnittestLite.packedBoolExtensionLite; -import static com.google.protobuf.UnittestLite.packedEnumExtensionLite; +import static protobuf_unittest.UnittestProto.packedSint32Extension; +import static protobuf_unittest.UnittestProto.packedSint64Extension; +import static protobuf_unittest.UnittestProto.packedUint32Extension; +import static protobuf_unittest.UnittestProto.packedUint64Extension; +import static protobuf_unittest.UnittestProto.repeatedBoolExtension; +import static protobuf_unittest.UnittestProto.repeatedBytesExtension; +import static protobuf_unittest.UnittestProto.repeatedCordExtension; +import static protobuf_unittest.UnittestProto.repeatedDoubleExtension; +import static protobuf_unittest.UnittestProto.repeatedFixed32Extension; +import static protobuf_unittest.UnittestProto.repeatedFixed64Extension; +import static protobuf_unittest.UnittestProto.repeatedFloatExtension; +import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension; +import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension; +import static protobuf_unittest.UnittestProto.repeatedGroupExtension; +import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension; +import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension; +import static protobuf_unittest.UnittestProto.repeatedInt32Extension; +import static protobuf_unittest.UnittestProto.repeatedInt64Extension; +import static protobuf_unittest.UnittestProto.repeatedLazyMessageExtension; +import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension; +import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension; +import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension; +import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension; +import static protobuf_unittest.UnittestProto.repeatedSint32Extension; +import static protobuf_unittest.UnittestProto.repeatedSint64Extension; +import static protobuf_unittest.UnittestProto.repeatedStringExtension; +import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension; +import static protobuf_unittest.UnittestProto.repeatedUint32Extension; +import static protobuf_unittest.UnittestProto.repeatedUint64Extension; +import com.google.protobuf.UnittestImportLite.ImportEnumLite; +import com.google.protobuf.UnittestImportLite.ImportMessageLite; +import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite; +import com.google.protobuf.UnittestLite; +import com.google.protobuf.UnittestLite.ForeignEnumLite; +import com.google.protobuf.UnittestLite.ForeignMessageLite; +import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder; +import com.google.protobuf.UnittestLite.TestAllTypesLite; +import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; +import com.google.protobuf.test.UnittestImport.ImportEnum; +import com.google.protobuf.test.UnittestImport.ImportMessage; +import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage; +import protobuf_unittest.UnittestProto; +import protobuf_unittest.UnittestProto.ForeignEnum; +import protobuf_unittest.UnittestProto.ForeignMessage; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllExtensionsOrBuilder; import protobuf_unittest.UnittestProto.TestAllTypes; @@ -237,21 +239,6 @@ import protobuf_unittest.UnittestProto.TestOneof2; import protobuf_unittest.UnittestProto.TestPackedExtensions; import protobuf_unittest.UnittestProto.TestPackedTypes; import protobuf_unittest.UnittestProto.TestUnpackedTypes; -import protobuf_unittest.UnittestProto.ForeignMessage; -import protobuf_unittest.UnittestProto.ForeignEnum; -import com.google.protobuf.test.UnittestImport.ImportEnum; -import com.google.protobuf.test.UnittestImport.ImportMessage; -import com.google.protobuf.test.UnittestImportPublic.PublicImportMessage; - -import com.google.protobuf.UnittestLite.TestAllTypesLite; -import com.google.protobuf.UnittestLite.TestAllExtensionsLite; -import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder; -import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; -import com.google.protobuf.UnittestLite.ForeignMessageLite; -import com.google.protobuf.UnittestLite.ForeignEnumLite; -import com.google.protobuf.UnittestImportLite.ImportEnumLite; -import com.google.protobuf.UnittestImportLite.ImportMessageLite; -import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite; import junit.framework.Assert; diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java new file mode 100644 index 00000000..e338af21 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseInfoTreeTest.java @@ -0,0 +1,182 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import protobuf_unittest.UnittestProto.TestAllTypes; + +import junit.framework.TestCase; + +/** + * Test @{link TextFormatParseInfoTree}. + */ +public class TextFormatParseInfoTreeTest extends TestCase { + + private static final Descriptor DESCRIPTOR = TestAllTypes.getDescriptor(); + private static final FieldDescriptor OPTIONAL_INT32 = + DESCRIPTOR.findFieldByName("optional_int32"); + private static final FieldDescriptor OPTIONAL_BOOLEAN = + DESCRIPTOR.findFieldByName("optional_boolean"); + private static final FieldDescriptor REPEATED_INT32 = + DESCRIPTOR.findFieldByName("repeated_int32"); + private static final FieldDescriptor OPTIONAL_NESTED_MESSAGE = + DESCRIPTOR.findFieldByName("optional_nested_message"); + private static final FieldDescriptor REPEATED_NESTED_MESSAGE = + DESCRIPTOR.findFieldByName("repeated_nested_message"); + private static final FieldDescriptor FIELD_BB = + TestAllTypes.NestedMessage.getDescriptor().findFieldByName("bb"); + + private static final TextFormatParseLocation LOC0 = TextFormatParseLocation.create(1, 2); + private static final TextFormatParseLocation LOC1 = TextFormatParseLocation.create(2, 3); + + private TextFormatParseInfoTree.Builder rootBuilder; + + @Override + public void setUp() { + rootBuilder = TextFormatParseInfoTree.builder(); + } + + public void testBuildEmptyParseTree() { + TextFormatParseInfoTree tree = rootBuilder.build(); + assertTrue(tree.getLocations(null).isEmpty()); + } + + public void testGetLocationReturnsSingleLocation() { + rootBuilder.setLocation(OPTIONAL_INT32, LOC0); + TextFormatParseInfoTree root = rootBuilder.build(); + assertEquals(LOC0, root.getLocation(OPTIONAL_INT32, 0)); + assertEquals(1, root.getLocations(OPTIONAL_INT32).size()); + } + + public void testGetLocationsReturnsNoParseLocationsForUnknownField() { + assertTrue(rootBuilder.build().getLocations(OPTIONAL_INT32).isEmpty()); + rootBuilder.setLocation(OPTIONAL_BOOLEAN, LOC0); + TextFormatParseInfoTree root = rootBuilder.build(); + assertTrue(root.getLocations(OPTIONAL_INT32).isEmpty()); + assertEquals(LOC0, root.getLocations(OPTIONAL_BOOLEAN).get(0)); + } + + public void testGetLocationThrowsIllegalArgumentExceptionForUnknownField() { + rootBuilder.setLocation(REPEATED_INT32, LOC0); + TextFormatParseInfoTree root = rootBuilder.build(); + try { + root.getNestedTree(OPTIONAL_INT32, 0); + fail("Did not detect unknown field"); + } catch (IllegalArgumentException expected) { + // pass + } + } + + public void testGetLocationThrowsIllegalArgumentExceptionForInvalidIndex() { + TextFormatParseInfoTree root = rootBuilder.setLocation(OPTIONAL_INT32, LOC0).build(); + try { + root.getLocation(OPTIONAL_INT32, 1); + fail("Invalid index not detected"); + } catch (IllegalArgumentException expected) { + // pass + } + try { + root.getLocation(OPTIONAL_INT32, -1); + fail("Negative index not detected"); + } catch (IllegalArgumentException expected) { + // pass + } + } + + public void testGetLocationsReturnsMultipleLocations() { + rootBuilder.setLocation(REPEATED_INT32, LOC0); + rootBuilder.setLocation(REPEATED_INT32, LOC1); + TextFormatParseInfoTree root = rootBuilder.build(); + assertEquals(LOC0, root.getLocation(REPEATED_INT32, 0)); + assertEquals(LOC1, root.getLocation(REPEATED_INT32, 1)); + assertEquals(2, root.getLocations(REPEATED_INT32).size()); + } + + public void testGetNestedTreeThrowsIllegalArgumentExceptionForUnknownField() { + rootBuilder.setLocation(REPEATED_INT32, LOC0); + TextFormatParseInfoTree root = rootBuilder.build(); + try { + root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 0); + fail("Did not detect unknown field"); + } catch (IllegalArgumentException expected) { + // pass + } + } + + public void testGetNestedTreesReturnsNoParseInfoTreesForUnknownField() { + rootBuilder.setLocation(REPEATED_INT32, LOC0); + TextFormatParseInfoTree root = rootBuilder.build(); + assertTrue(root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).isEmpty()); + } + + public void testGetNestedTreeThrowsIllegalArgumentExceptionForInvalidIndex() { + rootBuilder.setLocation(REPEATED_INT32, LOC0); + rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE); + TextFormatParseInfoTree root = rootBuilder.build(); + try { + root.getNestedTree(OPTIONAL_NESTED_MESSAGE, 1); + fail("Submessage index that is too large not detected"); + } catch (IllegalArgumentException expected) { + // pass + } + try { + rootBuilder.build().getNestedTree(OPTIONAL_NESTED_MESSAGE, -1); + fail("Invalid submessage index (-1) not detected"); + } catch (IllegalArgumentException expected) { + // pass + } + } + + public void testGetNestedTreesReturnsSingleTree() { + rootBuilder.getBuilderForSubMessageField(OPTIONAL_NESTED_MESSAGE); + TextFormatParseInfoTree root = rootBuilder.build(); + assertEquals(1, root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).size()); + TextFormatParseInfoTree subtree = root.getNestedTrees(OPTIONAL_NESTED_MESSAGE).get(0); + assertNotNull(subtree); + } + + public void testGetNestedTreesReturnsMultipleTrees() { + TextFormatParseInfoTree.Builder subtree1Builder = + rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE); + subtree1Builder.getBuilderForSubMessageField(FIELD_BB); + subtree1Builder.getBuilderForSubMessageField(FIELD_BB); + TextFormatParseInfoTree.Builder subtree2Builder = + rootBuilder.getBuilderForSubMessageField(REPEATED_NESTED_MESSAGE); + subtree2Builder.getBuilderForSubMessageField(FIELD_BB); + TextFormatParseInfoTree root = rootBuilder.build(); + assertEquals(2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).size()); + assertEquals( + 2, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(0).getNestedTrees(FIELD_BB).size()); + assertEquals( + 1, root.getNestedTrees(REPEATED_NESTED_MESSAGE).get(1).getNestedTrees(FIELD_BB).size()); + } +} diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java new file mode 100644 index 00000000..c42bfa6e --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/TextFormatParseLocationTest.java @@ -0,0 +1,86 @@ +// 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. + +package com.google.protobuf; + +import junit.framework.TestCase; + +/** + * Test @{link TextFormatParseLocation}. + */ +public class TextFormatParseLocationTest extends TestCase { + + public void testCreateEmpty() { + TextFormatParseLocation location = TextFormatParseLocation.create(-1, -1); + assertEquals(TextFormatParseLocation.EMPTY, location); + } + + public void testCreate() { + TextFormatParseLocation location = TextFormatParseLocation.create(2, 1); + assertEquals(2, location.getLine()); + assertEquals(1, location.getColumn()); + } + + public void testCreateThrowsIllegalArgumentExceptionForInvalidIndex() { + try { + TextFormatParseLocation.create(-1, 0); + fail("Should throw IllegalArgumentException if line is less than 0"); + } catch (IllegalArgumentException unused) { + // pass + } + try { + TextFormatParseLocation.create(0, -1); + fail("Should throw, column < 0"); + } catch (IllegalArgumentException unused) { + // pass + } + } + + public void testHashCode() { + TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1); + TextFormatParseLocation loc1 = TextFormatParseLocation.create(2, 1); + + assertEquals(loc0.hashCode(), loc1.hashCode()); + assertEquals( + TextFormatParseLocation.EMPTY.hashCode(), TextFormatParseLocation.EMPTY.hashCode()); + } + + public void testEquals() { + TextFormatParseLocation loc0 = TextFormatParseLocation.create(2, 1); + TextFormatParseLocation loc1 = TextFormatParseLocation.create(1, 2); + TextFormatParseLocation loc2 = TextFormatParseLocation.create(2, 2); + TextFormatParseLocation loc3 = TextFormatParseLocation.create(2, 1); + + assertEquals(loc0, loc3); + assertNotSame(loc0, loc1); + assertNotSame(loc0, loc2); + assertNotSame(loc1, loc2); + } +} 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 1df4fad7..3f47d924 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java @@ -30,6 +30,7 @@ package com.google.protobuf; +import com.google.protobuf.Descriptors.Descriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import com.google.protobuf.TextFormat.Parser.SingularOverwritePolicy; import protobuf_unittest.UnittestMset.TestMessageSetExtension1; @@ -45,6 +46,7 @@ import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; import junit.framework.TestCase; import java.io.StringReader; +import java.util.List; /** * Test case for {@link TextFormat}. @@ -568,6 +570,16 @@ public class TextFormatTest extends TestCase { assertEquals(kEscapeTestString, TextFormat.unescapeText(kEscapeTestStringEscaped)); + // Invariant + assertEquals("hello", + TextFormat.escapeBytes(bytes("hello"))); + assertEquals("hello", + TextFormat.escapeText("hello")); + assertEquals(bytes("hello"), + TextFormat.unescapeBytes("hello")); + assertEquals("hello", + TextFormat.unescapeText("hello")); + // Unicode handling. assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234")); assertEquals("\\341\\210\\264", @@ -811,7 +823,6 @@ public class TextFormatTest extends TestCase { private void assertPrintFieldValue(String expect, Object value, String fieldName) throws Exception { - TestAllTypes.Builder builder = TestAllTypes.newBuilder(); StringBuilder sb = new StringBuilder(); TextFormat.printFieldValue( TestAllTypes.getDescriptor().findFieldByName(fieldName), @@ -1018,4 +1029,98 @@ public class TextFormatTest extends TestCase { assertFalse(oneof.hasFooString()); assertTrue(oneof.hasFooInt()); } + + // ======================================================================= + // test location information + + public void testParseInfoTreeBuilding() throws Exception { + TestAllTypes.Builder builder = TestAllTypes.newBuilder(); + + Descriptor descriptor = TestAllTypes.getDescriptor(); + TextFormatParseInfoTree.Builder treeBuilder = TextFormatParseInfoTree.builder(); + // Set to allow unknown fields + TextFormat.Parser parser = + TextFormat.Parser.newBuilder() + .setParseInfoTreeBuilder(treeBuilder) + .build(); + + final String stringData = + "optional_int32: 1\n" + + "optional_int64: 2\n" + + " optional_double: 2.4\n" + + "repeated_int32: 5\n" + + "repeated_int32: 10\n" + + "optional_nested_message <\n" + + " bb: 78\n" + + ">\n" + + "repeated_nested_message <\n" + + " bb: 79\n" + + ">\n" + + "repeated_nested_message <\n" + + " bb: 80\n" + + ">"; + + parser.merge(stringData, builder); + TextFormatParseInfoTree tree = treeBuilder.build(); + + // Verify that the tree has the correct positions. + assertLocation(tree, descriptor, "optional_int32", 0, 0, 0); + assertLocation(tree, descriptor, "optional_int64", 0, 1, 0); + assertLocation(tree, descriptor, "optional_double", 0, 2, 2); + + assertLocation(tree, descriptor, "repeated_int32", 0, 3, 0); + assertLocation(tree, descriptor, "repeated_int32", 1, 4, 0); + + assertLocation(tree, descriptor, "optional_nested_message", 0, 5, 0); + assertLocation(tree, descriptor, "repeated_nested_message", 0, 8, 0); + assertLocation(tree, descriptor, "repeated_nested_message", 1, 11, 0); + + // Check for fields not set. For an invalid field, the location returned should be -1, -1. + assertLocation(tree, descriptor, "repeated_int64", 0, -1, -1); + assertLocation(tree, descriptor, "repeated_int32", 6, -1, -1); + + // Verify inside the nested message. + FieldDescriptor nestedField = descriptor.findFieldByName("optional_nested_message"); + + TextFormatParseInfoTree nestedTree = tree.getNestedTrees(nestedField).get(0); + assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 6, 2); + + // Verify inside another nested message. + nestedField = descriptor.findFieldByName("repeated_nested_message"); + nestedTree = tree.getNestedTrees(nestedField).get(0); + assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 9, 2); + + nestedTree = tree.getNestedTrees(nestedField).get(1); + assertLocation(nestedTree, nestedField.getMessageType(), "bb", 0, 12, 2); + + // Verify a NULL tree for an unknown nested field. + try { + tree.getNestedTree(nestedField, 2); + fail("unknown nested field should throw"); + } catch (IllegalArgumentException unused) { + // pass + } + } + + private void assertLocation( + TextFormatParseInfoTree tree, + final Descriptor descriptor, + final String fieldName, + int index, + int line, + int column) { + List locs = tree.getLocations(descriptor.findFieldByName(fieldName)); + if (index < locs.size()) { + TextFormatParseLocation location = locs.get(index); + TextFormatParseLocation expected = TextFormatParseLocation.create(line, column); + assertEquals(expected, location); + } else if (line != -1 && column != -1) { + fail( + String.format( + "Tree/descriptor/fieldname did not contain index %d, line %d column %d expected", + index, + line, + column)); + } + } } diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java index dc987379..573cd665 100644 --- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java +++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetLiteTest.java @@ -47,46 +47,6 @@ import java.io.IOException; * @author dweis@google.com (Daniel Weis) */ public class UnknownFieldSetLiteTest extends TestCase { - - public void testNoDataIsDefaultInstance() { - assertSame( - UnknownFieldSetLite.getDefaultInstance(), - UnknownFieldSetLite.newBuilder() - .build()); - } - - public void testBuilderReuse() throws IOException { - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.mergeVarintField(10, 2); - builder.build(); - - try { - builder.build(); - fail(); - } catch (UnsupportedOperationException e) { - // Expected. - } - - try { - builder.mergeFieldFrom(0, CodedInputStream.newInstance(new byte[0])); - fail(); - } catch (UnsupportedOperationException e) { - // Expected. - } - - try { - builder.mergeVarintField(5, 1); - fail(); - } catch (UnsupportedOperationException e) { - // Expected. - } - } - - public void testBuilderReuse_empty() { - UnknownFieldSetLite.Builder builder = UnknownFieldSetLite.newBuilder(); - builder.build(); - builder.build(); - } public void testDefaultInstance() { UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java index 0175005d..b3aabb8f 100644 --- a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java @@ -30,12 +30,11 @@ package com.google.protobuf; -import junit.framework.TestCase; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.util.List; - +import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; +import protobuf_unittest.UnittestMset.RawMessageSet; +import protobuf_unittest.UnittestMset.TestMessageSetExtension1; +import protobuf_unittest.UnittestMset.TestMessageSetExtension2; import protobuf_unittest.UnittestProto; import protobuf_unittest.UnittestProto.TestAllExtensions; import protobuf_unittest.UnittestProto.TestAllTypes; @@ -44,12 +43,13 @@ import protobuf_unittest.UnittestProto.TestOneof2; import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible; import protobuf_unittest.UnittestProto.TestPackedExtensions; import protobuf_unittest.UnittestProto.TestPackedTypes; -import protobuf_unittest.UnittestMset.RawMessageSet; -import protobuf_unittest.UnittestMset.TestMessageSetExtension1; -import protobuf_unittest.UnittestMset.TestMessageSetExtension2; import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; -import com.google.protobuf.UnittestLite.TestAllExtensionsLite; -import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; + +import junit.framework.TestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.List; /** * Tests related to parsing and serialization. diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto index 86837250..f75484de 100644 --- a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto +++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto @@ -39,6 +39,13 @@ package protobuf_unittest.lite_equals_and_hash; option java_generate_equals_and_hash = true; option optimize_for = LITE_RUNTIME; +message TestOneofEquals { + oneof oneof_field { + string name = 1; + int32 value = 2; + } +} + message Foo { optional int32 value = 1; repeated Bar bar = 2; @@ -70,3 +77,8 @@ extend Foo { } } +message TestRecursiveOneof { + oneof Foo { + TestRecursiveOneof r = 1; + } +} diff --git a/java/pom.xml b/java/pom.xml index d5719edf..787bc534 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -64,7 +64,7 @@ junit junit - 4.4 + 4.12 test diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java index dc2f4b84..d6a2f6fa 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java @@ -60,10 +60,9 @@ import java.util.logging.Logger; * FieldMask in a message tree. */ class FieldMaskTree { - private static final Logger logger = - Logger.getLogger(FieldMaskTree.class.getName()); - - private static final String FIELD_PATH_SEPARATOR_REGEX = "\\."; + private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName()); + + private static final String FIELD_PATH_SEPARATOR_REGEX = "\\."; private static class Node { public TreeMap children = new TreeMap(); @@ -73,12 +72,12 @@ class FieldMaskTree { /** Creates an empty FieldMaskTree. */ public FieldMaskTree() {} - + /** Creates a FieldMaskTree for a given FieldMask. */ public FieldMaskTree(FieldMask mask) { mergeFromFieldMask(mask); } - + @Override public String toString() { return FieldMaskUtil.toString(toFieldMask()); @@ -121,7 +120,7 @@ class FieldMaskTree { node.children.clear(); return this; } - + /** * Merges all field paths in a FieldMask into this tree. */ @@ -149,8 +148,7 @@ class FieldMaskTree { return; } for (Entry entry : node.children.entrySet()) { - String childPath = path.isEmpty() - ? entry.getKey() : path + "." + entry.getKey(); + String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey(); getFieldPaths(entry.getValue(), childPath, paths); } } @@ -193,11 +191,10 @@ class FieldMaskTree { * Merges all fields specified by this FieldMaskTree from {@code source} to * {@code destination}. */ - public void merge(Message source, Message.Builder destination, - FieldMaskUtil.MergeOptions options) { + public void merge( + Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) { if (source.getDescriptorForType() != destination.getDescriptorForType()) { - throw new IllegalArgumentException( - "Cannot merge messages of different types."); + throw new IllegalArgumentException("Cannot merge messages of different types."); } if (root.children.isEmpty()) { return; @@ -208,30 +205,41 @@ class FieldMaskTree { /** Merges all fields specified by a sub-tree from {@code source} to * {@code destination}. */ - private void merge(Node node, String path, Message source, - Message.Builder destination, FieldMaskUtil.MergeOptions options) { + private void merge( + Node node, + String path, + Message source, + Message.Builder destination, + FieldMaskUtil.MergeOptions options) { assert source.getDescriptorForType() == destination.getDescriptorForType(); - + Descriptor descriptor = source.getDescriptorForType(); for (Entry entry : node.children.entrySet()) { - FieldDescriptor field = - descriptor.findFieldByName(entry.getKey()); + FieldDescriptor field = descriptor.findFieldByName(entry.getKey()); if (field == null) { - logger.warning("Cannot find field \"" + entry.getKey() - + "\" in message type " + descriptor.getFullName()); + logger.warning( + "Cannot find field \"" + + entry.getKey() + + "\" in message type " + + descriptor.getFullName()); continue; } if (!entry.getValue().children.isEmpty()) { - if (field.isRepeated() - || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { - logger.warning("Field \"" + field.getFullName() + "\" is not a " - + "singluar message field and cannot have sub-fields."); + if (field.isRepeated() || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { + logger.warning( + "Field \"" + + field.getFullName() + + "\" is not a " + + "singluar message field and cannot have sub-fields."); continue; } - String childPath = path.isEmpty() - ? entry.getKey() : path + "." + entry.getKey(); - merge(entry.getValue(), childPath, (Message) source.getField(field), - destination.getFieldBuilder(field), options); + String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.getKey(); + merge( + entry.getValue(), + childPath, + (Message) source.getField(field), + destination.getFieldBuilder(field), + options); continue; } if (field.isRepeated()) { @@ -245,10 +253,15 @@ class FieldMaskTree { } else { if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { if (options.replaceMessageFields()) { - destination.setField(field, source.getField(field)); + if (!source.hasField(field)) { + destination.clearField(field); + } else { + destination.setField(field, source.getField(field)); + } } else { - destination.getFieldBuilder(field).mergeFrom( - (Message) source.getField(field)); + if (source.hasField(field)) { + destination.getFieldBuilder(field).mergeFrom((Message) source.getField(field)); + } } } else { destination.setField(field, source.getField(field)); 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 d13ff0ed..d7bf34a4 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 @@ -32,6 +32,7 @@ package com.google.protobuf.util; import com.google.common.io.BaseEncoding; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; @@ -433,7 +434,7 @@ public class JsonFormat { private final Gson gson; private static class GsonHolder { - private static final Gson DEFAULT_GSON = new Gson(); + private static final Gson DEFAULT_GSON = new GsonBuilder().disableHtmlEscaping().create(); } PrinterImpl( @@ -1066,6 +1067,15 @@ public class JsonFormat { parser.mergeStruct(json, builder); } }); + // Special-case ListValue. + parsers.put(ListValue.getDescriptor().getFullName(), + new WellKnownTypeParser() { + @Override + public void merge(ParserImpl parser, JsonElement json, + Message.Builder builder) throws InvalidProtocolBufferException { + parser.mergeListValue(json, builder); + } + }); // Special-case Value. parsers.put(Value.getDescriptor().getFullName(), new WellKnownTypeParser() { @@ -1213,6 +1223,16 @@ public class JsonFormat { } mergeMapField(field, json, builder); } + + private void mergeListValue(JsonElement json, Message.Builder builder) + throws InvalidProtocolBufferException { + Descriptor descriptor = builder.getDescriptorForType(); + FieldDescriptor field = descriptor.findFieldByName("values"); + if (field == null) { + throw new InvalidProtocolBufferException("Invalid ListValue type."); + } + mergeRepeatedField(field, json, builder); + } private void mergeValue(JsonElement json, Message.Builder builder) throws InvalidProtocolBufferException { @@ -1237,9 +1257,7 @@ public class JsonFormat { } else if (json instanceof JsonArray) { FieldDescriptor field = type.findFieldByName("list_value"); Message.Builder listBuilder = builder.newBuilderForField(field); - FieldDescriptor listField = - listBuilder.getDescriptorForType().findFieldByName("values"); - mergeRepeatedField(listField, json, listBuilder); + merge(json, listBuilder); builder.setField(field, listBuilder.build()); } else { throw new IllegalStateException("Unexpected json data: " + json); diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java index 3391f239..618e0072 100644 --- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java @@ -61,19 +61,16 @@ public class FieldMaskTreeTest extends TestCase { tree.addFieldPath("bar"); assertEquals("bar,foo", tree.toString()); } - + public void testMergeFromFieldMask() throws Exception { - FieldMaskTree tree = new FieldMaskTree( - FieldMaskUtil.fromString("foo,bar.baz,bar.quz")); + FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz")); assertEquals("bar.baz,bar.quz,foo", tree.toString()); - tree.mergeFromFieldMask( - FieldMaskUtil.fromString("foo.bar,bar")); + tree.mergeFromFieldMask(FieldMaskUtil.fromString("foo.bar,bar")); assertEquals("bar,foo", tree.toString()); } - + public void testIntersectFieldPath() throws Exception { - FieldMaskTree tree = new FieldMaskTree( - FieldMaskUtil.fromString("foo,bar.baz,bar.quz")); + FieldMaskTree tree = new FieldMaskTree(FieldMaskUtil.fromString("foo,bar.baz,bar.quz")); FieldMaskTree result = new FieldMaskTree(); // Empty path. tree.intersectFieldPath("", result); @@ -96,16 +93,18 @@ public class FieldMaskTreeTest extends TestCase { } public void testMerge() throws Exception { - TestAllTypes value = TestAllTypes.newBuilder() - .setOptionalInt32(1234) - .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678)) - .addRepeatedInt32(4321) - .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765)) - .build(); - NestedTestAllTypes source = NestedTestAllTypes.newBuilder() - .setPayload(value) - .setChild(NestedTestAllTypes.newBuilder().setPayload(value)) - .build(); + TestAllTypes value = + TestAllTypes.newBuilder() + .setOptionalInt32(1234) + .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678)) + .addRepeatedInt32(4321) + .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765)) + .build(); + NestedTestAllTypes source = + NestedTestAllTypes.newBuilder() + .setPayload(value) + .setChild(NestedTestAllTypes.newBuilder().setPayload(value)) + .build(); // Now we have a message source with the following structure: // [root] -+- payload -+- optional_int32 // | +- optional_nested_message @@ -116,114 +115,127 @@ public class FieldMaskTreeTest extends TestCase { // +- optional_nested_message // +- repeated_int32 // +- repeated_nested_message - + FieldMaskUtil.MergeOptions options = new FieldMaskUtil.MergeOptions(); - + // Test merging each individual field. NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("payload.optional_int32") - .merge(source, builder, options); + new FieldMaskTree().addFieldPath("payload.optional_int32").merge(source, builder, options); NestedTestAllTypes.Builder expected = NestedTestAllTypes.newBuilder(); expected.getPayloadBuilder().setOptionalInt32(1234); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("payload.optional_nested_message") + new FieldMaskTree() + .addFieldPath("payload.optional_nested_message") .merge(source, builder, options); expected = NestedTestAllTypes.newBuilder(); - expected.getPayloadBuilder().setOptionalNestedMessage( - NestedMessage.newBuilder().setBb(5678)); + expected.getPayloadBuilder().setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678)); assertEquals(expected.build(), builder.build()); - builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("payload.repeated_int32") - .merge(source, builder, options); + new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options); expected = NestedTestAllTypes.newBuilder(); expected.getPayloadBuilder().addRepeatedInt32(4321); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("payload.repeated_nested_message") + new FieldMaskTree() + .addFieldPath("payload.repeated_nested_message") .merge(source, builder, options); expected = NestedTestAllTypes.newBuilder(); - expected.getPayloadBuilder().addRepeatedNestedMessage( - NestedMessage.newBuilder().setBb(8765)); + expected.getPayloadBuilder().addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765)); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("child.payload.optional_int32") + new FieldMaskTree() + .addFieldPath("child.payload.optional_int32") .merge(source, builder, options); expected = NestedTestAllTypes.newBuilder(); expected.getChildBuilder().getPayloadBuilder().setOptionalInt32(1234); assertEquals(expected.build(), builder.build()); builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("child.payload.optional_nested_message") + new FieldMaskTree() + .addFieldPath("child.payload.optional_nested_message") .merge(source, builder, options); expected = NestedTestAllTypes.newBuilder(); - expected.getChildBuilder().getPayloadBuilder().setOptionalNestedMessage( - NestedMessage.newBuilder().setBb(5678)); + expected + .getChildBuilder() + .getPayloadBuilder() + .setOptionalNestedMessage(NestedMessage.newBuilder().setBb(5678)); assertEquals(expected.build(), builder.build()); - builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("child.payload.repeated_int32") + new FieldMaskTree() + .addFieldPath("child.payload.repeated_int32") .merge(source, builder, options); expected = NestedTestAllTypes.newBuilder(); expected.getChildBuilder().getPayloadBuilder().addRepeatedInt32(4321); assertEquals(expected.build(), builder.build()); - builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("child.payload.repeated_nested_message") + new FieldMaskTree() + .addFieldPath("child.payload.repeated_nested_message") .merge(source, builder, options); expected = NestedTestAllTypes.newBuilder(); - expected.getChildBuilder().getPayloadBuilder().addRepeatedNestedMessage( - NestedMessage.newBuilder().setBb(8765)); + expected + .getChildBuilder() + .getPayloadBuilder() + .addRepeatedNestedMessage(NestedMessage.newBuilder().setBb(8765)); assertEquals(expected.build(), builder.build()); - + // Test merging all fields. builder = NestedTestAllTypes.newBuilder(); - new FieldMaskTree().addFieldPath("child").addFieldPath("payload") - .merge(source, builder, options); + new FieldMaskTree() + .addFieldPath("child") + .addFieldPath("payload") + .merge(source, builder, options); assertEquals(source, builder.build()); - + // Test repeated options. builder = NestedTestAllTypes.newBuilder(); builder.getPayloadBuilder().addRepeatedInt32(1000); - new FieldMaskTree().addFieldPath("payload.repeated_int32") - .merge(source, builder, options); + new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options); // Default behavior is to append repeated fields. assertEquals(2, builder.getPayload().getRepeatedInt32Count()); assertEquals(1000, builder.getPayload().getRepeatedInt32(0)); assertEquals(4321, builder.getPayload().getRepeatedInt32(1)); // Change to replace repeated fields. options.setReplaceRepeatedFields(true); - new FieldMaskTree().addFieldPath("payload.repeated_int32") - .merge(source, builder, options); + new FieldMaskTree().addFieldPath("payload.repeated_int32").merge(source, builder, options); assertEquals(1, builder.getPayload().getRepeatedInt32Count()); assertEquals(4321, builder.getPayload().getRepeatedInt32(0)); - + // Test message options. builder = NestedTestAllTypes.newBuilder(); builder.getPayloadBuilder().setOptionalInt32(1000); builder.getPayloadBuilder().setOptionalUint32(2000); - new FieldMaskTree().addFieldPath("payload") - .merge(source, builder, options); + new FieldMaskTree().addFieldPath("payload").merge(source, builder, options); // Default behavior is to merge message fields. assertEquals(1234, builder.getPayload().getOptionalInt32()); assertEquals(2000, builder.getPayload().getOptionalUint32()); - + + // Test merging unset message fields. + NestedTestAllTypes clearedSource = source.toBuilder().clearPayload().build(); + builder = NestedTestAllTypes.newBuilder(); + new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options); + assertEquals(false, builder.hasPayload()); + // Change to replace message fields. options.setReplaceMessageFields(true); builder = NestedTestAllTypes.newBuilder(); builder.getPayloadBuilder().setOptionalInt32(1000); builder.getPayloadBuilder().setOptionalUint32(2000); - new FieldMaskTree().addFieldPath("payload") - .merge(source, builder, options); + new FieldMaskTree().addFieldPath("payload").merge(source, builder, options); assertEquals(1234, builder.getPayload().getOptionalInt32()); assertEquals(0, builder.getPayload().getOptionalUint32()); + + // Test merging unset message fields. + builder = NestedTestAllTypes.newBuilder(); + builder.getPayloadBuilder().setOptionalInt32(1000); + builder.getPayloadBuilder().setOptionalUint32(2000); + new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options); + assertEquals(false, builder.hasPayload()); } } - diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java index c0eb0330..d95b626c 100644 --- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java @@ -122,11 +122,11 @@ public class JsonFormatTest extends TestCase { builder.addRepeatedNestedEnum(NestedEnum.BAZ); builder.addRepeatedNestedMessageBuilder().setValue(200); } - + private void assertRoundTripEquals(Message message) throws Exception { assertRoundTripEquals(message, TypeRegistry.getEmptyTypeRegistry()); } - + private void assertRoundTripEquals(Message message, TypeRegistry registry) throws Exception { JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); JsonFormat.Parser parser = JsonFormat.parser().usingTypeRegistry(registry); @@ -135,68 +135,68 @@ public class JsonFormatTest extends TestCase { Message parsedMessage = builder.build(); assertEquals(message.toString(), parsedMessage.toString()); } - + private String toJsonString(Message message) throws IOException { return JsonFormat.printer().print(message); } - + private void mergeFromJson(String json, Message.Builder builder) throws IOException { JsonFormat.parser().merge(json, builder); } - + public void testAllFields() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); setAllFields(builder); TestAllTypes message = builder.build(); - - assertEquals( + + assertEquals( "{\n" - + " \"optionalInt32\": 1234,\n" - + " \"optionalInt64\": \"1234567890123456789\",\n" - + " \"optionalUint32\": 5678,\n" - + " \"optionalUint64\": \"2345678901234567890\",\n" - + " \"optionalSint32\": 9012,\n" - + " \"optionalSint64\": \"3456789012345678901\",\n" - + " \"optionalFixed32\": 3456,\n" - + " \"optionalFixed64\": \"4567890123456789012\",\n" - + " \"optionalSfixed32\": 7890,\n" - + " \"optionalSfixed64\": \"5678901234567890123\",\n" - + " \"optionalFloat\": 1.5,\n" - + " \"optionalDouble\": 1.25,\n" - + " \"optionalBool\": true,\n" - + " \"optionalString\": \"Hello world!\",\n" - + " \"optionalBytes\": \"AAEC\",\n" - + " \"optionalNestedMessage\": {\n" - + " \"value\": 100\n" - + " },\n" - + " \"optionalNestedEnum\": \"BAR\",\n" - + " \"repeatedInt32\": [1234, 234],\n" - + " \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n" - + " \"repeatedUint32\": [5678, 678],\n" - + " \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n" - + " \"repeatedSint32\": [9012, 10],\n" - + " \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n" - + " \"repeatedFixed32\": [3456, 456],\n" - + " \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n" - + " \"repeatedSfixed32\": [7890, 890],\n" - + " \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n" - + " \"repeatedFloat\": [1.5, 11.5],\n" - + " \"repeatedDouble\": [1.25, 11.25],\n" - + " \"repeatedBool\": [true, true],\n" - + " \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n" - + " \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n" - + " \"repeatedNestedMessage\": [{\n" - + " \"value\": 100\n" - + " }, {\n" - + " \"value\": 200\n" - + " }],\n" - + " \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n" - + "}", + + " \"optionalInt32\": 1234,\n" + + " \"optionalInt64\": \"1234567890123456789\",\n" + + " \"optionalUint32\": 5678,\n" + + " \"optionalUint64\": \"2345678901234567890\",\n" + + " \"optionalSint32\": 9012,\n" + + " \"optionalSint64\": \"3456789012345678901\",\n" + + " \"optionalFixed32\": 3456,\n" + + " \"optionalFixed64\": \"4567890123456789012\",\n" + + " \"optionalSfixed32\": 7890,\n" + + " \"optionalSfixed64\": \"5678901234567890123\",\n" + + " \"optionalFloat\": 1.5,\n" + + " \"optionalDouble\": 1.25,\n" + + " \"optionalBool\": true,\n" + + " \"optionalString\": \"Hello world!\",\n" + + " \"optionalBytes\": \"AAEC\",\n" + + " \"optionalNestedMessage\": {\n" + + " \"value\": 100\n" + + " },\n" + + " \"optionalNestedEnum\": \"BAR\",\n" + + " \"repeatedInt32\": [1234, 234],\n" + + " \"repeatedInt64\": [\"1234567890123456789\", \"234567890123456789\"],\n" + + " \"repeatedUint32\": [5678, 678],\n" + + " \"repeatedUint64\": [\"2345678901234567890\", \"345678901234567890\"],\n" + + " \"repeatedSint32\": [9012, 10],\n" + + " \"repeatedSint64\": [\"3456789012345678901\", \"456789012345678901\"],\n" + + " \"repeatedFixed32\": [3456, 456],\n" + + " \"repeatedFixed64\": [\"4567890123456789012\", \"567890123456789012\"],\n" + + " \"repeatedSfixed32\": [7890, 890],\n" + + " \"repeatedSfixed64\": [\"5678901234567890123\", \"678901234567890123\"],\n" + + " \"repeatedFloat\": [1.5, 11.5],\n" + + " \"repeatedDouble\": [1.25, 11.25],\n" + + " \"repeatedBool\": [true, true],\n" + + " \"repeatedString\": [\"Hello world!\", \"ello world!\"],\n" + + " \"repeatedBytes\": [\"AAEC\", \"AQI=\"],\n" + + " \"repeatedNestedMessage\": [{\n" + + " \"value\": 100\n" + + " }, {\n" + + " \"value\": 200\n" + + " }],\n" + + " \"repeatedNestedEnum\": [\"BAR\", \"BAZ\"]\n" + + "}", toJsonString(message)); - + assertRoundTripEquals(message); } - + public void testUnknownEnumValues() throws Exception { TestAllTypes message = TestAllTypes.newBuilder() .setOptionalNestedEnumValue(12345) @@ -209,21 +209,22 @@ public class JsonFormatTest extends TestCase { + " \"repeatedNestedEnum\": [12345, \"FOO\"]\n" + "}", toJsonString(message)); assertRoundTripEquals(message); - + TestMap.Builder mapBuilder = TestMap.newBuilder(); mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0); mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345); TestMap mapMessage = mapBuilder.build(); assertEquals( - "{\n" - + " \"int32ToEnumMap\": {\n" - + " \"1\": \"FOO\",\n" - + " \"2\": 12345\n" - + " }\n" - + "}", toJsonString(mapMessage)); + "{\n" + + " \"int32ToEnumMap\": {\n" + + " \"1\": \"FOO\",\n" + + " \"2\": 12345\n" + + " }\n" + + "}", + toJsonString(mapMessage)); assertRoundTripEquals(mapMessage); } - + public void testSpecialFloatValues() throws Exception { TestAllTypes message = TestAllTypes.newBuilder() .addRepeatedFloat(Float.NaN) @@ -238,10 +239,10 @@ public class JsonFormatTest extends TestCase { + " \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n" + " \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n" + "}", toJsonString(message)); - + assertRoundTripEquals(message); } - + public void testParserAcceptStringForNumbericField() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); mergeFromJson( @@ -265,7 +266,7 @@ public class JsonFormatTest extends TestCase { assertEquals(1.25, message.getOptionalDouble()); assertEquals(true, message.getOptionalBool()); } - + public void testParserAcceptFloatingPointValueForIntegerField() throws Exception { // Test that numeric values like "1.000", "1e5" will also be accepted. TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -287,14 +288,14 @@ public class JsonFormatTest extends TestCase { assertEquals(expectedValues[i], builder.getRepeatedInt64(i)); assertEquals(expectedValues[i], builder.getRepeatedUint64(i)); } - + // Non-integers will still be rejected. assertRejects("optionalInt32", "1.5"); assertRejects("optionalUint32", "1.5"); assertRejects("optionalInt64", "1.5"); assertRejects("optionalUint64", "1.5"); } - + private void assertRejects(String name, String value) { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); try { @@ -312,7 +313,7 @@ public class JsonFormatTest extends TestCase { // Expected. } } - + private void assertAccepts(String name, String value) throws IOException { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); // Both numeric form and string form are accepted. @@ -320,17 +321,17 @@ public class JsonFormatTest extends TestCase { builder.clear(); mergeFromJson("{\"" + name + "\":\"" + value + "\"}", builder); } - + public void testParserRejectOutOfRangeNumericValues() throws Exception { assertAccepts("optionalInt32", String.valueOf(Integer.MAX_VALUE)); assertAccepts("optionalInt32", String.valueOf(Integer.MIN_VALUE)); assertRejects("optionalInt32", String.valueOf(Integer.MAX_VALUE + 1L)); assertRejects("optionalInt32", String.valueOf(Integer.MIN_VALUE - 1L)); - + assertAccepts("optionalUint32", String.valueOf(Integer.MAX_VALUE + 1L)); assertRejects("optionalUint32", "123456789012345"); assertRejects("optionalUint32", "-1"); - + BigInteger one = new BigInteger("1"); BigInteger maxLong = new BigInteger(String.valueOf(Long.MAX_VALUE)); BigInteger minLong = new BigInteger(String.valueOf(Long.MIN_VALUE)); @@ -351,7 +352,7 @@ public class JsonFormatTest extends TestCase { assertAccepts("optionalFloat", String.valueOf(-Float.MAX_VALUE)); assertRejects("optionalFloat", String.valueOf(Double.MAX_VALUE)); assertRejects("optionalFloat", String.valueOf(-Double.MAX_VALUE)); - + BigDecimal moreThanOne = new BigDecimal("1.000001"); BigDecimal maxDouble = new BigDecimal(Double.MAX_VALUE); BigDecimal minDouble = new BigDecimal(-Double.MAX_VALUE); @@ -360,7 +361,7 @@ public class JsonFormatTest extends TestCase { assertRejects("optionalDouble", maxDouble.multiply(moreThanOne).toString()); assertRejects("optionalDouble", minDouble.multiply(moreThanOne).toString()); } - + public void testParserAcceptNull() throws Exception { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); mergeFromJson( @@ -402,7 +403,7 @@ public class JsonFormatTest extends TestCase { + "}", builder); TestAllTypes message = builder.build(); assertEquals(TestAllTypes.getDefaultInstance(), message); - + // Repeated field elements cannot be null. try { builder = TestAllTypes.newBuilder(); @@ -414,7 +415,7 @@ public class JsonFormatTest extends TestCase { } catch (InvalidProtocolBufferException e) { // Exception expected. } - + try { builder = TestAllTypes.newBuilder(); mergeFromJson( @@ -426,14 +427,14 @@ public class JsonFormatTest extends TestCase { // Exception expected. } } - + public void testParserRejectDuplicatedFields() throws Exception { // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last // one if multiple entries have the same name. This is not the desired behavior but it can // only be fixed by using our own parser. Here we only test the cases where the names are // different but still referring to the same field. - - // Duplicated optional fields. + + // Duplicated optional fields. try { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); mergeFromJson( @@ -445,7 +446,7 @@ public class JsonFormatTest extends TestCase { } catch (InvalidProtocolBufferException e) { // Exception expected. } - + // Duplicated repeated fields. try { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -458,7 +459,7 @@ public class JsonFormatTest extends TestCase { } catch (InvalidProtocolBufferException e) { // Exception expected. } - + // Duplicated oneof fields. try { TestOneof.Builder builder = TestOneof.newBuilder(); @@ -472,7 +473,7 @@ public class JsonFormatTest extends TestCase { // Exception expected. } } - + public void testMapFields() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); builder.getMutableInt32ToInt32Map().put(1, 10); @@ -507,7 +508,7 @@ public class JsonFormatTest extends TestCase { 8, NestedMessage.newBuilder().setValue(1234).build()); builder.getMutableInt32ToEnumMap().put(9, NestedEnum.BAR); TestMap message = builder.build(); - + assertEquals( "{\n" + " \"int32ToInt32Map\": {\n" @@ -598,13 +599,13 @@ public class JsonFormatTest extends TestCase { + " }\n" + "}", toJsonString(message)); assertRoundTripEquals(message); - + // Test multiple entries. builder = TestMap.newBuilder(); builder.getMutableInt32ToInt32Map().put(1, 2); builder.getMutableInt32ToInt32Map().put(3, 4); message = builder.build(); - + assertEquals( "{\n" + " \"int32ToInt32Map\": {\n" @@ -614,7 +615,7 @@ public class JsonFormatTest extends TestCase { + "}", toJsonString(message)); assertRoundTripEquals(message); } - + public void testMapNullValueIsRejected() throws Exception { try { TestMap.Builder builder = TestMap.newBuilder(); @@ -627,7 +628,7 @@ public class JsonFormatTest extends TestCase { } catch (InvalidProtocolBufferException e) { // Exception expected. } - + try { TestMap.Builder builder = TestMap.newBuilder(); mergeFromJson( @@ -640,7 +641,7 @@ public class JsonFormatTest extends TestCase { // Exception expected. } } - + public void testParserAcceptNonQuotedObjectKey() throws Exception { TestMap.Builder builder = TestMap.newBuilder(); mergeFromJson( @@ -652,7 +653,7 @@ public class JsonFormatTest extends TestCase { assertEquals(2, message.getInt32ToInt32Map().get(1).intValue()); assertEquals(3, message.getStringToInt32Map().get("hello").intValue()); } - + public void testWrappers() throws Exception { TestWrappers.Builder builder = TestWrappers.newBuilder(); builder.getBoolValueBuilder().setValue(false); @@ -665,7 +666,7 @@ public class JsonFormatTest extends TestCase { builder.getStringValueBuilder().setValue(""); builder.getBytesValueBuilder().setValue(ByteString.EMPTY); TestWrappers message = builder.build(); - + assertEquals( "{\n" + " \"int32Value\": 0,\n" @@ -691,7 +692,7 @@ public class JsonFormatTest extends TestCase { builder.getStringValueBuilder().setValue("7"); builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[]{8})); message = builder.build(); - + assertEquals( "{\n" + " \"int32Value\": 1,\n" @@ -706,43 +707,43 @@ public class JsonFormatTest extends TestCase { + "}", toJsonString(message)); assertRoundTripEquals(message); } - + public void testTimestamp() throws Exception { TestTimestamp message = TestTimestamp.newBuilder() .setTimestampValue(TimeUtil.parseTimestamp("1970-01-01T00:00:00Z")) .build(); - + assertEquals( "{\n" + " \"timestampValue\": \"1970-01-01T00:00:00Z\"\n" + "}", toJsonString(message)); assertRoundTripEquals(message); } - + public void testDuration() throws Exception { TestDuration message = TestDuration.newBuilder() .setDurationValue(TimeUtil.parseDuration("12345s")) .build(); - + assertEquals( "{\n" + " \"durationValue\": \"12345s\"\n" + "}", toJsonString(message)); assertRoundTripEquals(message); } - + public void testFieldMask() throws Exception { TestFieldMask message = TestFieldMask.newBuilder() .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz")) .build(); - + assertEquals( "{\n" + " \"fieldMaskValue\": \"foo.bar,baz\"\n" + "}", toJsonString(message)); assertRoundTripEquals(message); } - + public void testStruct() throws Exception { // Build a struct with all possible values. TestStruct.Builder builder = TestStruct.newBuilder(); @@ -764,7 +765,7 @@ public class JsonFormatTest extends TestCase { structBuilder.getMutableFields().put( "list_value", Value.newBuilder().setListValue(listBuilder.build()).build()); TestStruct message = builder.build(); - + assertEquals( "{\n" + " \"structValue\": {\n" @@ -778,7 +779,7 @@ public class JsonFormatTest extends TestCase { + " }\n" + "}", toJsonString(message)); assertRoundTripEquals(message); - + builder = TestStruct.newBuilder(); builder.setValue(Value.newBuilder().setNullValueValue(0).build()); message = builder.build(); @@ -787,12 +788,23 @@ public class JsonFormatTest extends TestCase { + " \"value\": null\n" + "}", toJsonString(message)); assertRoundTripEquals(message); + + builder = TestStruct.newBuilder(); + listBuilder = builder.getListValueBuilder(); + listBuilder.addValues(Value.newBuilder().setNumberValue(31831.125).build()); + listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build()); + message = builder.build(); + assertEquals( + "{\n" + + " \"listValue\": [31831.125, null]\n" + + "}", toJsonString(message)); + assertRoundTripEquals(message); } - + public void testAnyFields() throws Exception { TestAllTypes content = TestAllTypes.newBuilder().setOptionalInt32(1234).build(); TestAny message = TestAny.newBuilder().setAnyValue(Any.pack(content)).build(); - + // A TypeRegistry must be provided in order to convert Any types. try { toJsonString(message); @@ -800,11 +812,11 @@ public class JsonFormatTest extends TestCase { } catch (IOException e) { // Expected. } - + JsonFormat.TypeRegistry registry = JsonFormat.TypeRegistry.newBuilder() .add(TestAllTypes.getDescriptor()).build(); JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry); - + assertEquals( "{\n" + " \"anyValue\": {\n" @@ -813,8 +825,8 @@ public class JsonFormatTest extends TestCase { + " }\n" + "}" , printer.print(message)); assertRoundTripEquals(message, registry); - - + + // Well-known types have a special formatting when embedded in Any. // // 1. Any in Any. @@ -828,7 +840,7 @@ public class JsonFormatTest extends TestCase { + " }\n" + "}", printer.print(anyMessage)); assertRoundTripEquals(anyMessage, registry); - + // 2. Wrappers in Any. anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build()); assertEquals( @@ -894,7 +906,7 @@ public class JsonFormatTest extends TestCase { + " \"value\": \"AQI=\"\n" + "}", printer.print(anyMessage)); assertRoundTripEquals(anyMessage, registry); - + // 3. Timestamp in Any. anyMessage = Any.pack(TimeUtil.parseTimestamp("1969-12-31T23:59:59Z")); assertEquals( @@ -903,7 +915,7 @@ public class JsonFormatTest extends TestCase { + " \"value\": \"1969-12-31T23:59:59Z\"\n" + "}", printer.print(anyMessage)); assertRoundTripEquals(anyMessage, registry); - + // 4. Duration in Any anyMessage = Any.pack(TimeUtil.parseDuration("12345.10s")); assertEquals( @@ -945,7 +957,7 @@ public class JsonFormatTest extends TestCase { + "}", printer.print(anyMessage)); assertRoundTripEquals(anyMessage, registry); } - + public void testParserMissingTypeUrl() throws Exception { try { Any.Builder builder = Any.newBuilder(); @@ -958,7 +970,7 @@ public class JsonFormatTest extends TestCase { // Expected. } } - + public void testParserUnexpectedTypeUrl() throws Exception { try { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -970,9 +982,9 @@ public class JsonFormatTest extends TestCase { fail("Exception is expected."); } catch (IOException e) { // Expected. - } + } } - + public void testParserRejectTrailingComma() throws Exception { try { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -1000,13 +1012,13 @@ public class JsonFormatTest extends TestCase { // // Expected. // } } - + public void testParserRejectInvalidBase64() throws Exception { assertRejects("optionalBytes", "!@#$"); // We use standard BASE64 with paddings. assertRejects("optionalBytes", "AQI"); } - + public void testParserRejectInvalidEnumValue() throws Exception { try { TestAllTypes.Builder builder = TestAllTypes.newBuilder(); @@ -1017,7 +1029,7 @@ public class JsonFormatTest extends TestCase { fail("Exception is expected."); } catch (InvalidProtocolBufferException e) { // Expected. - } + } } public void testCustomJsonName() throws Exception { @@ -1026,6 +1038,12 @@ public class JsonFormatTest extends TestCase { assertRoundTripEquals(message); } + public void testDefaultGsonDoesNotHtmlEscape() throws Exception { + TestAllTypes message = TestAllTypes.newBuilder().setOptionalString("=").build(); + assertEquals( + "{\n" + " \"optionalString\": \"=\"" + "\n}", JsonFormat.printer().print(message)); + } + public void testIncludingDefaultValueFields() throws Exception { TestAllTypes message = TestAllTypes.getDefaultInstance(); assertEquals("{\n}", JsonFormat.printer().print(message)); diff --git a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto index 509c1d69..686edc42 100644 --- a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto +++ b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto @@ -28,6 +28,36 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// 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"; package json_test; @@ -159,6 +189,7 @@ message TestFieldMask { message TestStruct { google.protobuf.Struct struct_value = 1; google.protobuf.Value value = 2; + google.protobuf.ListValue list_value = 3; } message TestAny { diff --git a/js/binary/constants.js b/js/binary/constants.js index a976e0b6..836216bf 100644 --- a/js/binary/constants.js +++ b/js/binary/constants.js @@ -41,11 +41,16 @@ goog.provide('jspb.BinaryMessage'); goog.provide('jspb.BuilderFunction'); goog.provide('jspb.ByteSource'); goog.provide('jspb.ClonerFunction'); +goog.provide('jspb.ComparerFunction'); goog.provide('jspb.ConstBinaryMessage'); +goog.provide('jspb.PrunerFunction'); goog.provide('jspb.ReaderFunction'); goog.provide('jspb.RecyclerFunction'); +goog.provide('jspb.RepeatedFieldType'); +goog.provide('jspb.ScalarFieldType'); goog.provide('jspb.WriterFunction'); + goog.forwardDeclare('jspb.Message'); goog.forwardDeclare('jsproto.BinaryExtension'); @@ -78,12 +83,30 @@ jspb.BinaryMessage = function() {}; jspb.ByteSource; +/** + * A scalar field in jspb can be a boolean, number, or string. + * @typedef {boolean|number|string} + */ +jspb.ScalarFieldType; + + +/** + * A repeated field in jspb is an array of scalars, blobs, or messages. + * @typedef {!Array| + !Array| + !Array} + */ +jspb.RepeatedFieldType; + + /** * A field in jspb can be a scalar, a block of bytes, another proto, or an * array of any of the above. - * @typedef {boolean|number|string|Uint8Array| - jspb.BinaryMessage|jsproto.BinaryExtension| - Array} + * @typedef {jspb.ScalarFieldType| + jspb.RepeatedFieldType| + !Uint8Array| + !jspb.BinaryMessage| + !jsproto.BinaryExtension} */ jspb.AnyFieldType; @@ -124,6 +147,23 @@ jspb.ReaderFunction; jspb.WriterFunction; +/** + * A pruner function removes default-valued fields and empty submessages from a + * message and returns either the pruned message or null if the entire message + * was pruned away. + * @typedef {function(?jspb.BinaryMessage):?jspb.BinaryMessage} + */ +jspb.PrunerFunction; + + +/** + * A comparer function returns true if two protos are equal. + * @typedef {!function(?jspb.ConstBinaryMessage, + * ?jspb.ConstBinaryMessage):boolean} + */ +jspb.ComparerFunction; + + /** * Field type codes, taken from proto2/public/wire_format_lite.h. * @enum {number} diff --git a/js/binary/decoder.js b/js/binary/decoder.js index 9004eff0..41094a36 100644 --- a/js/binary/decoder.js +++ b/js/binary/decoder.js @@ -223,7 +223,7 @@ jspb.BinaryIterator.prototype.next = function() { jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) { /** * Typed byte-wise view of the source buffer. - * @private {Uint8Array} + * @private {?Uint8Array} */ this.bytes_ = null; @@ -335,7 +335,7 @@ jspb.BinaryDecoder.prototype.clear = function() { /** * Returns the raw buffer. - * @return {Uint8Array} The raw buffer. + * @return {?Uint8Array} The raw buffer. */ jspb.BinaryDecoder.prototype.getBuffer = function() { return this.bytes_; @@ -631,6 +631,7 @@ jspb.BinaryDecoder.prototype.readUnsignedVarint32String = function() { return value.toString(); }; + /** * Reads a 32-bit signed variant and returns its value as a string. * @@ -950,14 +951,15 @@ jspb.BinaryDecoder.prototype.readStringWithLength = function() { * Reads a block of raw bytes from the binary stream. * * @param {number} length The number of bytes to read. - * @return {Uint8Array} The decoded block of bytes, or null if the length was - * invalid. + * @return {!Uint8Array} The decoded block of bytes, or an empty block if the + * length was invalid. */ jspb.BinaryDecoder.prototype.readBytes = function(length) { if (length < 0 || this.cursor_ + length > this.bytes_.length) { this.error_ = true; - return null; + goog.asserts.fail('Invalid byte length!'); + return new Uint8Array(0); } var result = this.bytes_.subarray(this.cursor_, this.cursor_ + length); diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js index 27342e49..d045e912 100644 --- a/js/binary/decoder_test.js +++ b/js/binary/decoder_test.js @@ -44,11 +44,11 @@ goog.require('goog.testing.asserts'); goog.require('jspb.BinaryConstants'); goog.require('jspb.BinaryDecoder'); -goog.require('jspb.BinaryWriter'); +goog.require('jspb.BinaryEncoder'); /** - * Tests raw encoding and decoding of unsigned types. + * Tests encoding and decoding of unsigned types. * @param {Function} readValue * @param {Function} writeValue * @param {number} epsilon @@ -58,34 +58,38 @@ goog.require('jspb.BinaryWriter'); */ function doTestUnsignedValue(readValue, writeValue, epsilon, upperLimit, filter) { - var writer = new jspb.BinaryWriter(); + var encoder = new jspb.BinaryEncoder(); // Encode zero and limits. - writeValue.call(writer, filter(0)); - writeValue.call(writer, filter(epsilon)); - writeValue.call(writer, filter(upperLimit)); + writeValue.call(encoder, filter(0)); + writeValue.call(encoder, filter(epsilon)); + writeValue.call(encoder, filter(upperLimit)); // Encode positive values. for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { - writeValue.call(writer, filter(cursor)); + writeValue.call(encoder, filter(cursor)); } - var reader = jspb.BinaryDecoder.alloc(writer.getResultBuffer()); + var decoder = jspb.BinaryDecoder.alloc(encoder.end()); // Check zero and limits. - assertEquals(filter(0), readValue.call(reader)); - assertEquals(filter(epsilon), readValue.call(reader)); - assertEquals(filter(upperLimit), readValue.call(reader)); + assertEquals(filter(0), readValue.call(decoder)); + assertEquals(filter(epsilon), readValue.call(decoder)); + assertEquals(filter(upperLimit), readValue.call(decoder)); // Check positive values. for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { - if (filter(cursor) != readValue.call(reader)) throw 'fail!'; + if (filter(cursor) != readValue.call(decoder)) throw 'fail!'; } + + // Encoding values outside the valid range should assert. + assertThrows(function() {writeValue.call(encoder, -1);}); + assertThrows(function() {writeValue.call(encoder, upperLimit * 1.1);}); } /** - * Tests raw encoding and decoding of signed types. + * Tests encoding and decoding of signed types. * @param {Function} readValue * @param {Function} writeValue * @param {number} epsilon @@ -96,44 +100,48 @@ function doTestUnsignedValue(readValue, */ function doTestSignedValue(readValue, writeValue, epsilon, lowerLimit, upperLimit, filter) { - var writer = new jspb.BinaryWriter(); + var encoder = new jspb.BinaryEncoder(); // Encode zero and limits. - writeValue.call(writer, filter(lowerLimit)); - writeValue.call(writer, filter(-epsilon)); - writeValue.call(writer, filter(0)); - writeValue.call(writer, filter(epsilon)); - writeValue.call(writer, filter(upperLimit)); + writeValue.call(encoder, filter(lowerLimit)); + writeValue.call(encoder, filter(-epsilon)); + writeValue.call(encoder, filter(0)); + writeValue.call(encoder, filter(epsilon)); + writeValue.call(encoder, filter(upperLimit)); var inputValues = []; // Encode negative values. for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) { var val = filter(cursor); - writeValue.call(writer, val); + writeValue.call(encoder, val); inputValues.push(val); } // Encode positive values. for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { var val = filter(cursor); - writeValue.call(writer, val); + writeValue.call(encoder, val); inputValues.push(val); } - var reader = jspb.BinaryDecoder.alloc(writer.getResultBuffer()); + var decoder = jspb.BinaryDecoder.alloc(encoder.end()); // Check zero and limits. - assertEquals(filter(lowerLimit), readValue.call(reader)); - assertEquals(filter(-epsilon), readValue.call(reader)); - assertEquals(filter(0), readValue.call(reader)); - assertEquals(filter(epsilon), readValue.call(reader)); - assertEquals(filter(upperLimit), readValue.call(reader)); + assertEquals(filter(lowerLimit), readValue.call(decoder)); + assertEquals(filter(-epsilon), readValue.call(decoder)); + assertEquals(filter(0), readValue.call(decoder)); + assertEquals(filter(epsilon), readValue.call(decoder)); + assertEquals(filter(upperLimit), readValue.call(decoder)); // Verify decoded values. for (var i = 0; i < inputValues.length; i++) { - assertEquals(inputValues[i], readValue.call(reader)); + assertEquals(inputValues[i], readValue.call(decoder)); } + + // Encoding values outside the valid range should assert. + assertThrows(function() {writeValue.call(encoder, lowerLimit * 1.1);}); + assertThrows(function() {writeValue.call(encoder, upperLimit * 1.1);}); } describe('binaryDecoderTest', function() { @@ -169,7 +177,7 @@ describe('binaryDecoderTest', function() { * Tests reading 64-bit integers as hash strings. */ it('testHashStrings', function() { - var writer = new jspb.BinaryWriter(); + var encoder = new jspb.BinaryEncoder(); var hashA = String.fromCharCode(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); @@ -180,17 +188,17 @@ describe('binaryDecoderTest', function() { var hashD = String.fromCharCode(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); - writer.rawWriteVarintHash64(hashA); - writer.rawWriteVarintHash64(hashB); - writer.rawWriteVarintHash64(hashC); - writer.rawWriteVarintHash64(hashD); + encoder.writeVarintHash64(hashA); + encoder.writeVarintHash64(hashB); + encoder.writeVarintHash64(hashC); + encoder.writeVarintHash64(hashD); - writer.rawWriteFixedHash64(hashA); - writer.rawWriteFixedHash64(hashB); - writer.rawWriteFixedHash64(hashC); - writer.rawWriteFixedHash64(hashD); + encoder.writeFixedHash64(hashA); + encoder.writeFixedHash64(hashB); + encoder.writeFixedHash64(hashC); + encoder.writeFixedHash64(hashD); - var decoder = jspb.BinaryDecoder.alloc(writer.getResultBuffer()); + var decoder = jspb.BinaryDecoder.alloc(encoder.end()); assertEquals(hashA, decoder.readVarintHash64()); assertEquals(hashB, decoder.readVarintHash64()); @@ -214,8 +222,8 @@ describe('binaryDecoderTest', function() { assertThrows(function() {decoder.readUint64()}); // Overlong varints should trigger assertions. - decoder.setBlock( - [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0]); + decoder.setBlock([255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 0]); assertThrows(function() {decoder.readUnsignedVarint64()}); decoder.reset(); assertThrows(function() {decoder.readSignedVarint64()}); @@ -244,61 +252,61 @@ describe('binaryDecoderTest', function() { /** - * Tests raw encoding and decoding of unsigned integers. + * Tests encoding and decoding of unsigned integers. */ - it('testRawUnsigned', function() { + it('testUnsignedIntegers', function() { doTestUnsignedValue( jspb.BinaryDecoder.prototype.readUint8, - jspb.BinaryWriter.prototype.rawWriteUint8, + jspb.BinaryEncoder.prototype.writeUint8, 1, 0xFF, Math.round); doTestUnsignedValue( jspb.BinaryDecoder.prototype.readUint16, - jspb.BinaryWriter.prototype.rawWriteUint16, + jspb.BinaryEncoder.prototype.writeUint16, 1, 0xFFFF, Math.round); doTestUnsignedValue( jspb.BinaryDecoder.prototype.readUint32, - jspb.BinaryWriter.prototype.rawWriteUint32, + jspb.BinaryEncoder.prototype.writeUint32, 1, 0xFFFFFFFF, Math.round); doTestUnsignedValue( jspb.BinaryDecoder.prototype.readUint64, - jspb.BinaryWriter.prototype.rawWriteUint64, + jspb.BinaryEncoder.prototype.writeUint64, 1, Math.pow(2, 64) - 1025, Math.round); }); /** - * Tests raw encoding and decoding of signed integers. + * Tests encoding and decoding of signed integers. */ - it('testRawSigned', function() { + it('testSignedIntegers', function() { doTestSignedValue( jspb.BinaryDecoder.prototype.readInt8, - jspb.BinaryWriter.prototype.rawWriteInt8, + jspb.BinaryEncoder.prototype.writeInt8, 1, -0x80, 0x7F, Math.round); doTestSignedValue( jspb.BinaryDecoder.prototype.readInt16, - jspb.BinaryWriter.prototype.rawWriteInt16, + jspb.BinaryEncoder.prototype.writeInt16, 1, -0x8000, 0x7FFF, Math.round); doTestSignedValue( jspb.BinaryDecoder.prototype.readInt32, - jspb.BinaryWriter.prototype.rawWriteInt32, + jspb.BinaryEncoder.prototype.writeInt32, 1, -0x80000000, 0x7FFFFFFF, Math.round); doTestSignedValue( jspb.BinaryDecoder.prototype.readInt64, - jspb.BinaryWriter.prototype.rawWriteInt64, + jspb.BinaryEncoder.prototype.writeInt64, 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round); }); /** - * Tests raw encoding and decoding of floats. + * Tests encoding and decoding of floats. */ - it('testRawFloats', function() { + it('testFloats', function() { /** * @param {number} x * @return {number} @@ -310,7 +318,7 @@ describe('binaryDecoderTest', function() { } doTestSignedValue( jspb.BinaryDecoder.prototype.readFloat, - jspb.BinaryWriter.prototype.rawWriteFloat, + jspb.BinaryEncoder.prototype.writeFloat, jspb.BinaryConstants.FLOAT32_EPS, -jspb.BinaryConstants.FLOAT32_MAX, jspb.BinaryConstants.FLOAT32_MAX, @@ -318,7 +326,7 @@ describe('binaryDecoderTest', function() { doTestSignedValue( jspb.BinaryDecoder.prototype.readDouble, - jspb.BinaryWriter.prototype.rawWriteDouble, + jspb.BinaryEncoder.prototype.writeDouble, jspb.BinaryConstants.FLOAT64_EPS * 10, -jspb.BinaryConstants.FLOAT64_MAX, jspb.BinaryConstants.FLOAT64_MAX, diff --git a/js/binary/encoder.js b/js/binary/encoder.js new file mode 100644 index 00000000..c9b0c2ae --- /dev/null +++ b/js/binary/encoder.js @@ -0,0 +1,430 @@ +// 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. + +/** + * @fileoverview BinaryEncode defines methods for encoding Javascript values + * into arrays of bytes compatible with the Protocol Buffer wire format. + * + * @author aappleby@google.com (Austin Appleby) + */ + +goog.provide('jspb.BinaryEncoder'); + +goog.require('goog.asserts'); +goog.require('jspb.BinaryConstants'); +goog.require('jspb.utils'); + + + +/** + * BinaryEncoder implements encoders for all the wire types specified in + * https://developers.google.com/protocol-buffers/docs/encoding. + * + * @constructor + * @struct + */ +jspb.BinaryEncoder = function() { + /** @private {!Array.} */ + this.buffer_ = []; +}; + + +/** + * @return {number} + */ +jspb.BinaryEncoder.prototype.length = function() { + return this.buffer_.length; +}; + + +/** + * @return {!Array.} + */ +jspb.BinaryEncoder.prototype.end = function() { + var buffer = this.buffer_; + this.buffer_ = []; + return buffer; +}; + + +/** + * Encodes a 64-bit integer in 32:32 split representation into its wire-format + * varint representation and stores it in the buffer. + * @param {number} lowBits The low 32 bits of the int. + * @param {number} highBits The high 32 bits of the int. + */ +jspb.BinaryEncoder.prototype.writeSplitVarint64 = function(lowBits, highBits) { + goog.asserts.assert(lowBits == Math.floor(lowBits)); + goog.asserts.assert(highBits == Math.floor(highBits)); + goog.asserts.assert((lowBits >= 0) && + (lowBits < jspb.BinaryConstants.TWO_TO_32)); + goog.asserts.assert((highBits >= 0) && + (highBits < jspb.BinaryConstants.TWO_TO_32)); + + // Break the binary representation into chunks of 7 bits, set the 8th bit + // in each chunk if it's not the final chunk, and append to the result. + while (highBits > 0 || lowBits > 127) { + this.buffer_.push((lowBits & 0x7f) | 0x80); + lowBits = ((lowBits >>> 7) | (highBits << 25)) >>> 0; + highBits = highBits >>> 7; + } + this.buffer_.push(lowBits); +}; + + +/** + * Encodes a 32-bit unsigned integer into its wire-format varint representation + * and stores it in the buffer. + * @param {number} value The integer to convert. + */ +jspb.BinaryEncoder.prototype.writeUnsignedVarint32 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= 0) && + (value < jspb.BinaryConstants.TWO_TO_32)); + + while (value > 127) { + this.buffer_.push((value & 0x7f) | 0x80); + value = value >>> 7; + } + + this.buffer_.push(value); +}; + + +/** + * Encodes a 32-bit signed integer into its wire-format varint representation + * and stores it in the buffer. + * @param {number} value The integer to convert. + */ +jspb.BinaryEncoder.prototype.writeSignedVarint32 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && + (value < jspb.BinaryConstants.TWO_TO_31)); + + // Use the unsigned version if the value is not negative. + if (value >= 0) { + this.writeUnsignedVarint32(value); + return; + } + + // Write nine bytes with a _signed_ right shift so we preserve the sign bit. + for (var i = 0; i < 9; i++) { + this.buffer_.push((value & 0x7f) | 0x80); + value = value >> 7; + } + + // The above loop writes out 63 bits, so the last byte is always the sign bit + // which is always set for negative numbers. + this.buffer_.push(1); +}; + + +/** + * Encodes a 64-bit unsigned integer into its wire-format varint representation + * and stores it in the buffer. Integers that are not representable in 64 bits + * will be truncated. + * @param {number} value The integer to convert. + */ +jspb.BinaryEncoder.prototype.writeUnsignedVarint64 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= 0) && + (value < jspb.BinaryConstants.TWO_TO_64)); + jspb.utils.splitInt64(value); + this.writeSplitVarint64(jspb.utils.split64Low, + jspb.utils.split64High); +}; + + +/** + * Encodes a 64-bit signed integer into its wire-format varint representation + * and stores it in the buffer. Integers that are not representable in 64 bits + * will be truncated. + * @param {number} value The integer to convert. + */ +jspb.BinaryEncoder.prototype.writeSignedVarint64 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && + (value < jspb.BinaryConstants.TWO_TO_63)); + jspb.utils.splitInt64(value); + this.writeSplitVarint64(jspb.utils.split64Low, + jspb.utils.split64High); +}; + + +/** + * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint + * representation and stores it in the buffer. + * @param {number} value The integer to convert. + */ +jspb.BinaryEncoder.prototype.writeZigzagVarint32 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && + (value < jspb.BinaryConstants.TWO_TO_31)); + this.writeUnsignedVarint32(((value << 1) ^ (value >> 31)) >>> 0); +}; + + +/** + * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint + * representation and stores it in the buffer. Integers not representable in 64 + * bits will be truncated. + * @param {number} value The integer to convert. + */ +jspb.BinaryEncoder.prototype.writeZigzagVarint64 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && + (value < jspb.BinaryConstants.TWO_TO_63)); + jspb.utils.splitZigzag64(value); + this.writeSplitVarint64(jspb.utils.split64Low, + jspb.utils.split64High); +}; + + +/** + * Writes a 8-bit unsigned integer to the buffer. Numbers outside the range + * [0,2^8) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeUint8 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= 0) && (value < 256)); + this.buffer_.push((value >>> 0) & 0xFF); +}; + + +/** + * Writes a 16-bit unsigned integer to the buffer. Numbers outside the + * range [0,2^16) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeUint16 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= 0) && (value < 65536)); + this.buffer_.push((value >>> 0) & 0xFF); + this.buffer_.push((value >>> 8) & 0xFF); +}; + + +/** + * Writes a 32-bit unsigned integer to the buffer. Numbers outside the + * range [0,2^32) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeUint32 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= 0) && + (value < jspb.BinaryConstants.TWO_TO_32)); + this.buffer_.push((value >>> 0) & 0xFF); + this.buffer_.push((value >>> 8) & 0xFF); + this.buffer_.push((value >>> 16) & 0xFF); + this.buffer_.push((value >>> 24) & 0xFF); +}; + + +/** + * Writes a 64-bit unsigned integer to the buffer. Numbers outside the + * range [0,2^64) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeUint64 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= 0) && + (value < jspb.BinaryConstants.TWO_TO_64)); + jspb.utils.splitUint64(value); + this.writeUint32(jspb.utils.split64Low); + this.writeUint32(jspb.utils.split64High); +}; + + +/** + * Writes a 8-bit integer to the buffer. Numbers outside the range + * [-2^7,2^7) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeInt8 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -128) && (value < 128)); + this.buffer_.push((value >>> 0) & 0xFF); +}; + + +/** + * Writes a 16-bit integer to the buffer. Numbers outside the range + * [-2^15,2^15) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeInt16 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -32768) && (value < 32768)); + this.buffer_.push((value >>> 0) & 0xFF); + this.buffer_.push((value >>> 8) & 0xFF); +}; + + +/** + * Writes a 32-bit integer to the buffer. Numbers outside the range + * [-2^31,2^31) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeInt32 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && + (value < jspb.BinaryConstants.TWO_TO_31)); + this.buffer_.push((value >>> 0) & 0xFF); + this.buffer_.push((value >>> 8) & 0xFF); + this.buffer_.push((value >>> 16) & 0xFF); + this.buffer_.push((value >>> 24) & 0xFF); +}; + + +/** + * Writes a 64-bit integer to the buffer. Numbers outside the range + * [-2^63,2^63) will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeInt64 = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && + (value < jspb.BinaryConstants.TWO_TO_63)); + jspb.utils.splitInt64(value); + this.writeUint32(jspb.utils.split64Low); + this.writeUint32(jspb.utils.split64High); +}; + + +/** + * Writes a single-precision floating point value to the buffer. Numbers + * requiring more than 32 bits of precision will be truncated. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeFloat = function(value) { + goog.asserts.assert((value >= -jspb.BinaryConstants.FLOAT32_MAX) && + (value <= jspb.BinaryConstants.FLOAT32_MAX)); + jspb.utils.splitFloat32(value); + this.writeUint32(jspb.utils.split64Low); +}; + + +/** + * Writes a double-precision floating point value to the buffer. As this is + * the native format used by JavaScript, no precision will be lost. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeDouble = function(value) { + goog.asserts.assert((value >= -jspb.BinaryConstants.FLOAT64_MAX) && + (value <= jspb.BinaryConstants.FLOAT64_MAX)); + jspb.utils.splitFloat64(value); + this.writeUint32(jspb.utils.split64Low); + this.writeUint32(jspb.utils.split64High); +}; + + +/** + * Writes a boolean value to the buffer as a varint. + * @param {boolean} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeBool = function(value) { + goog.asserts.assert(goog.isBoolean(value)); + this.buffer_.push(value ? 1 : 0); +}; + + +/** + * Writes an enum value to the buffer as a varint. + * @param {number} value The value to write. + */ +jspb.BinaryEncoder.prototype.writeEnum = function(value) { + goog.asserts.assert(value == Math.floor(value)); + goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && + (value < jspb.BinaryConstants.TWO_TO_31)); + this.writeSignedVarint32(value); +}; + + +/** + * Writes an arbitrary byte array to the buffer. + * @param {!Uint8Array} bytes The array of bytes to write. + */ +jspb.BinaryEncoder.prototype.writeBytes = function(bytes) { + this.buffer_.push.apply(this.buffer_, bytes); +}; + + +/** + * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the + * buffer as a varint. + * @param {string} hash The hash to write. + */ +jspb.BinaryEncoder.prototype.writeVarintHash64 = function(hash) { + jspb.utils.splitHash64(hash); + this.writeSplitVarint64(jspb.utils.split64Low, + jspb.utils.split64High); +}; + + +/** + * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the + * buffer as a fixed64. + * @param {string} hash The hash to write. + */ +jspb.BinaryEncoder.prototype.writeFixedHash64 = function(hash) { + jspb.utils.splitHash64(hash); + this.writeUint32(jspb.utils.split64Low); + this.writeUint32(jspb.utils.split64High); +}; + + +/** + * Writes a UTF16 Javascript string to the buffer encoded as UTF8. + * TODO(aappleby): Add support for surrogate pairs, reject unpaired surrogates. + * @param {string} value The string to write. + * @return {number} The number of bytes used to encode the string. + */ +jspb.BinaryEncoder.prototype.writeString = function(value) { + var oldLength = this.buffer_.length; + + // UTF16 to UTF8 conversion loop swiped from goog.crypt.stringToUtf8ByteArray. + for (var i = 0; i < value.length; i++) { + var c = value.charCodeAt(i); + if (c < 128) { + this.buffer_.push(c); + } else if (c < 2048) { + this.buffer_.push((c >> 6) | 192); + this.buffer_.push((c & 63) | 128); + } else { + this.buffer_.push((c >> 12) | 224); + this.buffer_.push(((c >> 6) & 63) | 128); + this.buffer_.push((c & 63) | 128); + } + } + + var length = this.buffer_.length - oldLength; + return length; +}; diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js index 3b4aa17f..14d0f42e 100644 --- a/js/binary/proto_test.js +++ b/js/binary/proto_test.js @@ -30,7 +30,9 @@ // Test suite is written using Jasmine -- see http://jasmine.github.io/ +goog.require('goog.crypt.base64'); goog.require('goog.testing.asserts'); +goog.require('jspb.Message'); // CommonJS-LoadFromFile: ../testbinary_pb proto.jspb.test goog.require('proto.jspb.test.ExtendsWithMessage'); @@ -38,9 +40,61 @@ goog.require('proto.jspb.test.ForeignEnum'); goog.require('proto.jspb.test.ForeignMessage'); goog.require('proto.jspb.test.TestAllTypes'); goog.require('proto.jspb.test.TestExtendable'); +goog.require('proto.jspb.test.extendOptionalBool'); +goog.require('proto.jspb.test.extendOptionalBytes'); +goog.require('proto.jspb.test.extendOptionalDouble'); +goog.require('proto.jspb.test.extendOptionalFixed32'); +goog.require('proto.jspb.test.extendOptionalFixed64'); +goog.require('proto.jspb.test.extendOptionalFloat'); +goog.require('proto.jspb.test.extendOptionalForeignEnum'); +goog.require('proto.jspb.test.extendOptionalInt32'); +goog.require('proto.jspb.test.extendOptionalInt64'); +goog.require('proto.jspb.test.extendOptionalSfixed32'); +goog.require('proto.jspb.test.extendOptionalSfixed64'); +goog.require('proto.jspb.test.extendOptionalSint32'); +goog.require('proto.jspb.test.extendOptionalSint64'); +goog.require('proto.jspb.test.extendOptionalString'); +goog.require('proto.jspb.test.extendOptionalUint32'); +goog.require('proto.jspb.test.extendOptionalUint64'); +goog.require('proto.jspb.test.extendPackedRepeatedBoolList'); +goog.require('proto.jspb.test.extendPackedRepeatedDoubleList'); +goog.require('proto.jspb.test.extendPackedRepeatedFixed32List'); +goog.require('proto.jspb.test.extendPackedRepeatedFixed64List'); +goog.require('proto.jspb.test.extendPackedRepeatedFloatList'); +goog.require('proto.jspb.test.extendPackedRepeatedForeignEnumList'); +goog.require('proto.jspb.test.extendPackedRepeatedInt32List'); +goog.require('proto.jspb.test.extendPackedRepeatedInt64List'); +goog.require('proto.jspb.test.extendPackedRepeatedSfixed32List'); +goog.require('proto.jspb.test.extendPackedRepeatedSfixed64List'); +goog.require('proto.jspb.test.extendPackedRepeatedSint32List'); +goog.require('proto.jspb.test.extendPackedRepeatedSint64List'); +goog.require('proto.jspb.test.extendPackedRepeatedUint32List'); +goog.require('proto.jspb.test.extendPackedRepeatedUint64List'); +goog.require('proto.jspb.test.extendRepeatedBoolList'); +goog.require('proto.jspb.test.extendRepeatedBytesList'); +goog.require('proto.jspb.test.extendRepeatedDoubleList'); +goog.require('proto.jspb.test.extendRepeatedFixed32List'); +goog.require('proto.jspb.test.extendRepeatedFixed64List'); +goog.require('proto.jspb.test.extendRepeatedFloatList'); +goog.require('proto.jspb.test.extendRepeatedForeignEnumList'); +goog.require('proto.jspb.test.extendRepeatedInt32List'); +goog.require('proto.jspb.test.extendRepeatedInt64List'); +goog.require('proto.jspb.test.extendRepeatedSfixed32List'); +goog.require('proto.jspb.test.extendRepeatedSfixed64List'); +goog.require('proto.jspb.test.extendRepeatedSint32List'); +goog.require('proto.jspb.test.extendRepeatedSint64List'); +goog.require('proto.jspb.test.extendRepeatedStringList'); +goog.require('proto.jspb.test.extendRepeatedUint32List'); +goog.require('proto.jspb.test.extendRepeatedUint64List'); + var suite = {}; +var BYTES = new Uint8Array([1, 2, 8, 9]); + +var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES); + + /** * Helper: fill all fields on a TestAllTypes message. * @param {proto.jspb.test.TestAllTypes} msg @@ -62,7 +116,7 @@ function fillAllFields(msg) { msg.setOptionalDouble(-1.5); msg.setOptionalBool(true); msg.setOptionalString('hello world'); - msg.setOptionalBytes('bytes'); + msg.setOptionalBytes(BYTES); msg.setOptionalGroup(new proto.jspb.test.TestAllTypes.OptionalGroup()); msg.getOptionalGroup().setA(100); var submsg = new proto.jspb.test.ForeignMessage(); @@ -71,6 +125,7 @@ function fillAllFields(msg) { msg.setOptionalForeignEnum(proto.jspb.test.ForeignEnum.FOREIGN_FOO); msg.setOneofString('oneof'); + msg.setRepeatedInt32List([-42]); msg.setRepeatedInt64List([-0x7fffffff00000000]); msg.setRepeatedUint32List([0x80000000]); @@ -85,7 +140,7 @@ function fillAllFields(msg) { msg.setRepeatedDoubleList([-1.5]); msg.setRepeatedBoolList([true]); msg.setRepeatedStringList(['hello world']); - msg.setRepeatedBytesList(['bytes']); + msg.setRepeatedBytesList([BYTES, BYTES]); msg.setRepeatedGroupList([new proto.jspb.test.TestAllTypes.RepeatedGroup()]); msg.getRepeatedGroupList()[0].setA(100); submsg = new proto.jspb.test.ForeignMessage(); @@ -106,106 +161,115 @@ function fillAllFields(msg) { msg.setPackedRepeatedFloatList([1.5]); msg.setPackedRepeatedDoubleList([-1.5]); msg.setPackedRepeatedBoolList([true]); + } /** - * Helper: compare a bytes field to a string with codepoints 0--255. + * Helper: compare a bytes field to an expected value * @param {Uint8Array|string} arr - * @param {string} str + * @param {Uint8Array} expected * @return {boolean} */ -function bytesCompare(arr, str) { - if (arr.length != str.length) { +function bytesCompare(arr, expected) { + if (goog.isString(arr)) { + arr = goog.crypt.base64.decodeStringToUint8Array(arr); + } + if (arr.length != expected.length) { return false; } - if (typeof arr == 'string') { - for (var i = 0; i < arr.length; i++) { - if (arr.charCodeAt(i) != str.charCodeAt(i)) { - return false; - } + for (var i = 0; i < arr.length; i++) { + if (arr[i] != expected[i]) { + return false; } - return true; - } else { - for (var i = 0; i < arr.length; i++) { - if (arr[i] != str.charCodeAt(i)) { - return false; - } - } - return true; } + return true; } /** * Helper: verify contents of given TestAllTypes message as set by * fillAllFields(). - * @param {proto.jspb.test.TestAllTypes} msg + * @param {proto.jspb.test.TestAllTypes} original + * @param {proto.jspb.test.TestAllTypes} copy */ -function checkAllFields(msg) { - assertEquals(msg.getOptionalInt32(), -42); - assertEquals(msg.getOptionalInt64(), -0x7fffffff00000000); - assertEquals(msg.getOptionalUint32(), 0x80000000); - assertEquals(msg.getOptionalUint64(), 0xf000000000000000); - assertEquals(msg.getOptionalSint32(), -100); - assertEquals(msg.getOptionalSint64(), -0x8000000000000000); - assertEquals(msg.getOptionalFixed32(), 1234); - assertEquals(msg.getOptionalFixed64(), 0x1234567800000000); - assertEquals(msg.getOptionalSfixed32(), -1234); - assertEquals(msg.getOptionalSfixed64(), -0x1234567800000000); - assertEquals(msg.getOptionalFloat(), 1.5); - assertEquals(msg.getOptionalDouble(), -1.5); - assertEquals(msg.getOptionalBool(), true); - assertEquals(msg.getOptionalString(), 'hello world'); - assertEquals(true, bytesCompare(msg.getOptionalBytes(), 'bytes')); - assertEquals(msg.getOptionalGroup().getA(), 100); - assertEquals(msg.getOptionalForeignMessage().getC(), 16); - assertEquals(msg.getOptionalForeignEnum(), +function checkAllFields(original, copy) { + assertTrue(jspb.Message.equals(original, copy)); + + assertEquals(copy.getOptionalInt32(), -42); + assertEquals(copy.getOptionalInt64(), -0x7fffffff00000000); + assertEquals(copy.getOptionalUint32(), 0x80000000); + assertEquals(copy.getOptionalUint64(), 0xf000000000000000); + assertEquals(copy.getOptionalSint32(), -100); + assertEquals(copy.getOptionalSint64(), -0x8000000000000000); + assertEquals(copy.getOptionalFixed32(), 1234); + assertEquals(copy.getOptionalFixed64(), 0x1234567800000000); + assertEquals(copy.getOptionalSfixed32(), -1234); + assertEquals(copy.getOptionalSfixed64(), -0x1234567800000000); + assertEquals(copy.getOptionalFloat(), 1.5); + assertEquals(copy.getOptionalDouble(), -1.5); + assertEquals(copy.getOptionalBool(), true); + assertEquals(copy.getOptionalString(), 'hello world'); + assertEquals(true, bytesCompare(copy.getOptionalBytes(), BYTES)); + assertEquals(true, bytesCompare(copy.getOptionalBytes_asU8(), BYTES)); + assertEquals( + copy.getOptionalBytes_asB64(), goog.crypt.base64.encodeByteArray(BYTES)); + + assertEquals(copy.getOptionalGroup().getA(), 100); + assertEquals(copy.getOptionalForeignMessage().getC(), 16); + assertEquals(copy.getOptionalForeignEnum(), proto.jspb.test.ForeignEnum.FOREIGN_FOO); - assertEquals(msg.getOneofString(), 'oneof'); - assertEquals(msg.getOneofFieldCase(), + + + assertEquals(copy.getOneofString(), 'oneof'); + assertEquals(copy.getOneofFieldCase(), proto.jspb.test.TestAllTypes.OneofFieldCase.ONEOF_STRING); - assertElementsEquals(msg.getRepeatedInt32List(), [-42]); - assertElementsEquals(msg.getRepeatedInt64List(), [-0x7fffffff00000000]); - assertElementsEquals(msg.getRepeatedUint32List(), [0x80000000]); - assertElementsEquals(msg.getRepeatedUint64List(), [0xf000000000000000]); - assertElementsEquals(msg.getRepeatedSint32List(), [-100]); - assertElementsEquals(msg.getRepeatedSint64List(), [-0x8000000000000000]); - assertElementsEquals(msg.getRepeatedFixed32List(), [1234]); - assertElementsEquals(msg.getRepeatedFixed64List(), [0x1234567800000000]); - assertElementsEquals(msg.getRepeatedSfixed32List(), [-1234]); - assertElementsEquals(msg.getRepeatedSfixed64List(), [-0x1234567800000000]); - assertElementsEquals(msg.getRepeatedFloatList(), [1.5]); - assertElementsEquals(msg.getRepeatedDoubleList(), [-1.5]); - assertElementsEquals(msg.getRepeatedBoolList(), [true]); - assertElementsEquals(msg.getRepeatedStringList(), ['hello world']); - assertEquals(msg.getRepeatedBytesList().length, 1); - assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], 'bytes')); - assertEquals(msg.getRepeatedGroupList().length, 1); - assertEquals(msg.getRepeatedGroupList()[0].getA(), 100); - assertEquals(msg.getRepeatedForeignMessageList().length, 1); - assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000); - assertElementsEquals(msg.getRepeatedForeignEnumList(), + assertElementsEquals(copy.getRepeatedInt32List(), [-42]); + assertElementsEquals(copy.getRepeatedInt64List(), [-0x7fffffff00000000]); + assertElementsEquals(copy.getRepeatedUint32List(), [0x80000000]); + assertElementsEquals(copy.getRepeatedUint64List(), [0xf000000000000000]); + assertElementsEquals(copy.getRepeatedSint32List(), [-100]); + assertElementsEquals(copy.getRepeatedSint64List(), [-0x8000000000000000]); + assertElementsEquals(copy.getRepeatedFixed32List(), [1234]); + assertElementsEquals(copy.getRepeatedFixed64List(), [0x1234567800000000]); + assertElementsEquals(copy.getRepeatedSfixed32List(), [-1234]); + assertElementsEquals(copy.getRepeatedSfixed64List(), [-0x1234567800000000]); + assertElementsEquals(copy.getRepeatedFloatList(), [1.5]); + assertElementsEquals(copy.getRepeatedDoubleList(), [-1.5]); + assertElementsEquals(copy.getRepeatedBoolList(), [true]); + assertElementsEquals(copy.getRepeatedStringList(), ['hello world']); + assertEquals(copy.getRepeatedBytesList().length, 2); + assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[0], BYTES)); + assertEquals(true, bytesCompare(copy.getRepeatedBytesList()[0], BYTES)); + assertEquals(true, bytesCompare(copy.getRepeatedBytesList_asU8()[1], BYTES)); + assertEquals(copy.getRepeatedBytesList_asB64()[0], BYTES_B64); + assertEquals(copy.getRepeatedBytesList_asB64()[1], BYTES_B64); + assertEquals(copy.getRepeatedGroupList().length, 1); + assertEquals(copy.getRepeatedGroupList()[0].getA(), 100); + assertEquals(copy.getRepeatedForeignMessageList().length, 1); + assertEquals(copy.getRepeatedForeignMessageList()[0].getC(), 1000); + assertElementsEquals(copy.getRepeatedForeignEnumList(), [proto.jspb.test.ForeignEnum.FOREIGN_FOO]); - assertElementsEquals(msg.getPackedRepeatedInt32List(), [-42]); - assertElementsEquals(msg.getPackedRepeatedInt64List(), + assertElementsEquals(copy.getPackedRepeatedInt32List(), [-42]); + assertElementsEquals(copy.getPackedRepeatedInt64List(), [-0x7fffffff00000000]); - assertElementsEquals(msg.getPackedRepeatedUint32List(), [0x80000000]); - assertElementsEquals(msg.getPackedRepeatedUint64List(), [0xf000000000000000]); - assertElementsEquals(msg.getPackedRepeatedSint32List(), [-100]); - assertElementsEquals(msg.getPackedRepeatedSint64List(), + assertElementsEquals(copy.getPackedRepeatedUint32List(), [0x80000000]); + assertElementsEquals(copy.getPackedRepeatedUint64List(), + [0xf000000000000000]); + assertElementsEquals(copy.getPackedRepeatedSint32List(), [-100]); + assertElementsEquals(copy.getPackedRepeatedSint64List(), [-0x8000000000000000]); - assertElementsEquals(msg.getPackedRepeatedFixed32List(), [1234]); - assertElementsEquals(msg.getPackedRepeatedFixed64List(), + assertElementsEquals(copy.getPackedRepeatedFixed32List(), [1234]); + assertElementsEquals(copy.getPackedRepeatedFixed64List(), [0x1234567800000000]); - assertElementsEquals(msg.getPackedRepeatedSfixed32List(), [-1234]); - assertElementsEquals(msg.getPackedRepeatedSfixed64List(), + assertElementsEquals(copy.getPackedRepeatedSfixed32List(), [-1234]); + assertElementsEquals(copy.getPackedRepeatedSfixed64List(), [-0x1234567800000000]); - assertElementsEquals(msg.getPackedRepeatedFloatList(), [1.5]); - assertElementsEquals(msg.getPackedRepeatedDoubleList(), [-1.5]); - assertElementsEquals(msg.getPackedRepeatedBoolList(), [true]); + assertElementsEquals(copy.getPackedRepeatedFloatList(), [1.5]); + assertElementsEquals(copy.getPackedRepeatedDoubleList(), [-1.5]); + } @@ -242,14 +306,13 @@ function checkExtensions(msg) { msg.getExtension(proto.jspb.test.extendOptionalBool)); assertEquals('hello world', msg.getExtension(proto.jspb.test.extendOptionalString)); - assertEquals(true, - bytesCompare(msg.getExtension(proto.jspb.test.extendOptionalBytes), - 'bytes')); + assertEquals( + true, bytesCompare( + msg.getExtension(proto.jspb.test.extendOptionalBytes), BYTES)); assertEquals(16, msg.getExtension( proto.jspb.test.ExtendsWithMessage.optionalExtension).getFoo()); - assertEquals(proto.jspb.test.ForeignEnum.FOREIGN_FOO, - msg.getExtension(proto.jspb.test.extendOptionalForeignEnum)); + assertElementsEquals( msg.getExtension(proto.jspb.test.extendRepeatedInt32List), @@ -293,10 +356,10 @@ function checkExtensions(msg) { assertElementsEquals( msg.getExtension(proto.jspb.test.extendRepeatedStringList), ['hello world']); - assertEquals(true, + assertEquals( + true, bytesCompare( - msg.getExtension(proto.jspb.test.extendRepeatedBytesList)[0], - 'bytes')); + msg.getExtension(proto.jspb.test.extendRepeatedBytesList)[0], BYTES)); assertEquals(1000, msg.getExtension( proto.jspb.test.ExtendsWithMessage.repeatedExtensionList)[0] @@ -305,6 +368,7 @@ function checkExtensions(msg) { msg.getExtension(proto.jspb.test.extendRepeatedForeignEnumList), [proto.jspb.test.ForeignEnum.FOREIGN_FOO]); + assertElementsEquals( msg.getExtension(proto.jspb.test.extendPackedRepeatedInt32List), [-42]); @@ -347,6 +411,7 @@ function checkExtensions(msg) { assertElementsEquals( msg.getExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList), [proto.jspb.test.ForeignEnum.FOREIGN_FOO]); + } @@ -360,9 +425,82 @@ describe('protoBinaryTest', function() { fillAllFields(msg); var encoded = msg.serializeBinary(); var decoded = proto.jspb.test.TestAllTypes.deserializeBinary(encoded); - checkAllFields(decoded); + checkAllFields(msg, decoded); }); + /** + * Test that base64 string and Uint8Array are interchangeable in bytes fields. + */ + it('testBytesFieldsGettersInterop', function() { + var msg = new proto.jspb.test.TestAllTypes(); + // Set from a base64 string and check all the getters work. + msg.setOptionalBytes(BYTES_B64); + assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + + // Test binary serialize round trip doesn't break it. + msg = proto.jspb.test.TestAllTypes.deserializeBinary(msg.serializeBinary()); + assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + + msg = new proto.jspb.test.TestAllTypes(); + // Set from a Uint8Array and check all the getters work. + msg.setOptionalBytes(BYTES); + assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + + }); + + /** + * Test that bytes setters will receive result of any of the getters. + */ + it('testBytesFieldsSettersInterop', function() { + var msg = new proto.jspb.test.TestAllTypes(); + msg.setOptionalBytes(BYTES); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + + msg.setOptionalBytes(msg.getOptionalBytes()); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + msg.setOptionalBytes(msg.getOptionalBytes_asB64()); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + msg.setOptionalBytes(msg.getOptionalBytes_asU8()); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + }); + + /** + * Test that bytes setters will receive result of any of the getters. + */ + it('testRepeatedBytesGetters', function() { + var msg = new proto.jspb.test.TestAllTypes(); + + function assertGetters() { + assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[0])); + assertTrue(goog.isString(msg.getRepeatedBytesList_asB64()[1])); + assertTrue(msg.getRepeatedBytesList_asU8()[0] instanceof Uint8Array); + assertTrue(msg.getRepeatedBytesList_asU8()[1] instanceof Uint8Array); + + assertTrue(bytesCompare(msg.getRepeatedBytesList()[0], BYTES)); + assertTrue(bytesCompare(msg.getRepeatedBytesList()[1], BYTES)); + assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[0], BYTES)); + assertTrue(bytesCompare(msg.getRepeatedBytesList_asB64()[1], BYTES)); + assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[0], BYTES)); + assertTrue(bytesCompare(msg.getRepeatedBytesList_asU8()[1], BYTES)); + } + + msg.setRepeatedBytesList([BYTES, BYTES]); + assertGetters(); + + msg.setRepeatedBytesList([BYTES_B64, BYTES_B64]); + assertGetters(); + + msg.setRepeatedBytesList(null); + assertEquals(0, msg.getRepeatedBytesList().length); + assertEquals(0, msg.getRepeatedBytesList_asB64().length); + assertEquals(0, msg.getRepeatedBytesList_asU8().length); + }); /** * Helper: fill all extension values. @@ -397,8 +535,7 @@ describe('protoBinaryTest', function() { proto.jspb.test.extendOptionalBool, true); msg.setExtension( proto.jspb.test.extendOptionalString, 'hello world'); - msg.setExtension( - proto.jspb.test.extendOptionalBytes, 'bytes'); + msg.setExtension(proto.jspb.test.extendOptionalBytes, BYTES); var submsg = new proto.jspb.test.ExtendsWithMessage(); submsg.setFoo(16); msg.setExtension( @@ -407,6 +544,7 @@ describe('protoBinaryTest', function() { proto.jspb.test.extendOptionalForeignEnum, proto.jspb.test.ForeignEnum.FOREIGN_FOO); + msg.setExtension( proto.jspb.test.extendRepeatedInt32List, [-42]); msg.setExtension( @@ -435,8 +573,7 @@ describe('protoBinaryTest', function() { proto.jspb.test.extendRepeatedBoolList, [true]); msg.setExtension( proto.jspb.test.extendRepeatedStringList, ['hello world']); - msg.setExtension( - proto.jspb.test.extendRepeatedBytesList, ['bytes']); + msg.setExtension(proto.jspb.test.extendRepeatedBytesList, [BYTES]); submsg = new proto.jspb.test.ExtendsWithMessage(); submsg.setFoo(1000); msg.setExtension( @@ -444,6 +581,7 @@ describe('protoBinaryTest', function() { msg.setExtension(proto.jspb.test.extendRepeatedForeignEnumList, [proto.jspb.test.ForeignEnum.FOREIGN_FOO]); + msg.setExtension( proto.jspb.test.extendPackedRepeatedInt32List, [-42]); msg.setExtension( @@ -473,6 +611,7 @@ describe('protoBinaryTest', function() { proto.jspb.test.extendPackedRepeatedBoolList, [true]); msg.setExtension(proto.jspb.test.extendPackedRepeatedForeignEnumList, [proto.jspb.test.ForeignEnum.FOREIGN_FOO]); + } diff --git a/js/binary/reader.js b/js/binary/reader.js index abcd1660..15f90432 100644 --- a/js/binary/reader.js +++ b/js/binary/reader.js @@ -180,7 +180,7 @@ jspb.BinaryReader.prototype.getCursor = function() { /** * Returns the raw buffer. - * @return {Uint8Array} The raw buffer. + * @return {?Uint8Array} The raw buffer. */ jspb.BinaryReader.prototype.getBuffer = function() { return this.decoder_.getBuffer(); @@ -592,8 +592,8 @@ jspb.BinaryReader.prototype.getFieldDecoder = function() { var start = this.decoder_.getCursor(); var end = start + length; - var innerDecoder = jspb.BinaryDecoder.alloc(this.decoder_.getBuffer(), - start, length); + var innerDecoder = + jspb.BinaryDecoder.alloc(this.decoder_.getBuffer(), start, length); this.decoder_.setCursor(end); return innerDecoder; }; @@ -869,7 +869,7 @@ jspb.BinaryReader.prototype.readString = function() { * Reads a length-prefixed block of bytes from the binary stream, or returns * null if the next field in the stream has an invalid length value. * - * @return {Uint8Array} The block of bytes. + * @return {!Uint8Array} The block of bytes. */ jspb.BinaryReader.prototype.readBytes = function() { goog.asserts.assert( diff --git a/js/binary/reader_test.js b/js/binary/reader_test.js index a6482610..6f7e5d45 100644 --- a/js/binary/reader_test.js +++ b/js/binary/reader_test.js @@ -366,28 +366,28 @@ describe('binaryReaderTest', function() { var writer = new jspb.BinaryWriter(); var testSignedData = [ - '2730538252207801776', - '-2688470994844604560', - '3398529779486536359', - '3568577411627971000', - '272477188847484900', - '-6649058714086158188', - '-7695254765712060806', - '-4525541438037104029', - '-4993706538836508568', - '4990160321893729138' + '2730538252207801776', + '-2688470994844604560', + '3398529779486536359', + '3568577411627971000', + '272477188847484900', + '-6649058714086158188', + '-7695254765712060806', + '-4525541438037104029', + '-4993706538836508568', + '4990160321893729138' ]; var testUnsignedData = [ - '7822732630241694882', - '6753602971916687352', - '2399935075244442116', - '8724292567325338867', - '16948784802625696584', - '4136275908516066934', - '3575388346793700364', - '5167142028379259461', - '1557573948689737699', - '17100725280812548567' + '7822732630241694882', + '6753602971916687352', + '2399935075244442116', + '8724292567325338867', + '16948784802625696584', + '4136275908516066934', + '3575388346793700364', + '5167142028379259461', + '1557573948689737699', + '17100725280812548567' ]; for (var i = 0; i < testSignedData.length; i++) { @@ -535,7 +535,7 @@ describe('binaryReaderTest', function() { */ it('testNesting', function() { var writer = new jspb.BinaryWriter(); - var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); + var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); writer.writeInt32(1, 100); @@ -626,31 +626,15 @@ describe('binaryReaderTest', function() { writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); writer.writeString(4, 'The quick brown fox jumps over the lazy dog'); - // Write a group with a nested group inside. We use the internal - // .rawWriteVarint() to ensure the tested wire data is what we want, - // independently of any serialization logic. + // Write a group with a nested group inside. writer.writeInt32(5, sentinel); - // Start group, field 5. - writer.rawWriteVarint( - (5 << 3) + jspb.BinaryConstants.WireType.START_GROUP); - // Varint, field 42. - writer.rawWriteVarint( - (42 << 3) + jspb.BinaryConstants.WireType.VARINT); - // Varint data. - writer.rawWriteVarint(42); - // Start group, field 6. - writer.rawWriteVarint( - (6 << 3) + jspb.BinaryConstants.WireType.START_GROUP); - // Varint, field 84. - writer.rawWriteVarint( - (84 << 3) + jspb.BinaryConstants.WireType.VARINT); - writer.rawWriteVarint(42); - // End group, field 6. - writer.rawWriteVarint( - (6 << 3) + jspb.BinaryConstants.WireType.END_GROUP); - // End group, field 5. - writer.rawWriteVarint( - (5 << 3) + jspb.BinaryConstants.WireType.END_GROUP); + var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); + writer.writeGroup(5, dummyMessage, function() { + writer.writeInt64(42, 42); + writer.writeGroup(6, dummyMessage, function() { + writer.writeInt64(84, 42); + }); + }); // Write final sentinel. writer.writeInt32(6, sentinel); diff --git a/js/binary/utils.js b/js/binary/utils.js index 92600389..875ff955 100644 --- a/js/binary/utils.js +++ b/js/binary/utils.js @@ -838,63 +838,17 @@ jspb.utils.countDelimitedFields = function(buffer, start, end, field) { }; -/** - * Clones a scalar field. Pulling this out to a helper method saves us a few - * bytes of generated code. - * @param {Array} array - * @return {Array} - */ -jspb.utils.cloneRepeatedScalarField = function(array) { - return array ? array.slice() : null; -}; - - -/** - * Clones an array of messages using the provided cloner function. - * @param {Array.} messages - * @param {jspb.ClonerFunction} cloner - * @return {Array.} - */ -jspb.utils.cloneRepeatedMessageField = function(messages, cloner) { - if (messages === null) return null; - var result = []; - for (var i = 0; i < messages.length; i++) { - result.push(cloner(messages[i])); - } - return result; -}; - - -/** - * Clones an array of byte blobs. - * @param {Array.} blobs - * @return {Array.} - */ -jspb.utils.cloneRepeatedBlobField = function(blobs) { - if (blobs === null) return null; - var result = []; - for (var i = 0; i < blobs.length; i++) { - result.push(new Uint8Array(blobs[i])); - } - return result; -}; - - /** * String-ify bytes for text format. Should be optimized away in non-debug. * The returned string uses \xXX escapes for all values and is itself quoted. * [1, 31] serializes to '"\x01\x1f"'. * @param {jspb.ByteSource} byteSource The bytes to serialize. - * @param {boolean=} opt_stringIsRawBytes The string is interpreted as a series - * of raw bytes rather than base64 data. * @return {string} Stringified bytes for text format. */ -jspb.utils.debugBytesToTextFormat = function(byteSource, - opt_stringIsRawBytes) { +jspb.utils.debugBytesToTextFormat = function(byteSource) { var s = '"'; if (byteSource) { - var bytes = - jspb.utils.byteSourceToUint8Array(byteSource, opt_stringIsRawBytes); + var bytes = jspb.utils.byteSourceToUint8Array(byteSource); for (var i = 0; i < bytes.length; i++) { s += '\\x'; if (bytes[i] < 16) s += '0'; @@ -925,9 +879,8 @@ jspb.utils.debugScalarToTextFormat = function(scalar) { * exception. * @param {string} str * @return {!Uint8Array} - * @private */ -jspb.utils.stringToByteArray_ = function(str) { +jspb.utils.stringToByteArray = function(str) { var arr = new Uint8Array(str.length); for (var i = 0; i < str.length; i++) { var codepoint = str.charCodeAt(i); @@ -944,13 +897,10 @@ jspb.utils.stringToByteArray_ = function(str) { /** * Converts any type defined in jspb.ByteSource into a Uint8Array. * @param {!jspb.ByteSource} data - * @param {boolean=} opt_stringIsRawBytes Interpret a string as a series of raw - * bytes (encoded as codepoints 0--255 inclusive) rather than base64 data - * (default behavior). * @return {!Uint8Array} * @suppress {invalidCasts} */ -jspb.utils.byteSourceToUint8Array = function(data, opt_stringIsRawBytes) { +jspb.utils.byteSourceToUint8Array = function(data) { if (data.constructor === Uint8Array) { return /** @type {!Uint8Array} */(data); } @@ -967,11 +917,7 @@ jspb.utils.byteSourceToUint8Array = function(data, opt_stringIsRawBytes) { if (data.constructor === String) { data = /** @type {string} */(data); - if (opt_stringIsRawBytes) { - return jspb.utils.stringToByteArray_(data); - } else { - return goog.crypt.base64.decodeStringToUint8Array(data); - } + return goog.crypt.base64.decodeStringToUint8Array(data); } goog.asserts.fail('Type not convertible to Uint8Array.'); diff --git a/js/binary/utils_test.js b/js/binary/utils_test.js index 5c330791..518d7597 100644 --- a/js/binary/utils_test.js +++ b/js/binary/utils_test.js @@ -310,7 +310,7 @@ describe('binaryUtilsTest', function() { // NaN. jspb.utils.splitFloat32(NaN); if (!isNaN(jspb.utils.joinFloat32(jspb.utils.split64Low, - jspb.utils.split64High))) { + jspb.utils.split64High))) { throw 'fail!'; } @@ -324,7 +324,7 @@ describe('binaryUtilsTest', function() { if (opt_bits != jspb.utils.split64Low) throw 'fail!'; } if (truncate(x) != jspb.utils.joinFloat32(jspb.utils.split64Low, - jspb.utils.split64High)) { + jspb.utils.split64High)) { throw 'fail!'; } } @@ -376,7 +376,7 @@ describe('binaryUtilsTest', function() { // NaN. jspb.utils.splitFloat64(NaN); if (!isNaN(jspb.utils.joinFloat64(jspb.utils.split64Low, - jspb.utils.split64High))) { + jspb.utils.split64High))) { throw 'fail!'; } @@ -394,7 +394,7 @@ describe('binaryUtilsTest', function() { if (opt_lowBits != jspb.utils.split64Low) throw 'fail!'; } if (x != jspb.utils.joinFloat64(jspb.utils.split64Low, - jspb.utils.split64High)) { + jspb.utils.split64High)) { throw 'fail!'; } } @@ -439,16 +439,20 @@ describe('binaryUtilsTest', function() { * Tests counting packed varints. */ it('testCountVarints', function() { - var writer = new jspb.BinaryWriter(); - - var count = 0; + var values = []; for (var i = 1; i < 1000000000; i *= 1.1) { - writer.rawWriteVarint(Math.floor(i)); - count++; + values.push(Math.floor(i)); } + var writer = new jspb.BinaryWriter(); + writer.writePackedUint64(1, values); + var buffer = new Uint8Array(writer.getResultBuffer()); - assertEquals(count, jspb.utils.countVarints(buffer, 0, buffer.length)); + + // We should have two more varints than we started with - one for the field + // tag, one for the packed length. + assertEquals(values.length + 2, + jspb.utils.countVarints(buffer, 0, buffer.length)); }); @@ -625,8 +629,5 @@ describe('binaryUtilsTest', function() { // Converting base64-encoded strings into Uint8Arrays should work. check(convert(sourceBase64)); - - // Converting binary-data strings into Uint8Arrays should work. - check(convert(sourceString, /* opt_stringIsRawBytes = */ true)); }); }); diff --git a/js/binary/writer.js b/js/binary/writer.js index a1849457..be4478ee 100644 --- a/js/binary/writer.js +++ b/js/binary/writer.js @@ -60,12 +60,11 @@ goog.provide('jspb.BinaryWriter'); goog.require('goog.asserts'); goog.require('goog.crypt.base64'); goog.require('jspb.BinaryConstants'); +goog.require('jspb.BinaryEncoder'); goog.require('jspb.arith.Int64'); goog.require('jspb.arith.UInt64'); goog.require('jspb.utils'); -goog.forwardDeclare('jspb.Message'); - /** @@ -84,52 +83,31 @@ jspb.BinaryWriter = function() { this.blocks_ = []; /** - * Total number of bytes in the blocks_ array. Does _not_ include the temp - * buffer. + * Total number of bytes in the blocks_ array. Does _not_ include bytes in + * the encoder below. * @private {number} */ this.totalLength_ = 0; /** - * Temporary buffer holding a message that we're still serializing. When we - * get to a stopping point (either the start of a new submessage, or when we - * need to append a raw Uint8Array), the temp buffer will be added to the - * block array above and a new temp buffer will be created. - * @private {!Array.} + * Binary encoder holding pieces of a message that we're still serializing. + * When we get to a stopping point (either the start of a new submessage, or + * when we need to append a raw Uint8Array), the encoder's buffer will be + * added to the block array above and the encoder will be reset. + * @private {!jspb.BinaryEncoder} */ - this.temp_ = []; + this.encoder_ = new jspb.BinaryEncoder(); /** * A stack of bookmarks containing the parent blocks for each message started * via beginSubMessage(), needed as bookkeeping for endSubMessage(). * TODO(aappleby): Deprecated, users should be calling writeMessage(). - * @private {!Array.} + * @private {!Array.>} */ this.bookmarks_ = []; }; -/** - * @typedef {{block: !Array., length: number}} - * @private - */ -jspb.BinaryWriter.Bookmark_; - - -/** - * Saves the current temp buffer in the blocks_ array and starts a new one. - * @return {!Array.} Returns a reference to the old temp buffer. - * @private - */ -jspb.BinaryWriter.prototype.saveTempBuffer_ = function() { - var oldTemp = this.temp_; - this.blocks_.push(this.temp_); - this.totalLength_ += this.temp_.length; - this.temp_ = []; - return oldTemp; -}; - - /** * Append a typed array of bytes onto the buffer. * @@ -137,63 +115,77 @@ jspb.BinaryWriter.prototype.saveTempBuffer_ = function() { * @private */ jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) { - if (this.temp_.length) { - this.saveTempBuffer_(); - } + var temp = this.encoder_.end(); + this.blocks_.push(temp); this.blocks_.push(arr); - this.totalLength_ += arr.length; + this.totalLength_ += temp.length + arr.length; }; /** - * Append an untyped array of bytes onto the buffer. - * - * @param {!Array.} arr The byte array to append. - * @private - */ -jspb.BinaryWriter.prototype.appendArray_ = function(arr) { - if (this.temp_.length) { - this.saveTempBuffer_(); - } - this.temp_ = arr; -}; - - -/** - * Begins a length-delimited section by writing the field header to the current - * temp buffer and then saving it in the block array. Returns the saved block, - * which we will append the length to in endDelimited_ below. + * Begins a new message by writing the field header and returning a bookmark + * which we will use to patch in the message length to in endDelimited_ below. * @param {number} field - * @return {!jspb.BinaryWriter.Bookmark_} + * @return {!Array.} * @private */ jspb.BinaryWriter.prototype.beginDelimited_ = function(field) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - return {block: this.saveTempBuffer_(), length: this.totalLength_}; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + var bookmark = this.encoder_.end(); + this.blocks_.push(bookmark); + this.totalLength_ += bookmark.length; + bookmark.push(this.totalLength_); + return bookmark; }; /** - * Ends a length-delimited block by encoding the _change_ in length of the - * buffer to the parent block and adds the number of bytes needed to encode - * that length to the total byte length. Note that 'parentLength' _must_ be the - * total length _after_ the field header was written in beginDelimited_ above. - * @param {!jspb.BinaryWriter.Bookmark_} bookmark + * Ends a message by encoding the _change_ in length of the buffer to the + * parent block and adds the number of bytes needed to encode that length to + * the total byte length. + * @param {!Array.} bookmark * @private */ jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) { - var messageLength = this.totalLength_ + this.temp_.length - bookmark.length; + var oldLength = bookmark.pop(); + var messageLength = this.totalLength_ + this.encoder_.length() - oldLength; goog.asserts.assert(messageLength >= 0); - var bytes = 1; while (messageLength > 127) { - bookmark.block.push((messageLength & 0x7f) | 0x80); + bookmark.push((messageLength & 0x7f) | 0x80); messageLength = messageLength >>> 7; - bytes++; + this.totalLength_++; } - bookmark.block.push(messageLength); - this.totalLength_ += bytes; + bookmark.push(messageLength); + this.totalLength_++; +}; + + +/** + * Writes a pre-serialized message to the buffer. + * @param {!Uint8Array} bytes The array of bytes to write. + * @param {number} start The start of the range to write. + * @param {number} end The end of the range to write. + */ +jspb.BinaryWriter.prototype.writeSerializedMessage = function( + bytes, start, end) { + this.appendUint8Array_(bytes.subarray(start, end)); +}; + + +/** + * Writes a pre-serialized message to the buffer if the message and endpoints + * are non-null. + * @param {?Uint8Array} bytes The array of bytes to write. + * @param {?number} start The start of the range to write. + * @param {?number} end The end of the range to write. + */ +jspb.BinaryWriter.prototype.maybeWriteSerializedMessage = function( + bytes, start, end) { + if (bytes != null && start != null && end != null) { + this.writeSerializedMessage(bytes, start, end); + } }; @@ -202,7 +194,7 @@ jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) { */ jspb.BinaryWriter.prototype.reset = function() { this.blocks_ = []; - this.temp_ = []; + this.encoder_.end(); this.totalLength_ = 0; this.bookmarks_ = []; }; @@ -215,7 +207,7 @@ jspb.BinaryWriter.prototype.reset = function() { jspb.BinaryWriter.prototype.getResultBuffer = function() { goog.asserts.assert(this.bookmarks_.length == 0); - var flat = new Uint8Array(this.totalLength_ + this.temp_.length); + var flat = new Uint8Array(this.totalLength_ + this.encoder_.length()); var blocks = this.blocks_; var blockCount = blocks.length; @@ -227,8 +219,9 @@ jspb.BinaryWriter.prototype.getResultBuffer = function() { offset += block.length; } - flat.set(this.temp_, offset); - offset += this.temp_.length; + var tail = this.encoder_.end(); + flat.set(tail, offset); + offset += tail.length; // Post condition: `flattened` must have had every byte written. goog.asserts.assert(offset == flat.length); @@ -236,7 +229,6 @@ jspb.BinaryWriter.prototype.getResultBuffer = function() { // Replace our block list with the flattened block, which lets GC reclaim // the temp blocks sooner. this.blocks_ = [flat]; - this.temp_ = []; return flat; }; @@ -272,331 +264,6 @@ jspb.BinaryWriter.prototype.endSubMessage = function() { }; -/** - * Encodes a 32-bit unsigned integer into its wire-format varint representation - * and stores it in the buffer. - * @param {number} value The integer to convert. - */ -jspb.BinaryWriter.prototype.rawWriteUnsignedVarint32 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - - while (value > 127) { - this.temp_.push((value & 0x7f) | 0x80); - value = value >>> 7; - } - - this.temp_.push(value); -}; - - -/** - * Encodes a 32-bit signed integer into its wire-format varint representation - * and stores it in the buffer. - * @param {number} value The integer to convert. - */ -jspb.BinaryWriter.prototype.rawWriteSignedVarint32 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - if (value >= 0) { - this.rawWriteUnsignedVarint32(value); - return; - } - - // Write nine bytes with a _signed_ right shift so we preserve the sign bit. - for (var i = 0; i < 9; i++) { - this.temp_.push((value & 0x7f) | 0x80); - value = value >> 7; - } - - // The above loop writes out 63 bits, so the last byte is always the sign bit - // which is always set for negative numbers. - this.temp_.push(1); -}; - - -/** - * Encodes an unsigned 64-bit integer in 32:32 split representation into its - * wire-format varint representation and stores it in the buffer. - * @param {number} lowBits The low 32 bits of the int. - * @param {number} highBits The high 32 bits of the int. - */ -jspb.BinaryWriter.prototype.rawWriteSplitVarint = - function(lowBits, highBits) { - // Break the binary representation into chunks of 7 bits, set the 8th bit - // in each chunk if it's not the final chunk, and append to the result. - while (highBits > 0 || lowBits > 127) { - this.temp_.push((lowBits & 0x7f) | 0x80); - lowBits = ((lowBits >>> 7) | (highBits << 25)) >>> 0; - highBits = highBits >>> 7; - } - this.temp_.push(lowBits); -}; - - -/** - * Encodes a JavaScript integer into its wire-format varint representation and - * stores it in the buffer. Due to the way the varint encoding works this - * behaves correctly for both signed and unsigned integers, though integers - * that are not representable in 64 bits will still be truncated. - * @param {number} value The integer to convert. - */ -jspb.BinaryWriter.prototype.rawWriteVarint = function(value) { - goog.asserts.assert(value == Math.floor(value)); - jspb.utils.splitInt64(value); - this.rawWriteSplitVarint(jspb.utils.split64Low, - jspb.utils.split64High); -}; - - -/** - * Encodes a jspb.arith.{Int64,UInt64} instance into its wire-format - * varint representation and stores it in the buffer. Due to the way the varint - * encoding works this behaves correctly for both signed and unsigned integers, - * though integers that are not representable in 64 bits will still be - * truncated. - * @param {jspb.arith.Int64|jspb.arith.UInt64} value - */ -jspb.BinaryWriter.prototype.rawWriteVarintFromNum = function(value) { - this.rawWriteSplitVarint(value.lo, value.hi); -}; - - -/** - * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint - * representation and stores it in the buffer. - * @param {number} value The integer to convert. - */ -jspb.BinaryWriter.prototype.rawWriteZigzagVarint32 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - this.rawWriteUnsignedVarint32(((value << 1) ^ (value >> 31)) >>> 0); -}; - - -/** - * Encodes a JavaScript integer into its wire-format, zigzag-encoded varint - * representation and stores it in the buffer. Integers not representable in 64 - * bits will be truncated. - * @param {number} value The integer to convert. - */ -jspb.BinaryWriter.prototype.rawWriteZigzagVarint = function(value) { - goog.asserts.assert(value == Math.floor(value)); - jspb.utils.splitZigzag64(value); - this.rawWriteSplitVarint(jspb.utils.split64Low, - jspb.utils.split64High); -}; - - -/** - * Writes a raw 8-bit unsigned integer to the buffer. Numbers outside the range - * [0,2^8) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteUint8 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= 0) && (value < 256)); - this.temp_.push((value >>> 0) & 0xFF); -}; - - -/** - * Writes a raw 16-bit unsigned integer to the buffer. Numbers outside the - * range [0,2^16) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteUint16 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= 0) && (value < 65536)); - this.temp_.push((value >>> 0) & 0xFF); - this.temp_.push((value >>> 8) & 0xFF); -}; - - -/** - * Writes a raw 32-bit unsigned integer to the buffer. Numbers outside the - * range [0,2^32) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteUint32 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= 0) && - (value < jspb.BinaryConstants.TWO_TO_32)); - this.temp_.push((value >>> 0) & 0xFF); - this.temp_.push((value >>> 8) & 0xFF); - this.temp_.push((value >>> 16) & 0xFF); - this.temp_.push((value >>> 24) & 0xFF); -}; - - -/** - * Writes a raw 64-bit unsigned integer to the buffer. Numbers outside the - * range [0,2^64) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteUint64 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= 0) && - (value < jspb.BinaryConstants.TWO_TO_64)); - jspb.utils.splitUint64(value); - this.rawWriteUint32(jspb.utils.split64Low); - this.rawWriteUint32(jspb.utils.split64High); -}; - - -/** - * Writes a raw 8-bit integer to the buffer. Numbers outside the range - * [-2^7,2^7) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteInt8 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= -128) && (value < 128)); - this.temp_.push((value >>> 0) & 0xFF); -}; - - -/** - * Writes a raw 16-bit integer to the buffer. Numbers outside the range - * [-2^15,2^15) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteInt16 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= -32768) && (value < 32768)); - this.temp_.push((value >>> 0) & 0xFF); - this.temp_.push((value >>> 8) & 0xFF); -}; - - -/** - * Writes a raw 32-bit integer to the buffer. Numbers outside the range - * [-2^31,2^31) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteInt32 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && - (value < jspb.BinaryConstants.TWO_TO_31)); - this.temp_.push((value >>> 0) & 0xFF); - this.temp_.push((value >>> 8) & 0xFF); - this.temp_.push((value >>> 16) & 0xFF); - this.temp_.push((value >>> 24) & 0xFF); -}; - - -/** - * Writes a raw 64-bit integer to the buffer. Numbers outside the range - * [-2^63,2^63) will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteInt64 = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && - (value < jspb.BinaryConstants.TWO_TO_63)); - jspb.utils.splitInt64(value); - this.rawWriteUint32(jspb.utils.split64Low); - this.rawWriteUint32(jspb.utils.split64High); -}; - - -/** - * Writes a raw single-precision floating point value to the buffer. Numbers - * requiring more than 32 bits of precision will be truncated. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteFloat = function(value) { - jspb.utils.splitFloat32(value); - this.rawWriteUint32(jspb.utils.split64Low); -}; - - -/** - * Writes a raw double-precision floating point value to the buffer. As this is - * the native format used by JavaScript, no precision will be lost. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteDouble = function(value) { - jspb.utils.splitFloat64(value); - this.rawWriteUint32(jspb.utils.split64Low); - this.rawWriteUint32(jspb.utils.split64High); -}; - - -/** - * Writes a raw boolean value to the buffer as a varint. - * @param {boolean} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteBool = function(value) { - goog.asserts.assert(goog.isBoolean(value)); - this.temp_.push(~~value); -}; - - -/** - * Writes an raw enum value to the buffer as a varint. - * @param {number} value The value to write. - */ -jspb.BinaryWriter.prototype.rawWriteEnum = function(value) { - goog.asserts.assert(value == Math.floor(value)); - goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && - (value < jspb.BinaryConstants.TWO_TO_31)); - this.rawWriteSignedVarint32(value); -}; - - -/** - * Writes a raw string value to the buffer. - * @param {string} string The string to write. - */ -jspb.BinaryWriter.prototype.rawWriteUtf8String = function(string) { - for (var i = 0; i < string.length; i++) { - this.temp_.push(string.charCodeAt(i)); - } -}; - - -/** - * Writes an arbitrary raw byte array to the buffer. - * @param {!Uint8Array} bytes The array of bytes to write. - */ -jspb.BinaryWriter.prototype.rawWriteBytes = function(bytes) { - this.appendUint8Array_(bytes); -}; - - -/** - * Writes an arbitrary raw byte array to the buffer. - * @param {!Uint8Array} bytes The array of bytes to write. - * @param {number} start The start of the range to write. - * @param {number} end The end of the range to write. - */ -jspb.BinaryWriter.prototype.rawWriteByteRange = function(bytes, start, end) { - this.appendUint8Array_(bytes.subarray(start, end)); -}; - - -/** - * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the - * buffer as a varint. - * @param {string} hash The hash to write. - */ -jspb.BinaryWriter.prototype.rawWriteVarintHash64 = function(hash) { - jspb.utils.splitHash64(hash); - this.rawWriteSplitVarint(jspb.utils.split64Low, - jspb.utils.split64High); -}; - - -/** - * Writes a 64-bit hash string (8 characters @ 8 bits of data each) to the - * buffer as a fixed64. - * @param {string} hash The hash to write. - */ -jspb.BinaryWriter.prototype.rawWriteFixedHash64 = function(hash) { - jspb.utils.splitHash64(hash); - this.rawWriteUint32(jspb.utils.split64Low); - this.rawWriteUint32(jspb.utils.split64High); -}; - - /** * Encodes a (field number, wire type) tuple into a wire-format field header * and stores it in the buffer as a varint. @@ -605,11 +272,11 @@ jspb.BinaryWriter.prototype.rawWriteFixedHash64 = function(hash) { * protocol buffer documentation. * @private */ -jspb.BinaryWriter.prototype.rawWriteFieldHeader_ = +jspb.BinaryWriter.prototype.writeFieldHeader_ = function(field, wireType) { goog.asserts.assert(field >= 1 && field == Math.floor(field)); var x = field * 8 + wireType; - this.rawWriteUnsignedVarint32(x); + this.encoder_.writeUnsignedVarint32(x); }; @@ -697,8 +364,8 @@ jspb.BinaryWriter.prototype.writeAny = function(fieldType, field, value) { */ jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteSignedVarint32(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeUnsignedVarint32(value); }; @@ -710,8 +377,8 @@ jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(field, value) { */ jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteSignedVarint32(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeSignedVarint32(value); }; @@ -721,10 +388,23 @@ jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(field, value) { * @param {number?} value The value to write. * @private */ -jspb.BinaryWriter.prototype.writeVarint_ = function(field, value) { +jspb.BinaryWriter.prototype.writeUnsignedVarint64_ = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteVarint(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeUnsignedVarint64(value); +}; + + +/** + * Writes a varint field to the buffer without range checking. + * @param {number} field The field number. + * @param {number?} value The value to write. + * @private + */ +jspb.BinaryWriter.prototype.writeSignedVarint64_ = function(field, value) { + if (value == null) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeSignedVarint64(value); }; @@ -736,8 +416,8 @@ jspb.BinaryWriter.prototype.writeVarint_ = function(field, value) { */ jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteZigzagVarint32(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeZigzagVarint32(value); }; @@ -747,10 +427,10 @@ jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(field, value) { * @param {number?} value The value to write. * @private */ -jspb.BinaryWriter.prototype.writeZigzagVarint_ = function(field, value) { +jspb.BinaryWriter.prototype.writeZigzagVarint64_ = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteZigzagVarint(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeZigzagVarint64(value); }; @@ -793,7 +473,7 @@ jspb.BinaryWriter.prototype.writeInt64 = function(field, value) { if (value == null) return; goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && (value < jspb.BinaryConstants.TWO_TO_63)); - this.writeVarint_(field, value); + this.writeSignedVarint64_(field, value); }; @@ -805,8 +485,8 @@ jspb.BinaryWriter.prototype.writeInt64 = function(field, value) { jspb.BinaryWriter.prototype.writeInt64String = function(field, value) { if (value == null) return; var num = jspb.arith.Int64.fromString(value); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteVarintFromNum(num); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeSplitVarint64(num.lo, num.hi); }; @@ -849,7 +529,7 @@ jspb.BinaryWriter.prototype.writeUint64 = function(field, value) { if (value == null) return; goog.asserts.assert((value >= 0) && (value < jspb.BinaryConstants.TWO_TO_64)); - this.writeVarint_(field, value); + this.writeUnsignedVarint64_(field, value); }; @@ -861,8 +541,8 @@ jspb.BinaryWriter.prototype.writeUint64 = function(field, value) { jspb.BinaryWriter.prototype.writeUint64String = function(field, value) { if (value == null) return; var num = jspb.arith.UInt64.fromString(value); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteVarintFromNum(num); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeSplitVarint64(num.lo, num.hi); }; @@ -890,7 +570,7 @@ jspb.BinaryWriter.prototype.writeSint64 = function(field, value) { if (value == null) return; goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && (value < jspb.BinaryConstants.TWO_TO_63)); - this.writeZigzagVarint_(field, value); + this.writeZigzagVarint64_(field, value); }; @@ -904,8 +584,8 @@ jspb.BinaryWriter.prototype.writeFixed32 = function(field, value) { if (value == null) return; goog.asserts.assert((value >= 0) && (value < jspb.BinaryConstants.TWO_TO_32)); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32); - this.rawWriteUint32(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32); + this.encoder_.writeUint32(value); }; @@ -919,8 +599,8 @@ jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) { if (value == null) return; goog.asserts.assert((value >= 0) && (value < jspb.BinaryConstants.TWO_TO_64)); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); - this.rawWriteUint64(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); + this.encoder_.writeUint64(value); }; @@ -934,8 +614,8 @@ jspb.BinaryWriter.prototype.writeSfixed32 = function(field, value) { if (value == null) return; goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && (value < jspb.BinaryConstants.TWO_TO_31)); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32); - this.rawWriteInt32(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32); + this.encoder_.writeInt32(value); }; @@ -949,8 +629,8 @@ jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) { if (value == null) return; goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) && (value < jspb.BinaryConstants.TWO_TO_63)); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); - this.rawWriteInt64(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); + this.encoder_.writeInt64(value); }; @@ -962,8 +642,8 @@ jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) { */ jspb.BinaryWriter.prototype.writeFloat = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32); - this.rawWriteFloat(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32); + this.encoder_.writeFloat(value); }; @@ -975,8 +655,8 @@ jspb.BinaryWriter.prototype.writeFloat = function(field, value) { */ jspb.BinaryWriter.prototype.writeDouble = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); - this.rawWriteDouble(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); + this.encoder_.writeDouble(value); }; @@ -988,8 +668,8 @@ jspb.BinaryWriter.prototype.writeDouble = function(field, value) { jspb.BinaryWriter.prototype.writeBool = function(field, value) { if (value == null) return; goog.asserts.assert(goog.isBoolean(value)); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.temp_.push(~~value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeBool(value); }; @@ -1002,8 +682,8 @@ jspb.BinaryWriter.prototype.writeEnum = function(field, value) { if (value == null) return; goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) && (value < jspb.BinaryConstants.TWO_TO_31)); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteSignedVarint32(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeSignedVarint32(value); }; @@ -1014,99 +694,41 @@ jspb.BinaryWriter.prototype.writeEnum = function(field, value) { */ jspb.BinaryWriter.prototype.writeString = function(field, value) { if (value == null) return; - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - - // Conversion loop swiped from goog.crypt.stringToUtf8ByteArray. Note that - // 'bytes' will be at least as long as 'value', but could be longer if we - // need to unpack unicode characters. - var bytes = []; - for (var i = 0; i < value.length; i++) { - var c = value.charCodeAt(i); - if (c < 128) { - bytes.push(c); - } else if (c < 2048) { - bytes.push((c >> 6) | 192); - bytes.push((c & 63) | 128); - } else { - bytes.push((c >> 12) | 224); - bytes.push(((c >> 6) & 63) | 128); - bytes.push((c & 63) | 128); - } - } - - this.rawWriteUnsignedVarint32(bytes.length); - this.appendArray_(bytes); + var bookmark = this.beginDelimited_(field); + this.encoder_.writeString(value); + this.endDelimited_(bookmark); }; /** * Writes an arbitrary byte field to the buffer. Note - to match the behavior * of the C++ implementation, empty byte arrays _are_ serialized. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. - * @param {jspb.ByteSource} value The array of bytes to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. - * @param {boolean=} opt_stringIsRawBytes If `value` is a string, interpret it - * as a series of raw bytes (codepoints 0--255 inclusive) rather than base64 - * data. + * @param {?jspb.ByteSource} value The array of bytes to write. */ -jspb.BinaryWriter.prototype.writeBytes = - function(field, value, opt_buffer, opt_start, opt_end, - opt_stringIsRawBytes) { - if (value != null) { - this.rawWriteFieldHeader_(field, - jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length); - this.rawWriteBytes( - jspb.utils.byteSourceToUint8Array(value, opt_stringIsRawBytes)); - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); - } -}; - - -/** - * Writes an arbitrary byte field to the buffer, with `opt_stringIsRawBytes` - * flag implicitly true. - * @param {number} field - * @param {jspb.ByteSource} value The array of bytes to write. - */ -jspb.BinaryWriter.prototype.writeBytesRawString = function(field, value) { - this.writeBytes(field, value, null, null, null, true); +jspb.BinaryWriter.prototype.writeBytes = function(field, value) { + if (value == null) return; + var bytes = jspb.utils.byteSourceToUint8Array(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(bytes.length); + this.appendUint8Array_(bytes); }; /** * Writes a message to the buffer. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @template MessageType * @param {number} field The field number. * @param {?MessageType} value The message to write. * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value * to write and the writer to write it with. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writeMessage = - function(field, value, writerCallback, opt_buffer, opt_start, opt_end) { - if (value !== null) { - var bookmark = this.beginDelimited_(field); - - writerCallback(value, this); - - this.endDelimited_(bookmark); - } else if (opt_buffer && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); - } +jspb.BinaryWriter.prototype.writeMessage = function( + field, value, writerCallback) { + if (value == null) return; + var bookmark = this.beginDelimited_(field); + writerCallback(value, this); + this.endDelimited_(bookmark); }; @@ -1120,15 +742,12 @@ jspb.BinaryWriter.prototype.writeMessage = * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value * to write and the writer to write it with. */ -jspb.BinaryWriter.prototype.writeGroup = - function(field, value, writerCallback) { - if (value) { - this.rawWriteFieldHeader_( - field, jspb.BinaryConstants.WireType.START_GROUP); - writerCallback(value, this); - this.rawWriteFieldHeader_( - field, jspb.BinaryConstants.WireType.END_GROUP); - } +jspb.BinaryWriter.prototype.writeGroup = function( + field, value, writerCallback) { + if (value == null) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP); + writerCallback(value, this); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP); }; @@ -1141,8 +760,8 @@ jspb.BinaryWriter.prototype.writeGroup = jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) { if (value == null) return; goog.asserts.assert(value.length == 8); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); - this.rawWriteFixedHash64(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64); + this.encoder_.writeFixedHash64(value); }; @@ -1155,8 +774,8 @@ jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) { jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) { if (value == null) return; goog.asserts.assert(value.length == 8); - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); - this.rawWriteVarintHash64(value); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT); + this.encoder_.writeVarintHash64(value); }; @@ -1196,10 +815,26 @@ jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_ = * @param {?Array.} value The array of ints to write. * @private */ -jspb.BinaryWriter.prototype.writeRepeatedVarint_ = function(field, value) { +jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_ = + function(field, value) { if (value == null) return; for (var i = 0; i < value.length; i++) { - this.writeVarint_(field, value[i]); + this.writeUnsignedVarint64_(field, value[i]); + } +}; + + +/** + * Writes an array of numbers to the buffer as a repeated varint field. + * @param {number} field The field number. + * @param {?Array.} value The array of ints to write. + * @private + */ +jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_ = + function(field, value) { + if (value == null) return; + for (var i = 0; i < value.length; i++) { + this.writeSignedVarint64_(field, value[i]); } }; @@ -1227,7 +862,7 @@ jspb.BinaryWriter.prototype.writeRepeatedZigzag32_ = function(field, value) { jspb.BinaryWriter.prototype.writeRepeatedZigzag_ = function(field, value) { if (value == null) return; for (var i = 0; i < value.length; i++) { - this.writeZigzagVarint_(field, value[i]); + this.writeZigzagVarint64_(field, value[i]); } }; @@ -1262,7 +897,7 @@ jspb.BinaryWriter.prototype.writeRepeatedInt32String = * @param {?Array.} value The array of ints to write. */ jspb.BinaryWriter.prototype.writeRepeatedInt64 = - jspb.BinaryWriter.prototype.writeRepeatedVarint_; + jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_; /** @@ -1312,7 +947,7 @@ jspb.BinaryWriter.prototype.writeRepeatedUint32String = * @param {?Array.} value The array of ints to write. */ jspb.BinaryWriter.prototype.writeRepeatedUint64 = - jspb.BinaryWriter.prototype.writeRepeatedVarint_; + jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_; /** @@ -1469,96 +1104,54 @@ jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) { /** * Writes an array of arbitrary byte fields to the buffer. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. - * @param {?Array.} value - * The arrays of arrays of bytes to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. - * @param {boolean=} opt_stringIsRawBytes Any values that are strings are - * interpreted as raw bytes rather than base64 data. + * @param {?Array.} value The arrays of arrays of bytes to + * write. */ -jspb.BinaryWriter.prototype.writeRepeatedBytes = - function(field, value, opt_buffer, opt_start, opt_end, - opt_stringIsRawBytes) { - if (value != null) { - for (var i = 0; i < value.length; i++) { - this.writeBytes(field, value[i], null, null, null, opt_stringIsRawBytes); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) { + if (value == null) return; + for (var i = 0; i < value.length; i++) { + this.writeBytes(field, value[i]); } }; -/** - * Writes an array of arbitrary byte fields to the buffer, with - * `opt_stringIsRawBytes` implicitly true. - * @param {number} field - * @param {?Array.} value - */ -jspb.BinaryWriter.prototype.writeRepeatedBytesRawString = - function(field, value) { - this.writeRepeatedBytes(field, value, null, null, null, true); -}; - - /** * Writes an array of messages to the buffer. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @template MessageType * @param {number} field The field number. - * @param {?Array.} value The array of messages to + * @param {?Array.} value The array of messages to * write. * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value * to write and the writer to write it with. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writeRepeatedMessage = - function(field, value, writerCallback, opt_buffer, opt_start, opt_end) { - if (value) { - for (var i = 0; i < value.length; i++) { - var bookmark = this.beginDelimited_(field); - - writerCallback(value[i], this); - - this.endDelimited_(bookmark); - } - } else if (opt_buffer && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writeRepeatedMessage = function( + field, value, writerCallback) { + if (value == null) return; + for (var i = 0; i < value.length; i++) { + var bookmark = this.beginDelimited_(field); + writerCallback(value[i], this); + this.endDelimited_(bookmark); } }; /** * Writes an array of group messages to the buffer. - * * @template MessageType * @param {number} field The field number. - * @param {?Array.} value The array of messages to + * @param {?Array.} value The array of messages to * write. * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value * to write and the writer to write it with. */ -jspb.BinaryWriter.prototype.writeRepeatedGroup = - function(field, value, writerCallback) { - if (value) { - for (var i = 0; i < value.length; i++) { - this.rawWriteFieldHeader_( - field, jspb.BinaryConstants.WireType.START_GROUP); - writerCallback(value[i], this); - this.rawWriteFieldHeader_( - field, jspb.BinaryConstants.WireType.END_GROUP); - } +jspb.BinaryWriter.prototype.writeRepeatedGroup = function( + field, value, writerCallback) { + if (value == null) return; + for (var i = 0; i < value.length; i++) { + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP); + writerCallback(value[i], this); + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP); } }; @@ -1595,123 +1188,108 @@ jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 = /** * Writes an array of numbers to the buffer as a packed varint field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. * @private */ -jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - var bookmark = this.beginDelimited_(field); - for (var i = 0; i < value.length; i++) { - this.rawWriteUnsignedVarint32(value[i]); - } - this.endDelimited_(bookmark); - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ = function( + field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeUnsignedVarint32(value[i]); } + this.endDelimited_(bookmark); }; /** * Writes an array of numbers to the buffer as a packed varint field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. * @private */ -jspb.BinaryWriter.prototype.writePackedSignedVarint32_ = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - var bookmark = this.beginDelimited_(field); - for (var i = 0; i < value.length; i++) { - this.rawWriteSignedVarint32(value[i]); - } - this.endDelimited_(bookmark); - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedSignedVarint32_ = function( + field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeSignedVarint32(value[i]); } + this.endDelimited_(bookmark); }; /** * Writes an array of numbers to the buffer as a packed varint field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. * @private */ -jspb.BinaryWriter.prototype.writePackedVarint_ = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - var bookmark = this.beginDelimited_(field); - for (var i = 0; i < value.length; i++) { - this.rawWriteVarint(value[i]); - } - this.endDelimited_(bookmark); - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_ = function( + field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeUnsignedVarint64(value[i]); } + this.endDelimited_(bookmark); +}; + + +/** + * Writes an array of numbers to the buffer as a packed varint field. + * @param {number} field The field number. + * @param {?Array.} value The array of ints to write. + * @private + */ +jspb.BinaryWriter.prototype.writePackedSignedVarint64_ = function( + field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeSignedVarint64(value[i]); + } + this.endDelimited_(bookmark); }; /** * Writes an array of numbers to the buffer as a packed zigzag field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. * @private */ -jspb.BinaryWriter.prototype.writePackedZigzag_ = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - var bookmark = this.beginDelimited_(field); - for (var i = 0; i < value.length; i++) { - this.rawWriteZigzagVarint(value[i]); - } - this.endDelimited_(bookmark); - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedZigzag32_ = function(field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeZigzagVarint32(value[i]); } + this.endDelimited_(bookmark); +}; + + +/** + * Writes an array of numbers to the buffer as a packed zigzag field. + * @param {number} field The field number. + * @param {?Array.} value The array of ints to write. + * @private + */ +jspb.BinaryWriter.prototype.writePackedZigzag64_ = function(field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeZigzagVarint64(value[i]); + } + this.endDelimited_(bookmark); }; /** * Writes an array of numbers to the buffer as a packed 32-bit int field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ jspb.BinaryWriter.prototype.writePackedInt32 = jspb.BinaryWriter.prototype.writePackedSignedVarint32_; @@ -1727,7 +1305,7 @@ jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) { if (value == null || !value.length) return; var bookmark = this.beginDelimited_(field); for (var i = 0; i < value.length; i++) { - this.rawWriteSignedVarint32(parseInt(value[i], 10)); + this.encoder_.writeSignedVarint32(parseInt(value[i], 10)); } this.endDelimited_(bookmark); }; @@ -1737,12 +1315,9 @@ jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) { * Writes an array of numbers to the buffer as a packed 64-bit int field. * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ jspb.BinaryWriter.prototype.writePackedInt64 = - jspb.BinaryWriter.prototype.writePackedVarint_; + jspb.BinaryWriter.prototype.writePackedSignedVarint64_; /** @@ -1757,7 +1332,7 @@ jspb.BinaryWriter.prototype.writePackedInt64String = var bookmark = this.beginDelimited_(field); for (var i = 0; i < value.length; i++) { var num = jspb.arith.Int64.fromString(value[i]); - this.rawWriteVarintFromNum(num); + this.encoder_.writeSplitVarint64(num.lo, num.hi); } this.endDelimited_(bookmark); }; @@ -1765,15 +1340,8 @@ jspb.BinaryWriter.prototype.writePackedInt64String = /** * Writes an array numbers to the buffer as a packed unsigned 32-bit int field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ jspb.BinaryWriter.prototype.writePackedUint32 = jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_; @@ -1790,7 +1358,7 @@ jspb.BinaryWriter.prototype.writePackedUint32String = if (value == null || !value.length) return; var bookmark = this.beginDelimited_(field); for (var i = 0; i < value.length; i++) { - this.rawWriteUnsignedVarint32(parseInt(value[i], 10)); + this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10)); } this.endDelimited_(bookmark); }; @@ -1798,18 +1366,11 @@ jspb.BinaryWriter.prototype.writePackedUint32String = /** * Writes an array numbers to the buffer as a packed unsigned 64-bit int field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ jspb.BinaryWriter.prototype.writePackedUint64 = - jspb.BinaryWriter.prototype.writePackedVarint_; + jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_; /** @@ -1824,7 +1385,7 @@ jspb.BinaryWriter.prototype.writePackedUint64String = var bookmark = this.beginDelimited_(field); for (var i = 0; i < value.length; i++) { var num = jspb.arith.UInt64.fromString(value[i]); - this.rawWriteVarintFromNum(num); + this.encoder_.writeSplitVarint64(num.lo, num.hi); } this.endDelimited_(bookmark); }; @@ -1832,240 +1393,154 @@ jspb.BinaryWriter.prototype.writePackedUint64String = /** * Writes an array numbers to the buffer as a packed signed 32-bit int field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ jspb.BinaryWriter.prototype.writePackedSint32 = - jspb.BinaryWriter.prototype.writePackedZigzag_; + jspb.BinaryWriter.prototype.writePackedZigzag32_; /** * Writes an array numbers to the buffer as a packed signed 64-bit int field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ jspb.BinaryWriter.prototype.writePackedSint64 = - jspb.BinaryWriter.prototype.writePackedZigzag_; + jspb.BinaryWriter.prototype.writePackedZigzag64_; /** * Writes an array of numbers to the buffer as a packed fixed32 field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedFixed32 = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length * 4); - for (var i = 0; i < value.length; i++) { - this.rawWriteUint32(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length * 4); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeUint32(value[i]); } }; /** * Writes an array of numbers to the buffer as a packed fixed64 field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedFixed64 = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length * 8); - for (var i = 0; i < value.length; i++) { - this.rawWriteUint64(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length * 8); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeUint64(value[i]); } }; /** * Writes an array of numbers to the buffer as a packed sfixed32 field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedSfixed32 = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length * 4); - for (var i = 0; i < value.length; i++) { - this.rawWriteInt32(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length * 4); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeInt32(value[i]); } }; /** * Writes an array of numbers to the buffer as a packed sfixed64 field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedSfixed64 = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length * 8); - for (var i = 0; i < value.length; i++) { - this.rawWriteInt64(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length * 8); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeInt64(value[i]); } }; /** * Writes an array of numbers to the buffer as a packed float field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedFloat = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length * 4); - for (var i = 0; i < value.length; i++) { - this.rawWriteFloat(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length * 4); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeFloat(value[i]); } }; /** * Writes an array of numbers to the buffer as a packed double field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedDouble = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length * 8); - for (var i = 0; i < value.length; i++) { - this.rawWriteDouble(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length * 8); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeDouble(value[i]); } }; /** * Writes an array of booleans to the buffer as a packed bool field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedBool = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length); - for (var i = 0; i < value.length; i++) { - this.rawWriteBool(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedBool = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeBool(value[i]); } }; /** * Writes an array of enums to the buffer as a packed enum field. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of ints to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedEnum = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - var bookmark = this.beginDelimited_(field); - for (var i = 0; i < value.length; i++) { - this.rawWriteEnum(value[i]); - } - this.endDelimited_(bookmark); - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeEnum(value[i]); + } + this.endDelimited_(bookmark); +}; + + +/** + * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to + * the buffer. + * @param {number} field The field number. + * @param {?Array.} value The array of hashes to write. + */ +jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) { + if (value == null || !value.length) return; + this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); + this.encoder_.writeUnsignedVarint32(value.length * 8); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeFixedHash64(value[i]); } }; @@ -2073,52 +1548,14 @@ jspb.BinaryWriter.prototype.writePackedEnum = /** * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to * the buffer. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * * @param {number} field The field number. * @param {?Array.} value The array of hashes to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. */ -jspb.BinaryWriter.prototype.writePackedFixedHash64 = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - this.rawWriteFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED); - this.rawWriteUnsignedVarint32(value.length * 8); - for (var i = 0; i < value.length; i++) { - this.rawWriteFixedHash64(value[i]); - } - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); - } -}; - - -/** - * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to - * the buffer. - * - * If 'value' is null, this method will try and copy the pre-serialized value - * in 'opt_buffer' if present. - * - * @param {number} field The field number. - * @param {?Array.} value The array of hashes to write. - * @param {?Uint8Array=} opt_buffer A buffer containing pre-packed values. - * @param {?number=} opt_start The starting point in the above buffer. - * @param {?number=} opt_end The ending point in the above buffer. - */ -jspb.BinaryWriter.prototype.writePackedVarintHash64 = - function(field, value, opt_buffer, opt_start, opt_end) { - if (value != null && value.length) { - var bookmark = this.beginDelimited_(field); - for (var i = 0; i < value.length; i++) { - this.rawWriteVarintHash64(value[i]); - } - this.endDelimited_(bookmark); - } else if ((opt_buffer != null) && (opt_start != null) && (opt_end != null)) { - this.rawWriteByteRange(opt_buffer, opt_start, opt_end); +jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) { + if (value == null || !value.length) return; + var bookmark = this.beginDelimited_(field); + for (var i = 0; i < value.length; i++) { + this.encoder_.writeVarintHash64(value[i]); } + this.endDelimited_(bookmark); }; diff --git a/js/debug.js b/js/debug.js index 48389118..3701a095 100644 --- a/js/debug.js +++ b/js/debug.js @@ -68,7 +68,7 @@ jspb.debug.dump = function(message) { * Recursively introspects a message and the values its getters return to * make a best effort in creating a human readable representation of the * message. - * @param {*} thing A jspb.Message, Array or primitive type to dump. + * @param {?} thing A jspb.Message, Array or primitive type to dump. * @return {*} * @private */ diff --git a/js/debug_test.js b/js/debug_test.js index d7bf3768..01cbf891 100644 --- a/js/debug_test.js +++ b/js/debug_test.js @@ -41,6 +41,7 @@ goog.require('proto.jspb.test.IsExtension'); goog.require('proto.jspb.test.Simple1'); + describe('debugTest', function() { it('testSimple1', function() { if (COMPILED) { diff --git a/js/message.js b/js/message.js index cef9aefd..813e6b8c 100644 --- a/js/message.js +++ b/js/message.js @@ -39,8 +39,8 @@ goog.provide('jspb.Message'); goog.require('goog.array'); goog.require('goog.asserts'); +goog.require('goog.crypt.base64'); goog.require('goog.json'); -goog.require('goog.object'); // Not needed in compilation units that have no protos with xids. goog.forwardDeclare('xid.String'); @@ -119,6 +119,14 @@ jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn, }; +/** + * @return {boolean} Does this field represent a sub Message? + */ +jspb.ExtensionFieldInfo.prototype.isMessageType = function() { + return !!this.ctor; +}; + + /** * Base class for all JsPb messages. * @constructor @@ -165,6 +173,14 @@ goog.define('jspb.Message.MINIMIZE_MEMORY_ALLOCATIONS', COMPILED); // TODO(b/19419436) Turn this on by default. +/** + * Does this browser support Uint8Aray typed arrays? + * @type {boolean} + * @private + */ +jspb.Message.SUPPORTS_UINT8ARRAY_ = (typeof Uint8Array == 'function'); + + /** * The internal data array. * @type {!Array} @@ -210,6 +226,14 @@ jspb.Message.prototype.pivot_; jspb.Message.prototype.messageId_; +/** + * Repeated float or double fields which have been converted to include only + * numbers and not strings holding "NaN", "Infinity" and "-Infinity". + * @private {!Object|undefined} + */ +jspb.Message.prototype.convertedFloatingPointFields_; + + /** * The xid of this proto type (The same for all instances of a proto). Provides * a way to identify a proto by stable obfuscated name. @@ -284,6 +308,8 @@ jspb.Message.initialize = function( msg.arrayIndexOffset_ = messageId === 0 ? -1 : 0; msg.array = data; jspb.Message.materializeExtensionObject_(msg, suggestedPivot); + msg.convertedFloatingPointFields_ = {}; + if (repeatedFields) { for (var i = 0; i < repeatedFields.length; i++) { var fieldNumber = repeatedFields[i]; @@ -419,8 +445,9 @@ jspb.Message.toObjectList = function(field, toObjectFn, opt_includeInstance) { * @param {!jspb.Message} proto The proto whose extensions to convert. * @param {!Object} obj The Soy object to add converted extension data to. * @param {!Object} extensions The proto class' registered extensions. - * @param {function(jspb.ExtensionFieldInfo) : *} getExtensionFn The proto - * class' getExtension function. Passed for effective dead code removal. + * @param {function(this:?, jspb.ExtensionFieldInfo) : *} getExtensionFn + * The proto class' getExtension function. Passed for effective dead code + * removal. * @param {boolean=} opt_includeInstance Whether to include the JSPB instance * for transitional soy proto support: http://goto/soy-param-migration */ @@ -472,7 +499,7 @@ jspb.Message.serializeBinaryExtensions = function(proto, writer, extensions, } var value = getExtensionFn.call(proto, fieldInfo); if (value) { - if (fieldInfo.ctor) { // is this a message type? + if (fieldInfo.isMessageType()) { // If the message type of the extension was generated without binary // support, there may not be a binary message serializer function, and // we can't know when we codegen the extending message that the extended @@ -517,8 +544,7 @@ jspb.Message.readBinaryExtension = function(msg, reader, extensions, } var value; - if (fieldInfo.ctor) { - // Message type. + if (fieldInfo.isMessageType()) { value = new fieldInfo.ctor(); fieldInfo.binaryReaderFn.call( reader, value, fieldInfo.binaryMessageDeserializeFn); @@ -566,6 +592,130 @@ jspb.Message.getField = function(msg, fieldNumber) { }; +/** + * Gets the value of an optional float or double field. + * @param {!jspb.Message} msg A jspb proto. + * @param {number} fieldNumber The field number. + * @return {?number|undefined} The field's value. + * @protected + */ +jspb.Message.getOptionalFloatingPointField = function(msg, fieldNumber) { + var value = jspb.Message.getField(msg, fieldNumber); + // Converts "NaN", "Infinity" and "-Infinity" to their corresponding numbers. + return value == null ? value : +value; +}; + + +/** + * Gets the value of a repeated float or double field. + * @param {!jspb.Message} msg A jspb proto. + * @param {number} fieldNumber The field number. + * @return {!Array} The field's value. + * @protected + */ +jspb.Message.getRepeatedFloatingPointField = function(msg, fieldNumber) { + var values = jspb.Message.getField(msg, fieldNumber); + if (!msg.convertedFloatingPointFields_) { + msg.convertedFloatingPointFields_ = {}; + } + if (!msg.convertedFloatingPointFields_[fieldNumber]) { + for (var i = 0; i < values.length; i++) { + // Converts "NaN", "Infinity" and "-Infinity" to their corresponding + // numbers. + values[i] = +values[i]; + } + msg.convertedFloatingPointFields_[fieldNumber] = true; + } + return /** @type {!Array} */ (values); +}; + + +/** + * Coerce a 'bytes' field to a base 64 string. + * @param {string|Uint8Array|null} value + * @return {?string} The field's coerced value. + */ +jspb.Message.bytesAsB64 = function(value) { + if (value == null || goog.isString(value)) { + return value; + } + if (jspb.Message.SUPPORTS_UINT8ARRAY_ && value instanceof Uint8Array) { + return goog.crypt.base64.encodeByteArray(value); + } + goog.asserts.fail('Cannot coerce to b64 string: ' + goog.typeOf(value)); + return null; +}; + + +/** + * Coerce a 'bytes' field to a Uint8Array byte buffer. + * Note that Uint8Array is not supported on IE versions before 10 nor on Opera + * Mini. @see http://caniuse.com/Uint8Array + * @param {string|Uint8Array|null} value + * @return {?Uint8Array} The field's coerced value. + */ +jspb.Message.bytesAsU8 = function(value) { + if (value == null || value instanceof Uint8Array) { + return value; + } + if (goog.isString(value)) { + return goog.crypt.base64.decodeStringToUint8Array(value); + } + goog.asserts.fail('Cannot coerce to Uint8Array: ' + goog.typeOf(value)); + return null; +}; + + +/** + * Coerce a repeated 'bytes' field to an array of base 64 strings. + * Note: the returned array should be treated as immutable. + * @param {!Array|!Array} value + * @return {!Array} The field's coerced value. + */ +jspb.Message.bytesListAsB64 = function(value) { + jspb.Message.assertConsistentTypes_(value); + if (!value.length || goog.isString(value[0])) { + return /** @type {!Array} */ (value); + } + return goog.array.map(value, jspb.Message.bytesAsB64); +}; + + +/** + * Coerce a repeated 'bytes' field to an array of Uint8Array byte buffers. + * Note: the returned array should be treated as immutable. + * Note that Uint8Array is not supported on IE versions before 10 nor on Opera + * Mini. @see http://caniuse.com/Uint8Array + * @param {!Array|!Array} value + * @return {!Array} The field's coerced value. + */ +jspb.Message.bytesListAsU8 = function(value) { + jspb.Message.assertConsistentTypes_(value); + if (!value.length || value[0] instanceof Uint8Array) { + return /** @type {!Array} */ (value); + } + return goog.array.map(value, jspb.Message.bytesAsU8); +}; + + +/** + * Asserts that all elements of an array are of the same type. + * @param {Array?} array The array to test. + * @private + */ +jspb.Message.assertConsistentTypes_ = function(array) { + if (goog.DEBUG && array && array.length > 1) { + var expected = goog.typeOf(array[0]); + goog.array.forEach(array, function(e) { + if (goog.typeOf(e) != expected) { + goog.asserts.fail('Inconsistent type in JSPB repeated field array. ' + + 'Got ' + goog.typeOf(e) + ' expected ' + expected); + } + }); + } +}; + + /** * Gets the value of a non-extension primitive field, with proto3 (non-nullable * primitives) semantics. Returns `defaultValue` if the field is not otherwise @@ -841,7 +991,7 @@ jspb.Message.prototype.getExtension = function(fieldInfo) { } var fieldNumber = fieldInfo.fieldIndex; if (fieldInfo.isRepeated) { - if (fieldInfo.ctor) { + if (fieldInfo.isMessageType()) { if (!this.wrappers_[fieldNumber]) { this.wrappers_[fieldNumber] = goog.array.map(this.extensionObject_[fieldNumber] || [], @@ -854,7 +1004,7 @@ jspb.Message.prototype.getExtension = function(fieldInfo) { return this.extensionObject_[fieldNumber]; } } else { - if (fieldInfo.ctor) { + if (fieldInfo.isMessageType()) { if (!this.wrappers_[fieldNumber] && this.extensionObject_[fieldNumber]) { this.wrappers_[fieldNumber] = new fieldInfo.ctor( /** @type {Array|undefined} */ ( @@ -871,7 +1021,8 @@ jspb.Message.prototype.getExtension = function(fieldInfo) { /** * Sets the value of the extension field in the extended object. * @param {jspb.ExtensionFieldInfo} fieldInfo Specifies the field to set. - * @param {jspb.Message|string|number|boolean|Array} value The value to set. + * @param {jspb.Message|string|Uint8Array|number|boolean|Array?} value The value + * to set. */ jspb.Message.prototype.setExtension = function(fieldInfo, value) { if (!this.wrappers_) { @@ -881,7 +1032,7 @@ jspb.Message.prototype.setExtension = function(fieldInfo, value) { var fieldNumber = fieldInfo.fieldIndex; if (fieldInfo.isRepeated) { value = value || []; - if (fieldInfo.ctor) { + if (fieldInfo.isMessageType()) { this.wrappers_[fieldNumber] = value; this.extensionObject_[fieldNumber] = goog.array.map( /** @type {Array} */ (value), function(msg) { @@ -891,7 +1042,7 @@ jspb.Message.prototype.setExtension = function(fieldInfo, value) { this.extensionObject_[fieldNumber] = value; } } else { - if (fieldInfo.ctor) { + if (fieldInfo.isMessageType()) { this.wrappers_[fieldNumber] = value; this.extensionObject_[fieldNumber] = value ? value.toArray() : value; } else { @@ -957,6 +1108,33 @@ jspb.Message.equals = function(m1, m2) { }; +/** + * Compares two message extension fields recursively. + * @param {!Object} extension1 The first field. + * @param {!Object} extension2 The second field. + * @return {boolean} true if the extensions are null/undefined, or otherwise + * equal. + */ +jspb.Message.compareExtensions = function(extension1, extension2) { + extension1 = extension1 || {}; + extension2 = extension2 || {}; + + var keys = {}; + for (var name in extension1) { + keys[name] = 0; + } + for (var name in extension2) { + keys[name] = 0; + } + for (name in keys) { + if (!jspb.Message.compareFields(extension1[name], extension2[name])) { + return false; + } + } + return true; +}; + + /** * Compares two message fields recursively. * @param {*} field1 The first field. @@ -964,43 +1142,77 @@ jspb.Message.equals = function(m1, m2) { * @return {boolean} true if the fields are null/undefined, or otherwise equal. */ jspb.Message.compareFields = function(field1, field2) { - if (goog.isObject(field1) && goog.isObject(field2)) { - var keys = {}, name, extensionObject1, extensionObject2; - for (name in field1) { - field1.hasOwnProperty(name) && (keys[name] = 0); + // If the fields are trivially equal, they're equal. + if (field1 == field2) return true; + + // If the fields aren't trivially equal and one of them isn't an object, + // they can't possibly be equal. + if (!goog.isObject(field1) || !goog.isObject(field2)) { + return false; + } + + // We have two objects. If they're different types, they're not equal. + field1 = /** @type {!Object} */(field1); + field2 = /** @type {!Object} */(field2); + if (field1.constructor != field2.constructor) return false; + + // If both are Uint8Arrays, compare them element-by-element. + if (jspb.Message.SUPPORTS_UINT8ARRAY_ && field1.constructor === Uint8Array) { + var bytes1 = /** @type {!Uint8Array} */(field1); + var bytes2 = /** @type {!Uint8Array} */(field2); + if (bytes1.length != bytes2.length) return false; + for (var i = 0; i < bytes1.length; i++) { + if (bytes1[i] != bytes2[i]) return false; } - for (name in field2) { - field2.hasOwnProperty(name) && (keys[name] = 0); - } - for (name in keys) { - var val1 = field1[name], val2 = field2[name]; - if (goog.isObject(val1) && !goog.isArray(val1)) { - if (extensionObject1 !== undefined) { - throw new Error('invalid jspb state'); - } - extensionObject1 = goog.object.isEmpty(val1) ? undefined : val1; + return true; + } + + // If they're both Arrays, compare them element by element except for the + // optional extension objects at the end, which we compare separately. + if (field1.constructor === Array) { + var extension1 = undefined; + var extension2 = undefined; + + var length = Math.max(field1.length, field2.length); + for (var i = 0; i < length; i++) { + var val1 = field1[i]; + var val2 = field2[i]; + + if (val1 && (val1.constructor == Object)) { + goog.asserts.assert(extension1 === undefined); + goog.asserts.assert(i === field1.length - 1); + extension1 = val1; val1 = undefined; } - if (goog.isObject(val2) && !goog.isArray(val2)) { - if (extensionObject2 !== undefined) { - throw new Error('invalid jspb state'); - } - extensionObject2 = goog.object.isEmpty(val2) ? undefined : val2; + + if (val2 && (val2.constructor == Object)) { + goog.asserts.assert(extension2 === undefined); + goog.asserts.assert(i === field2.length - 1); + extension2 = val2; val2 = undefined; } + if (!jspb.Message.compareFields(val1, val2)) { return false; } } - if (extensionObject1 || extensionObject2) { - return jspb.Message.compareFields(extensionObject1, extensionObject2); + + if (extension1 || extension2) { + extension1 = extension1 || {}; + extension2 = extension2 || {}; + return jspb.Message.compareExtensions(extension1, extension2); } + return true; } - // Primitive fields, null and undefined compare as equal. - // This also forces booleans and 0/1 to compare as equal to ensure - // compatibility with the jspb serializer. - return field1 == field2; + + // If they're both plain Objects (i.e. extensions), compare them as + // extensions. + if (field1.constructor === Object) { + return jspb.Message.compareExtensions(field1, field2); + } + + throw new Error('Invalid type in JSPB array'); }; diff --git a/js/message_test.js b/js/message_test.js index f572188e..01add5f1 100644 --- a/js/message_test.js +++ b/js/message_test.js @@ -53,6 +53,8 @@ goog.require('proto.jspb.test.Complex'); goog.require('proto.jspb.test.DefaultValues'); goog.require('proto.jspb.test.Empty'); goog.require('proto.jspb.test.EnumContainer'); +goog.require('proto.jspb.test.floatingMsgField'); +goog.require('proto.jspb.test.FloatingPointFields'); goog.require('proto.jspb.test.floatingStrField'); goog.require('proto.jspb.test.HasExtensions'); goog.require('proto.jspb.test.IndirectExtension'); @@ -60,7 +62,6 @@ goog.require('proto.jspb.test.IsExtension'); goog.require('proto.jspb.test.OptionalFields'); goog.require('proto.jspb.test.OuterEnum'); goog.require('proto.jspb.test.OuterMessage.Complex'); -goog.require('proto.jspb.test.simple1'); goog.require('proto.jspb.test.Simple1'); goog.require('proto.jspb.test.Simple2'); goog.require('proto.jspb.test.SpecialCases'); @@ -74,7 +75,7 @@ goog.require('proto.jspb.test.TestReservedNamesExtension'); // CommonJS-LoadFromFile: test2_pb proto.jspb.test goog.require('proto.jspb.test.ExtensionMessage'); goog.require('proto.jspb.test.TestExtensionsMessage'); -goog.require('proto.jspb.test.floatingMsgField'); + @@ -98,12 +99,6 @@ describe('Message test suite', function() { assertEquals('some_bytes', data.getBytesField()); }); - it('testNestedMessage', function() { - var msg = new proto.jspb.test.OuterMessage.Complex(); - msg.setInnerComplexField(5); - assertObjectEquals({innerComplexField: 5}, msg.toObject()); - }); - it('testComplexConversion', function() { var data1 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1]; var data2 = ['a',,, [, 11], [[, 22], [, 33]],, ['s1', 's2'],, 1]; @@ -160,6 +155,13 @@ describe('Message test suite', function() { }); + it('testNestedComplexMessage', function() { + // Instantiate the message and set a unique field, just to ensure that we + // are not getting jspb.test.Complex instead. + var msg = new proto.jspb.test.OuterMessage.Complex(); + msg.setInnerComplexField(5); + }); + it('testSpecialCases', function() { // Note: Some property names are reserved in JavaScript. // These names are converted to the Js property named pb_. @@ -544,12 +546,6 @@ describe('Message test suite', function() { extendable.setExtension(proto.jspb.test.IndirectExtension.str, null); assertNull(extendable.getExtension(proto.jspb.test.IndirectExtension.str)); - // These assertions will only work properly in uncompiled mode. - // Extension fields defined on proto2 Descriptor messages are filtered out. - - // TODO(haberman): codegen changes to properly ignore descriptor.proto - // extensions need to be merged from google3. - // assertUndefined(proto.jspb.test.IsExtension['simpleOption']); // Extension fields with jspb.ignore = true are ignored. assertUndefined(proto.jspb.test.IndirectExtension['ignored']); @@ -907,7 +903,7 @@ describe('Message test suite', function() { message.getDefaultOneofACase()); message = - new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567,890)); + new proto.jspb.test.TestMessageWithOneof(new Array(9).concat(567, 890)); assertEquals(1234, message.getAone()); assertEquals(890, message.getAtwo()); assertEquals( @@ -936,7 +932,7 @@ describe('Message test suite', function() { message.getDefaultOneofBCase()); message = new proto.jspb.test.TestMessageWithOneof( - new Array(11).concat(567,890)); + new Array(11).concat(567, 890)); assertUndefined(message.getBone()); assertEquals(890, message.getBtwo()); assertEquals( @@ -989,4 +985,26 @@ describe('Message test suite', function() { assertEquals('y', array[4]); }); + it('testFloatingPointFieldsSupportNan', function() { + var assertNan = function(x) { + assertTrue('Expected ' + x + ' (' + goog.typeOf(x) + ') to be NaN.', + goog.isNumber(x) && isNaN(x)); + }; + + var message = new proto.jspb.test.FloatingPointFields([ + 'NaN', 'NaN', ['NaN', 'NaN'], 'NaN', + 'NaN', 'NaN', ['NaN', 'NaN'], 'NaN' + ]); + assertNan(message.getOptionalFloatField()); + assertNan(message.getRequiredFloatField()); + assertNan(message.getRepeatedFloatFieldList()[0]); + assertNan(message.getRepeatedFloatFieldList()[1]); + assertNan(message.getDefaultFloatField()); + assertNan(message.getOptionalDoubleField()); + assertNan(message.getRequiredDoubleField()); + assertNan(message.getRepeatedDoubleFieldList()[0]); + assertNan(message.getRepeatedDoubleFieldList()[1]); + assertNan(message.getDefaultDoubleField()); + }); + }); diff --git a/js/proto3_test.js b/js/proto3_test.js index f8868716..4dd7790f 100644 --- a/js/proto3_test.js +++ b/js/proto3_test.js @@ -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. +goog.require('goog.crypt.base64'); goog.require('goog.testing.asserts'); // CommonJS-LoadFromFile: testbinary_pb proto.jspb.test @@ -37,31 +38,30 @@ goog.require('proto.jspb.test.ForeignMessage'); goog.require('proto.jspb.test.Proto3Enum'); goog.require('proto.jspb.test.TestProto3'); + +var BYTES = new Uint8Array([1, 2, 8, 9]); +var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES); + + /** - * Helper: compare a bytes field to a string with codepoints 0--255. + * Helper: compare a bytes field to an expected value * @param {Uint8Array|string} arr - * @param {string} str + * @param {Uint8Array} expected * @return {boolean} */ -function bytesCompare(arr, str) { - if (arr.length != str.length) { +function bytesCompare(arr, expected) { + if (goog.isString(arr)) { + arr = goog.crypt.base64.decodeStringToUint8Array(arr); + } + if (arr.length != expected.length) { return false; } - if (typeof arr == 'string') { - for (var i = 0; i < arr.length; i++) { - if (arr.charCodeAt(i) != str.charCodeAt(i)) { - return false; - } + for (var i = 0; i < arr.length; i++) { + if (arr[i] != expected[i]) { + return false; } - return true; - } else { - for (var i = 0; i < arr.length; i++) { - if (arr[i] != str.charCodeAt(i)) { - return false; - } - } - return true; } + return true; } @@ -86,13 +86,17 @@ describe('proto3Test', function() { assertEquals(msg.getOptionalDouble(), 0); assertEquals(msg.getOptionalString(), ''); - // If/when we change bytes fields to return Uint8Array, we'll want to switch - // to this assertion instead: - //assertEquals(msg.getOptionalBytes() instanceof Uint8Array, true); + // TODO(b/26173701): when we change bytes fields default getter to return + // Uint8Array, we'll want to switch this assertion to match the u8 case. assertEquals(typeof msg.getOptionalBytes(), 'string'); - + assertEquals(msg.getOptionalBytes_asU8() instanceof Uint8Array, true); + assertEquals(typeof msg.getOptionalBytes_asB64(), 'string'); assertEquals(msg.getOptionalBytes().length, 0); - assertEquals(msg.getOptionalForeignEnum(), proto.jspb.test.Proto3Enum.PROTO3_FOO); + assertEquals(msg.getOptionalBytes_asU8().length, 0); + assertEquals(msg.getOptionalBytes_asB64(), ''); + + assertEquals(msg.getOptionalForeignEnum(), + proto.jspb.test.Proto3Enum.PROTO3_FOO); assertEquals(msg.getOptionalForeignMessage(), undefined); assertEquals(msg.getOptionalForeignMessage(), undefined); @@ -136,7 +140,7 @@ describe('proto3Test', function() { msg.setOptionalDouble(-1.5); msg.setOptionalBool(true); msg.setOptionalString('hello world'); - msg.setOptionalBytes('bytes'); + msg.setOptionalBytes(BYTES); var submsg = new proto.jspb.test.ForeignMessage(); submsg.setC(16); msg.setOptionalForeignMessage(submsg); @@ -156,7 +160,7 @@ describe('proto3Test', function() { msg.setRepeatedDoubleList([-1.5]); msg.setRepeatedBoolList([true]); msg.setRepeatedStringList(['hello world']); - msg.setRepeatedBytesList(['bytes']); + msg.setRepeatedBytesList([BYTES]); submsg = new proto.jspb.test.ForeignMessage(); submsg.setC(1000); msg.setRepeatedForeignMessageList([submsg]); @@ -181,7 +185,7 @@ describe('proto3Test', function() { assertEquals(msg.getOptionalDouble(), -1.5); assertEquals(msg.getOptionalBool(), true); assertEquals(msg.getOptionalString(), 'hello world'); - assertEquals(true, bytesCompare(msg.getOptionalBytes(), 'bytes')); + assertEquals(true, bytesCompare(msg.getOptionalBytes(), BYTES)); assertEquals(msg.getOptionalForeignMessage().getC(), 16); assertEquals(msg.getOptionalForeignEnum(), proto.jspb.test.Proto3Enum.PROTO3_BAR); @@ -201,7 +205,7 @@ describe('proto3Test', function() { assertElementsEquals(msg.getRepeatedBoolList(), [true]); assertElementsEquals(msg.getRepeatedStringList(), ['hello world']); assertEquals(msg.getRepeatedBytesList().length, 1); - assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], 'bytes')); + assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], BYTES)); assertEquals(msg.getRepeatedForeignMessageList().length, 1); assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000); assertElementsEquals(msg.getRepeatedForeignEnumList(), @@ -242,11 +246,12 @@ describe('proto3Test', function() { assertEquals(msg.getOneofString(), 'hello'); assertEquals(msg.getOneofBytes(), undefined); - msg.setOneofBytes('\u00FF\u00FF'); + msg.setOneofBytes(goog.crypt.base64.encodeString('\u00FF\u00FF')); assertEquals(msg.getOneofUint32(), undefined); assertEquals(msg.getOneofForeignMessage(), undefined); assertEquals(msg.getOneofString(), undefined); - assertEquals(msg.getOneofBytes(), '\u00FF\u00FF'); + assertEquals(msg.getOneofBytes_asB64(), + goog.crypt.base64.encodeString('\u00FF\u00FF')); }); @@ -267,7 +272,7 @@ describe('proto3Test', function() { msg.setOptionalBool(false); msg.setOptionalString('hello world'); msg.setOptionalString(''); - msg.setOptionalBytes('\u00FF\u00FF'); + msg.setOptionalBytes(goog.crypt.base64.encodeString('\u00FF\u00FF')); msg.setOptionalBytes(''); msg.setOptionalForeignMessage(new proto.jspb.test.ForeignMessage()); msg.setOptionalForeignMessage(null); @@ -280,4 +285,30 @@ describe('proto3Test', function() { var serialized = msg.serializeBinary(); assertEquals(0, serialized.length); }); + + /** + * Test that base64 string and Uint8Array are interchangeable in bytes fields. + */ + it('testBytesFieldsInterop', function() { + var msg = new proto.jspb.test.TestProto3(); + // Set as a base64 string and check all the getters work. + msg.setOptionalBytes(BYTES_B64); + assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + + // Test binary serialize round trip doesn't break it. + msg = proto.jspb.test.TestProto3.deserializeBinary(msg.serializeBinary()); + assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + + msg = new proto.jspb.test.TestProto3(); + // Set as a Uint8Array and check all the getters work. + msg.setOptionalBytes(BYTES); + assertTrue(bytesCompare(msg.getOptionalBytes_asU8(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes_asB64(), BYTES)); + assertTrue(bytesCompare(msg.getOptionalBytes(), BYTES)); + + }); }); diff --git a/js/test.proto b/js/test.proto index 14418ac9..6b9dc891 100644 --- a/js/test.proto +++ b/js/test.proto @@ -145,6 +145,17 @@ message DefaultValues { optional bytes bytes_field = 8 [default="moo"]; // Base64 encoding is "bW9v" } +message FloatingPointFields { + optional float optional_float_field = 1; + required float required_float_field = 2; + repeated float repeated_float_field = 3; + optional float default_float_field = 4 [default = 2.0]; + optional double optional_double_field = 5; + required double required_double_field = 6; + repeated double repeated_double_field = 7; + optional double default_double_field = 8 [default = 2.0]; +} + message TestClone { optional string str = 1; optional Simple1 simple1 = 3; @@ -216,3 +227,4 @@ message TestMessageWithOneof { int32 btwo = 13 [default = 1234]; } } + diff --git a/php/ext/google/protobuf/config.m4 b/php/ext/google/protobuf/config.m4 new file mode 100644 index 00000000..b5946f74 --- /dev/null +++ b/php/ext/google/protobuf/config.m4 @@ -0,0 +1,10 @@ +dnl lines starting with "dnl" are comments + +PHP_ARG_ENABLE(protobuf, whether to enable Protobuf extension, [ --enable-protobuf Enable Protobuf extension]) + +if test "$PHP_PROTOBUF" != "no"; then + + dnl this defines the extension + PHP_NEW_EXTENSION(protobuf, upb.c protobuf.c def.c message.c storage.c, $ext_shared) + +fi diff --git a/php/ext/google/protobuf/def.c b/php/ext/google/protobuf/def.c new file mode 100644 index 00000000..fc188069 --- /dev/null +++ b/php/ext/google/protobuf/def.c @@ -0,0 +1,381 @@ +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Common Utilities +// ----------------------------------------------------------------------------- + +void check_upb_status(const upb_status* status, const char* msg) { + if (!upb_ok(status)) { + zend_error("%s: %s\n", msg, upb_status_errmsg(status)); + } +} + + +static upb_def *check_notfrozen(const upb_def *def) { + if (upb_def_isfrozen(def)) { + zend_error(E_ERROR, + "Attempt to modify a frozen descriptor. Once descriptors are " + "added to the descriptor pool, they may not be modified."); + } + return (upb_def *)def; +} + +static upb_msgdef *check_msgdef_notfrozen(const upb_msgdef *def) { + return upb_downcast_msgdef_mutable(check_notfrozen((const upb_def *)def)); +} + +static upb_fielddef *check_fielddef_notfrozen(const upb_fielddef *def) { + return upb_downcast_fielddef_mutable(check_notfrozen((const upb_def *)def)); +} + +#define PROTOBUF_WRAP_INTERN(wrapper, intern, intern_dtor) \ + Z_TYPE_P(wrapper) = IS_OBJECT; \ + Z_OBJVAL_P(wrapper) \ + .handle = zend_objects_store_put( \ + intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ + intern_dtor, NULL TSRMLS_CC); \ + Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); + +#define PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper, \ + intern) \ + Z_TYPE_P(wrapper) = IS_OBJECT; \ + class_name *intern = ALLOC(class_name); \ + memset(intern, 0, sizeof(class_name)); \ + class_name_lower##_init_c_instance(intern TSRMLS_CC); \ + Z_OBJVAL_P(wrapper) \ + .handle = zend_objects_store_put(intern, NULL, class_name_lower##_free, \ + NULL TSRMLS_CC); \ + Z_OBJVAL_P(wrapper).handlers = zend_get_std_object_handlers(); + +#define PROTOBUF_CREATE_ZEND_WRAPPER(class_name, class_name_lower, wrapper, \ + intern) \ + MAKE_STD_ZVAL(wrapper); \ + PROTOBUF_SETUP_ZEND_WRAPPER(class_name, class_name_lower, wrapper, intern); + +#define DEFINE_CLASS(name, name_lower, string_name) \ + zend_class_entry *name_lower##_type; \ + void name_lower##_init(TSRMLS_D) { \ + zend_class_entry class_type; \ + INIT_CLASS_ENTRY(class_type, string_name, name_lower##_methods); \ + name_lower##_type = zend_register_internal_class(&class_type TSRMLS_CC); \ + name_lower##_type->create_object = name_lower##_create; \ + } \ + name *php_to_##name_lower(zval *val TSRMLS_DC) { \ + return (name *)zend_object_store_get_object(val TSRMLS_CC); \ + } \ + void name_lower##_free(void *object TSRMLS_DC) { \ + name *intern = (name *)object; \ + name_lower##_free_c(intern TSRMLS_CC); \ + efree(object); \ + } \ + zend_object_value name_lower##_create(zend_class_entry *ce TSRMLS_DC) { \ + zend_object_value return_value; \ + name *intern = (name *)emalloc(sizeof(name)); \ + memset(intern, 0, sizeof(name)); \ + name_lower##_init_c_instance(intern TSRMLS_CC); \ + return_value.handle = zend_objects_store_put( \ + intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ + name_lower##_free, NULL TSRMLS_CC); \ + return_value.handlers = zend_get_std_object_handlers(); \ + return return_value; \ + } + +// ----------------------------------------------------------------------------- +// DescriptorPool +// ----------------------------------------------------------------------------- + +static zend_function_entry descriptor_pool_methods[] = { + PHP_ME(DescriptorPool, addMessage, NULL, ZEND_ACC_PUBLIC) + PHP_ME(DescriptorPool, finalize, NULL, ZEND_ACC_PUBLIC) + ZEND_FE_END +}; + +DEFINE_CLASS(DescriptorPool, descriptor_pool, + "Google\\Protobuf\\DescriptorPool"); + +DescriptorPool *generated_pool; // The actual generated pool + +ZEND_FUNCTION(get_generated_pool) { + if (PROTOBUF_G(generated_pool) == NULL) { + MAKE_STD_ZVAL(PROTOBUF_G(generated_pool)); + Z_TYPE_P(PROTOBUF_G(generated_pool)) = IS_OBJECT; + generated_pool = ALLOC(DescriptorPool); + descriptor_pool_init_c_instance(generated_pool TSRMLS_CC); + Z_OBJ_HANDLE_P(PROTOBUF_G(generated_pool)) = zend_objects_store_put( + generated_pool, NULL, + (zend_objects_free_object_storage_t)descriptor_pool_free, NULL TSRMLS_CC); + Z_OBJ_HT_P(PROTOBUF_G(generated_pool)) = zend_get_std_object_handlers(); + } + RETURN_ZVAL(PROTOBUF_G(generated_pool), 1, 0); +} + +void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC) { + zend_object_std_init(&pool->std, descriptor_pool_type TSRMLS_CC); + pool->symtab = upb_symtab_new(&pool->symtab); + + ALLOC_HASHTABLE(pool->pending_list); + zend_hash_init(pool->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); +} + +void descriptor_pool_free_c(DescriptorPool *pool TSRMLS_DC) { + upb_symtab_unref(pool->symtab, &pool->symtab); + zend_hash_destroy(pool->pending_list); + FREE_HASHTABLE(pool->pending_list); +} + +PHP_METHOD(DescriptorPool, addMessage) { + char *name = NULL; + int str_len; + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &str_len) == + FAILURE) { + return; + } + + zval* retval = NULL; + PROTOBUF_CREATE_ZEND_WRAPPER(MessageBuilderContext, message_builder_context, + retval, context); + + MAKE_STD_ZVAL(context->pool); + ZVAL_ZVAL(context->pool, getThis(), 1, 0); + + Descriptor *desc = php_to_descriptor(context->descriptor TSRMLS_CC); + Descriptor_name_set(desc, name); + + RETURN_ZVAL(retval, 0, 1); +} + +static void validate_msgdef(const upb_msgdef* msgdef) { + // Verify that no required fields exist. proto3 does not support these. + upb_msg_field_iter it; + for (upb_msg_field_begin(&it, msgdef); + !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + const upb_fielddef* field = upb_msg_iter_field(&it); + if (upb_fielddef_label(field) == UPB_LABEL_REQUIRED) { + zend_error(E_ERROR, "Required fields are unsupported in proto3."); + } + } +} + +PHP_METHOD(DescriptorPool, finalize) { + DescriptorPool *self = php_to_descriptor_pool(getThis() TSRMLS_CC); + Bucket *temp; + int i, num; + + num = zend_hash_num_elements(self->pending_list); + upb_def **defs = emalloc(sizeof(upb_def *) * num); + + for (i = 0, temp = self->pending_list->pListHead; temp != NULL; + temp = temp->pListNext) { + zval *def_php = *(zval **)temp->pData; + Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC); + defs[i] = (upb_def *)desc->msgdef; + validate_msgdef((const upb_msgdef *)defs[i++]); + } + + CHECK_UPB(upb_symtab_add(self->symtab, (upb_def **)defs, num, NULL, &status), + "Unable to add defs to DescriptorPool"); + + for (temp = self->pending_list->pListHead; temp != NULL; + temp = temp->pListNext) { + // zval *def_php = *(zval **)temp->pData; + // Descriptor* desc = php_to_descriptor(def_php TSRMLS_CC); + build_class_from_descriptor((zval *)temp->pDataPtr TSRMLS_CC); + } + + FREE(defs); + zend_hash_destroy(self->pending_list); + zend_hash_init(self->pending_list, 1, NULL, ZVAL_PTR_DTOR, 0); +} + +// ----------------------------------------------------------------------------- +// Descriptor +// ----------------------------------------------------------------------------- + +static zend_function_entry descriptor_methods[] = { + ZEND_FE_END +}; + +DEFINE_CLASS(Descriptor, descriptor, "Google\\Protobuf\\Descriptor"); + +void descriptor_free_c(Descriptor *self TSRMLS_DC) { + upb_msg_field_iter iter; + upb_msg_field_begin(&iter, self->msgdef); + while (!upb_msg_field_done(&iter)) { + upb_fielddef *fielddef = upb_msg_iter_field(&iter); + upb_fielddef_unref(fielddef, &fielddef); + upb_msg_field_next(&iter); + } + upb_msgdef_unref(self->msgdef, &self->msgdef); + if (self->layout) { + free_layout(self->layout); + } +} + +static void descriptor_add_field(Descriptor *desc, + const upb_fielddef *fielddef) { + upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef); + upb_fielddef *mut_field_def = check_fielddef_notfrozen(fielddef); + CHECK_UPB(upb_msgdef_addfield(mut_def, mut_field_def, NULL, &status), + "Adding field to Descriptor failed"); + // add_def_obj(fielddef, obj); +} + +void descriptor_init_c_instance(Descriptor* desc TSRMLS_DC) { + zend_object_std_init(&desc->std, descriptor_type TSRMLS_CC); + desc->msgdef = upb_msgdef_new(&desc->msgdef); + desc->layout = NULL; + // MAKE_STD_ZVAL(intern->klass); + // ZVAL_NULL(intern->klass); + desc->pb_serialize_handlers = NULL; +} + +void Descriptor_name_set(Descriptor *desc, const char *name) { + upb_msgdef *mut_def = check_msgdef_notfrozen(desc->msgdef); + CHECK_UPB(upb_msgdef_setfullname(mut_def, name, &status), + "Error setting Descriptor name"); +} + +// ----------------------------------------------------------------------------- +// FieldDescriptor +// ----------------------------------------------------------------------------- + +static void field_descriptor_name_set(const upb_fielddef* fielddef, + const char *name) { + upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); + CHECK_UPB(upb_fielddef_setname(mut_def, name, &status), + "Error setting FieldDescriptor name"); +} + +static void field_descriptor_label_set(const upb_fielddef* fielddef, + upb_label_t upb_label) { + upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); + upb_fielddef_setlabel(mut_def, upb_label); +} + +upb_fieldtype_t string_to_descriptortype(const char *type) { +#define CONVERT(upb, str) \ + if (!strcmp(type, str)) { \ + return UPB_DESCRIPTOR_TYPE_##upb; \ + } + + CONVERT(FLOAT, "float"); + CONVERT(DOUBLE, "double"); + CONVERT(BOOL, "bool"); + CONVERT(STRING, "string"); + CONVERT(BYTES, "bytes"); + CONVERT(MESSAGE, "message"); + CONVERT(GROUP, "group"); + CONVERT(ENUM, "enum"); + CONVERT(INT32, "int32"); + CONVERT(INT64, "int64"); + CONVERT(UINT32, "uint32"); + CONVERT(UINT64, "uint64"); + CONVERT(SINT32, "sint32"); + CONVERT(SINT64, "sint64"); + CONVERT(FIXED32, "fixed32"); + CONVERT(FIXED64, "fixed64"); + CONVERT(SFIXED32, "sfixed32"); + CONVERT(SFIXED64, "sfixed64"); + +#undef CONVERT + + zend_error(E_ERROR, "Unknown field type."); + return 0; +} + +static void field_descriptor_type_set(const upb_fielddef* fielddef, + const char *type) { + upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); + upb_fielddef_setdescriptortype(mut_def, string_to_descriptortype(type)); +} + +static void field_descriptor_number_set(const upb_fielddef* fielddef, + int number) { + upb_fielddef *mut_def = check_fielddef_notfrozen(fielddef); + CHECK_UPB(upb_fielddef_setnumber(mut_def, number, &status), + "Error setting field number"); +} + +// ----------------------------------------------------------------------------- +// MessageBuilderContext +// ----------------------------------------------------------------------------- + +static zend_function_entry message_builder_context_methods[] = { + PHP_ME(MessageBuilderContext, finalizeToPool, NULL, ZEND_ACC_PUBLIC) + PHP_ME(MessageBuilderContext, optional, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +DEFINE_CLASS(MessageBuilderContext, message_builder_context, + "Google\\Protobuf\\Internal\\MessageBuilderContext"); + +void message_builder_context_free_c(MessageBuilderContext *context TSRMLS_DC) { + zval_ptr_dtor(&context->descriptor); + zval_ptr_dtor(&context->pool); +} + +void message_builder_context_init_c_instance( + MessageBuilderContext *context TSRMLS_DC) { + zend_object_std_init(&context->std, message_builder_context_type TSRMLS_CC); + PROTOBUF_CREATE_ZEND_WRAPPER(Descriptor, descriptor, context->descriptor, + desc); +} + +static void msgdef_add_field(Descriptor *desc, upb_label_t upb_label, + const char *name, const char *type, int number, + const char *type_class) { + upb_fielddef *fielddef = upb_fielddef_new(&fielddef); + upb_fielddef_setpacked(fielddef, false); + + field_descriptor_label_set(fielddef, upb_label); + field_descriptor_name_set(fielddef, name); + field_descriptor_type_set(fielddef, type); + field_descriptor_number_set(fielddef, number); + +// // if (type_class != Qnil) { +// // if (TYPE(type_class) != T_STRING) { +// // rb_raise(rb_eArgError, "Expected string for type class"); +// // } +// // // Make it an absolute type name by prepending a dot. +// // type_class = rb_str_append(rb_str_new2("."), type_class); +// // rb_funcall(fielddef, rb_intern("submsg_name="), 1, type_class); +// // } + descriptor_add_field(desc, fielddef); +} + +PHP_METHOD(MessageBuilderContext, optional) { + MessageBuilderContext *self = php_to_message_builder_context(getThis() TSRMLS_CC); + Descriptor *desc = php_to_descriptor(self->descriptor TSRMLS_CC); + // VALUE name, type, number, type_class; + const char *name, *type, *type_class; + int number, name_str_len, type_str_len, type_class_str_len; + if (ZEND_NUM_ARGS() == 3) { + if (zend_parse_parameters(3 TSRMLS_CC, "ssl", &name, + &name_str_len, &type, &type_str_len, &number) == FAILURE) { + return; + } + } else { + if (zend_parse_parameters(4 TSRMLS_CC, "ssls", &name, + &name_str_len, &type, &type_str_len, &number, &type_class, + &type_class_str_len) == FAILURE) { + return; + } + } + + msgdef_add_field(desc, UPB_LABEL_OPTIONAL, name, type, number, type_class); + + zval_copy_ctor(getThis()); + RETURN_ZVAL(getThis(), 1, 0); +} + +PHP_METHOD(MessageBuilderContext, finalizeToPool) { + MessageBuilderContext *self = php_to_message_builder_context(getThis() TSRMLS_CC); + DescriptorPool *pool = php_to_descriptor_pool(self->pool TSRMLS_CC); + Descriptor* desc = php_to_descriptor(self->descriptor TSRMLS_CC); + + Z_ADDREF_P(self->descriptor); + zend_hash_next_index_insert(pool->pending_list, &self->descriptor, + sizeof(zval *), NULL); + RETURN_ZVAL(self->pool, 1, 0); +} diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c new file mode 100644 index 00000000..c062d665 --- /dev/null +++ b/php/ext/google/protobuf/message.c @@ -0,0 +1,273 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2014 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 + +#include "protobuf.h" + +// ----------------------------------------------------------------------------- +// Class/module creation from msgdefs and enumdefs, respectively. +// ----------------------------------------------------------------------------- + +void* message_data(void* msg) { + return ((uint8_t *)msg) + sizeof(MessageHeader); +} + +void message_set_property(zval* object, zval* field_name, zval* value, + const zend_literal* key TSRMLS_DC) { + const upb_fielddef* field; + + MessageHeader* self = zend_object_store_get_object(object TSRMLS_CC); + + CHECK_TYPE(field_name, IS_STRING); + field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(field_name)); + if (field == NULL) { + zend_error(E_ERROR, "Unknown field: %s", Z_STRVAL_P(field_name)); + } + layout_set(self->descriptor->layout, message_data(self), field, value); +} + +zval* message_get_property(zval* object, zval* member, int type, + const zend_literal* key TSRMLS_DC) { + MessageHeader* self = + (MessageHeader*)zend_object_store_get_object(object TSRMLS_CC); + CHECK_TYPE(member, IS_STRING); + + const upb_fielddef* field; + field = upb_msgdef_ntofz(self->descriptor->msgdef, Z_STRVAL_P(member)); + if (field == NULL) { + return EG(uninitialized_zval_ptr); + } + zval* retval = layout_get(self->descriptor->layout, message_data(self), field TSRMLS_CC); + return retval; +} + +static zend_function_entry message_methods[] = { + PHP_ME(Message, encode, NULL, ZEND_ACC_PUBLIC) + {NULL, NULL, NULL} +}; + +/* stringsink *****************************************************************/ + +// This should probably be factored into a common upb component. + +typedef struct { + upb_byteshandler handler; + upb_bytessink sink; + char *ptr; + size_t len, size; +} stringsink; + +static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { + stringsink *sink = _sink; + sink->len = 0; + return sink; +} + +static size_t stringsink_string(void *_sink, const void *hd, const char *ptr, + size_t len, const upb_bufhandle *handle) { + stringsink *sink = _sink; + size_t new_size = sink->size; + + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + while (sink->len + len > new_size) { + new_size *= 2; + } + + if (new_size != sink->size) { + sink->ptr = realloc(sink->ptr, new_size); + sink->size = new_size; + } + + memcpy(sink->ptr + sink->len, ptr, len); + sink->len += len; + + return len; +} + +void stringsink_init(stringsink *sink) { + upb_byteshandler_init(&sink->handler); + upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); + upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); + + upb_bytessink_reset(&sink->sink, &sink->handler, sink); + + sink->size = 32; + sink->ptr = malloc(sink->size); + sink->len = 0; +} + +void stringsink_uninit(stringsink *sink) { free(sink->ptr); } + +// Stack-allocated context during an encode/decode operation. Contains the upb +// environment and its stack-based allocator, an initial buffer for allocations +// to avoid malloc() when possible, and a template for PHP exception messages +// if any error occurs. +#define STACK_ENV_STACKBYTES 4096 +typedef struct { + upb_env env; + upb_seededalloc alloc; + const char *php_error_template; + char allocbuf[STACK_ENV_STACKBYTES]; +} stackenv; + +static void stackenv_init(stackenv* se, const char* errmsg); +static void stackenv_uninit(stackenv* se); + +// Callback invoked by upb if any error occurs during parsing or serialization. +static bool env_error_func(void* ud, const upb_status* status) { + stackenv* se = ud; + // Free the env -- rb_raise will longjmp up the stack past the encode/decode + // function so it would not otherwise have been freed. + stackenv_uninit(se); + + // TODO(teboring): have a way to verify that this is actually a parse error, + // instead of just throwing "parse error" unconditionally. + zend_error(E_ERROR, se->php_error_template); + // Never reached. + return false; +} + +static void stackenv_init(stackenv* se, const char* errmsg) { + se->php_error_template = errmsg; + upb_env_init(&se->env); + upb_seededalloc_init(&se->alloc, &se->allocbuf, STACK_ENV_STACKBYTES); + upb_env_setallocfunc(&se->env, upb_seededalloc_getallocfunc(&se->alloc), + &se->alloc); + upb_env_seterrorfunc(&se->env, env_error_func, se); +} + +static void stackenv_uninit(stackenv* se) { + upb_env_uninit(&se->env); + upb_seededalloc_uninit(&se->alloc); +} + +// ----------------------------------------------------------------------------- +// Message +// ----------------------------------------------------------------------------- + +static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) { + if (desc->pb_serialize_handlers == NULL) { + desc->pb_serialize_handlers = + upb_pb_encoder_newhandlers(desc->msgdef, &desc->pb_serialize_handlers); + } + return desc->pb_serialize_handlers; +} + +PHP_METHOD(Message, encode) { + Descriptor* desc = (Descriptor*)zend_object_store_get_object( + CE_STATIC_MEMBERS(Z_OBJCE_P(getThis()))[0] TSRMLS_CC); + + stringsink sink; + stringsink_init(&sink); + + { + const upb_handlers* serialize_handlers = msgdef_pb_serialize_handlers(desc); + + stackenv se; + upb_pb_encoder* encoder; + + stackenv_init(&se, "Error occurred during encoding: %s"); + encoder = upb_pb_encoder_create(&se.env, serialize_handlers, &sink.sink); + + putmsg(getThis(), desc, upb_pb_encoder_input(encoder), 0); + + RETVAL_STRINGL(sink.ptr, sink.len, 1); + + stackenv_uninit(&se); + stringsink_uninit(&sink); + } +} + +void message_free(void * object TSRMLS_DC) { + FREE(object); +} + +zend_object_value message_create(zend_class_entry* ce TSRMLS_DC) { + zend_object_value return_value; + + zval* php_descriptor = get_def_obj(ce); + + Descriptor* desc = zend_object_store_get_object(php_descriptor TSRMLS_CC); + MessageHeader* msg = (MessageHeader*)ALLOC_N( + uint8_t, sizeof(MessageHeader) + desc->layout->size); + memset(message_data(msg), 0, desc->layout->size); + + // We wrap first so that everything in the message object is GC-rooted in case + // a collection happens during object creation in layout_init(). + msg->descriptor = desc; + + layout_init(desc->layout, message_data(msg)); + zend_object_std_init(&msg->std, ce TSRMLS_CC); + + return_value.handle = zend_objects_store_put( + msg, (zend_objects_store_dtor_t)zend_objects_destroy_object, + message_free, NULL TSRMLS_CC); + + return_value.handlers = PROTOBUF_G(message_handlers); + return return_value; +} + +const zend_class_entry* build_class_from_descriptor( + zval* php_descriptor TSRMLS_DC) { + Descriptor* desc = php_to_descriptor(php_descriptor); + if (desc->layout == NULL) { + MessageLayout* layout = create_layout(desc->msgdef); + desc->layout = layout; + } + // TODO(teboring): Add it back. + // if (desc->fill_method == NULL) { + // desc->fill_method = new_fillmsg_decodermethod(desc, &desc->fill_method); + // } + + const char* name = upb_msgdef_fullname(desc->msgdef); + if (name == NULL) { + zend_error(E_ERROR, "Descriptor does not have assigned name."); + } + + zend_class_entry class_entry; + INIT_CLASS_ENTRY_EX(class_entry, name, strlen(name), message_methods); + zend_class_entry* registered_ce = + zend_register_internal_class(&class_entry TSRMLS_CC); + + add_def_obj(registered_ce, php_descriptor); + + if (PROTOBUF_G(message_handlers) == NULL) { + PROTOBUF_G(message_handlers) = ALLOC(zend_object_handlers); + memcpy(PROTOBUF_G(message_handlers), zend_get_std_object_handlers(), + sizeof(zend_object_handlers)); + PROTOBUF_G(message_handlers)->write_property = message_set_property; + PROTOBUF_G(message_handlers)->read_property = message_get_property; + } + + registered_ce->create_object = message_create; +} diff --git a/php/ext/google/protobuf/protobuf.c b/php/ext/google/protobuf/protobuf.c new file mode 100644 index 00000000..b1ace8b0 --- /dev/null +++ b/php/ext/google/protobuf/protobuf.c @@ -0,0 +1,89 @@ +#include "protobuf.h" + +#include + +ZEND_DECLARE_MODULE_GLOBALS(protobuf) +static PHP_GINIT_FUNCTION(protobuf); +static PHP_GSHUTDOWN_FUNCTION(protobuf); + +// ----------------------------------------------------------------------------- +// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor +// instances. +// ----------------------------------------------------------------------------- + +void add_def_obj(const void* def, zval* value) { + uint nIndex = (ulong)def & PROTOBUF_G(upb_def_to_php_obj_map).nTableMask; + + zval* pDest = NULL; + Z_ADDREF_P(value); + zend_hash_index_update(&PROTOBUF_G(upb_def_to_php_obj_map), (zend_ulong)def, + &value, sizeof(zval*), &pDest); +} + +zval* get_def_obj(const void* def) { + zval** value; + if (zend_hash_index_find(&PROTOBUF_G(upb_def_to_php_obj_map), (zend_ulong)def, + &value) == FAILURE) { + zend_error(E_ERROR, "PHP object not found for given definition.\n"); + return NULL; + } + return *value; +} + +// ----------------------------------------------------------------------------- +// Utilities. +// ----------------------------------------------------------------------------- + +// define the function(s) we want to add +zend_function_entry protobuf_functions[] = { + ZEND_FE(get_generated_pool, NULL) + ZEND_FE_END +}; + +// "protobuf_functions" refers to the struct defined above +// we'll be filling in more of this later: you can use this to specify +// globals, php.ini info, startup and teardown functions, etc. +zend_module_entry protobuf_module_entry = { + STANDARD_MODULE_HEADER, + PHP_PROTOBUF_EXTNAME, // extension name + protobuf_functions, // function list + PHP_MINIT(protobuf), // process startup + NULL, // process shutdown + NULL, // request startup + NULL, // request shutdown + NULL, // extension info + PHP_PROTOBUF_VERSION, // extension version + PHP_MODULE_GLOBALS(protobuf), // globals descriptor + PHP_GINIT(protobuf), // globals ctor + PHP_GSHUTDOWN(protobuf), // globals dtor + NULL, // post deactivate + STANDARD_MODULE_PROPERTIES_EX +}; + +// install module +ZEND_GET_MODULE(protobuf) + +// global variables +static PHP_GINIT_FUNCTION(protobuf) { + protobuf_globals->generated_pool = NULL; + generated_pool = NULL; + protobuf_globals->message_handlers = NULL; + zend_hash_init(&protobuf_globals->upb_def_to_php_obj_map, 16, NULL, + ZVAL_PTR_DTOR, 0); +} + +static PHP_GSHUTDOWN_FUNCTION(protobuf) { + if (protobuf_globals->generated_pool != NULL) { + FREE_ZVAL(protobuf_globals->generated_pool); + } + if (protobuf_globals->message_handlers != NULL) { + FREE(protobuf_globals->message_handlers); + } + zend_hash_destroy(&protobuf_globals->upb_def_to_php_obj_map); +} + +PHP_MINIT_FUNCTION(protobuf) { + descriptor_pool_init(TSRMLS_C); + descriptor_init(TSRMLS_C); + message_builder_context_init(TSRMLS_C); +} diff --git a/php/ext/google/protobuf/protobuf.h b/php/ext/google/protobuf/protobuf.h new file mode 100644 index 00000000..f9038550 --- /dev/null +++ b/php/ext/google/protobuf/protobuf.h @@ -0,0 +1,281 @@ +#ifndef __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ +#define __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ + +#include + +#include "upb.h" + +#define PHP_PROTOBUF_EXTNAME "protobuf" +#define PHP_PROTOBUF_VERSION "0.01" + +// Forward decls. +struct DescriptorPool; +struct Descriptor; +struct FieldDescriptor; +struct EnumDescriptor; +struct MessageLayout; +struct MessageField; +struct MessageHeader; +struct MessageBuilderContext; +struct EnumBuilderContext; + +typedef struct DescriptorPool DescriptorPool; +typedef struct Descriptor Descriptor; +typedef struct FieldDescriptor FieldDescriptor; +typedef struct OneofDescriptor OneofDescriptor; +typedef struct EnumDescriptor EnumDescriptor; +typedef struct MessageLayout MessageLayout; +typedef struct MessageField MessageField; +typedef struct MessageHeader MessageHeader; +typedef struct MessageBuilderContext MessageBuilderContext; +typedef struct OneofBuilderContext OneofBuilderContext; +typedef struct EnumBuilderContext EnumBuilderContext; + +extern zend_class_entry* builder_type; +extern zend_class_entry* descriptor_type; +extern zend_class_entry* message_builder_context_type; + +extern DescriptorPool* generated_pool; // The actual generated pool + +ZEND_BEGIN_MODULE_GLOBALS(protobuf) + zval* generated_pool; + zend_object_handlers* message_handlers; + HashTable upb_def_to_php_obj_map; +ZEND_END_MODULE_GLOBALS(protobuf) + +ZEND_DECLARE_MODULE_GLOBALS(protobuf) + +#ifdef ZTS +#define PROTOBUF_G(v) TSRMG(protobuf_globals_id, zend_protobuf_globals*, v) +#else +#define PROTOBUF_G(v) (protobuf_globals.v) +#endif + +// ----------------------------------------------------------------------------- +// PHP functions and global variables. +// ----------------------------------------------------------------------------- + +PHP_MINIT_FUNCTION(protobuf); + +// ----------------------------------------------------------------------------- +// PHP class structure. +// ----------------------------------------------------------------------------- + +struct DescriptorPool { + zend_object std; + upb_symtab* symtab; + HashTable* pending_list; +}; + +struct Descriptor { + zend_object std; + const upb_msgdef* msgdef; + MessageLayout* layout; + // zval* klass; // begins as NULL + // const upb_handlers* fill_handlers; + // const upb_pbdecodermethod* fill_method; + const upb_handlers* pb_serialize_handlers; + // const upb_handlers* json_serialize_handlers; + // Handlers hold type class references for sub-message fields directly in some + // cases. We need to keep these rooted because they might otherwise be + // collected. + // zval_array typeclass_references; +}; + +struct FieldDescriptor { + zend_object std; + const upb_fielddef* fielddef; +}; + +struct OneofDescriptor { + zend_object std; + const upb_oneofdef* oneofdef; +}; + +struct EnumDescriptor { + zend_object std; + const upb_enumdef* enumdef; + // zval* module; // begins as NULL +}; + +// ----------------------------------------------------------------------------- +// Native slot storage abstraction. +// ----------------------------------------------------------------------------- + +#define NATIVE_SLOT_MAX_SIZE sizeof(uint64_t) + +size_t native_slot_size(upb_fieldtype_t type); + +#define MAP_KEY_FIELD 1 +#define MAP_VALUE_FIELD 2 + +// Oneof case slot value to indicate that no oneof case is set. The value `0` is +// safe because field numbers are used as case identifiers, and no field can +// have a number of 0. +#define ONEOF_CASE_NONE 0 + +// These operate on a map field (i.e., a repeated field of submessages whose +// submessage type is a map-entry msgdef). +bool is_map_field(const upb_fielddef* field); +const upb_fielddef* map_field_key(const upb_fielddef* field); +const upb_fielddef* map_field_value(const upb_fielddef* field); + +// These operate on a map-entry msgdef. +const upb_fielddef* map_entry_key(const upb_msgdef* msgdef); +const upb_fielddef* map_entry_value(const upb_msgdef* msgdef); + +// ----------------------------------------------------------------------------- +// Message layout / storage. +// ----------------------------------------------------------------------------- + +#define MESSAGE_FIELD_NO_CASE ((size_t)-1) + +struct MessageField { + size_t offset; + size_t case_offset; // for oneofs, a uint32. Else, MESSAGE_FIELD_NO_CASE. +}; + +struct MessageLayout { + const upb_msgdef* msgdef; + MessageField* fields; + size_t size; +}; + +void layout_init(MessageLayout* layout, void* storage); +zval* layout_get(MessageLayout* layout, const void* storage, + const upb_fielddef* field TSRMLS_DC); +MessageLayout* create_layout(const upb_msgdef* msgdef); +void free_layout(MessageLayout* layout); +zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/ + const void* memory TSRMLS_DC); + +// ----------------------------------------------------------------------------- +// Message class creation. +// ----------------------------------------------------------------------------- + +struct MessageHeader { + zend_object std; + Descriptor* descriptor; // kept alive by self.class.descriptor reference. + // Data comes after this. +}; + +struct MessageBuilderContext { + zend_object std; + zval* descriptor; + zval* pool; +}; + +struct OneofBuilderContext { + zend_object std; + // VALUE descriptor; + // VALUE builder; +}; + +struct EnumBuilderContext { + zend_object std; + // VALUE enumdesc; +}; + +// Forward-declare all of the PHP method implementations. + +DescriptorPool* php_to_descriptor_pool(zval* value TSRMLS_DC); +zend_object_value descriptor_pool_create(zend_class_entry *ce TSRMLS_DC); +void descriptor_pool_free_c(DescriptorPool* object TSRMLS_DC); +void descriptor_pool_free(void* object TSRMLS_DC); +void descriptor_pool_init_c_instance(DescriptorPool* pool TSRMLS_DC); +PHP_METHOD(DescriptorPool, addMessage); +PHP_METHOD(DescriptorPool, finalize); + +Descriptor* php_to_descriptor(zval* value TSRMLS_DC); +zend_object_value descriptor_create(zend_class_entry *ce TSRMLS_DC); +void descriptor_init_c_instance(Descriptor* intern TSRMLS_DC); +void descriptor_free_c(Descriptor* object TSRMLS_DC); +void descriptor_free(void* object TSRMLS_DC); +void descriptor_name_set(Descriptor *desc, const char *name); + +MessageBuilderContext* php_to_message_builder_context(zval* value TSRMLS_DC); +zend_object_value message_builder_context_create( + zend_class_entry* ce TSRMLS_DC); +void message_builder_context_init_c_instance( + MessageBuilderContext* intern TSRMLS_DC); +void message_builder_context_free_c(MessageBuilderContext* object TSRMLS_DC); +void message_builder_context_free(void* object TSRMLS_DC); +PHP_METHOD(MessageBuilderContext, optional); +PHP_METHOD(MessageBuilderContext, finalizeToPool); + +PHP_METHOD(Message, encode); +const zend_class_entry* build_class_from_descriptor( + zval* php_descriptor TSRMLS_DC); + +PHP_FUNCTION(get_generated_pool); + +// ----------------------------------------------------------------------------- +// Global map from upb {msg,enum}defs to wrapper Descriptor/EnumDescriptor +// instances. +// ---------------------------------------------------------------------------- + +void add_def_obj(const void* def, zval* value); +zval* get_def_obj(const void* def); + +// ----------------------------------------------------------------------------- +// Utilities. +// ----------------------------------------------------------------------------- + +// PHP Array utils. +#define Z_ARRVAL_SIZE_P(zval_p) zend_hash_num_elements(Z_ARRVAL_P(zval_p)) +#define Z_ARRVAL_BEGIN_P(zval_p) Z_ARRVAL_P(zval_p)->pListHead +#define Z_BUCKET_NEXT_PP(bucket_pp) *bucket_pp = (*bucket_pp)->pListNext + +#define DEFINE_PHP_OBJECT(class_name, class_name_lower, name) \ + do { \ + zval* name; \ + MAKE_STD_ZVAL(name); \ + object_init_ex(name, class_name_lower##_type); \ + } while (0) + +#define DEFINE_PHP_WRAPPER(class_name, class_name_lower, name, intern) \ + zval* name; \ + MAKE_STD_ZVAL(name); \ + object_init_ex(name, class_name_lower##_type); \ + Z_OBJVAL_P(name) \ + .handle = zend_objects_store_put( \ + intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, \ + class_name_lower##_free, NULL TSRMLS_CC); + +#define DEFINE_PHP_ZVAL(name) \ + do { \ + zval* name; \ + MAKE_STD_ZVAL(name); \ + } while (0) + +#define DEFINE_PHP_STRING(name, value) \ + do { \ + zval* name; \ + MAKE_STD_ZVAL(name); \ + ZVAL_STRING(name, value, 1); \ + } while (0) + +// Upb Utilities + +void check_upb_status(const upb_status* status, const char* msg); + +#define CHECK_UPB(code, msg) \ + do { \ + upb_status status = UPB_STATUS_INIT; \ + code; \ + check_upb_status(&status, msg); \ + } while (0) + +// Memory management + +#define ALLOC(class_name) (class_name*) emalloc(sizeof(class_name)) +#define ALLOC_N(class_name, n) (class_name*) emalloc(sizeof(class_name) * n) +#define FREE(object) efree(object) + +// Type Checking +#define CHECK_TYPE(field, type) \ + if (Z_TYPE_P(field) != type) { \ + zend_error(E_ERROR, "Unexpected type"); \ + } + +#endif // __GOOGLE_PROTOBUF_PHP_PROTOBUF_H__ diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c new file mode 100644 index 00000000..e5a09c17 --- /dev/null +++ b/php/ext/google/protobuf/storage.c @@ -0,0 +1,539 @@ +#include +#include + +// ----------------------------------------------------------------------------- +// PHP <-> native slot management. +// ----------------------------------------------------------------------------- + +static zval* int32_to_zval(int32_t value) { + zval* tmp; + MAKE_STD_ZVAL(tmp); + ZVAL_LONG(tmp, value); + php_printf("int32 to zval\n"); + // ZVAL_LONG(tmp, 1); + return tmp; +} + +#define DEREF(memory, type) *(type*)(memory) + +size_t native_slot_size(upb_fieldtype_t type) { + switch (type) { + case UPB_TYPE_FLOAT: return 4; + case UPB_TYPE_DOUBLE: return 8; + case UPB_TYPE_BOOL: return 1; + case UPB_TYPE_STRING: return sizeof(zval*); + case UPB_TYPE_BYTES: return sizeof(zval*); + case UPB_TYPE_MESSAGE: return sizeof(zval*); + case UPB_TYPE_ENUM: return 4; + case UPB_TYPE_INT32: return 4; + case UPB_TYPE_INT64: return 8; + case UPB_TYPE_UINT32: return 4; + case UPB_TYPE_UINT64: return 8; + default: return 0; + } +} + +static bool is_php_num(zval* value) { + // Is numerial string also valid? + return (Z_TYPE_P(value) == IS_LONG || + Z_TYPE_P(value) == IS_DOUBLE); +} + +void native_slot_check_int_range_precision(upb_fieldtype_t type, zval* val) { + // TODO(teboring): Add it back. + // if (!is_php_num(val)) { + // zend_error(E_ERROR, "Expected number type for integral field."); + // } + + // if (Z_TYPE_P(val) == IS_DOUBLE) { + // double dbl_val = NUM2DBL(val); + // if (floor(dbl_val) != dbl_val) { + // zend_error(E_ERROR, + // "Non-integral floating point value assigned to integer field."); + // } + // } + // if (type == UPB_TYPE_UINT32 || type == UPB_TYPE_UINT64) { + // if (NUM2DBL(val) < 0) { + // zend_error(E_ERROR, + // "Assigning negative value to unsigned integer field."); + // } + // } +} + +zval* native_slot_get(upb_fieldtype_t type, /*VALUE type_class,*/ + const void* memory TSRMLS_DC) { + zval* retval = NULL; + switch (type) { + // TODO(teboring): Add it back. + // case UPB_TYPE_FLOAT: + // return DBL2NUM(DEREF(memory, float)); + // case UPB_TYPE_DOUBLE: + // return DBL2NUM(DEREF(memory, double)); + // case UPB_TYPE_BOOL: + // return DEREF(memory, int8_t) ? Qtrue : Qfalse; + // case UPB_TYPE_STRING: + // case UPB_TYPE_BYTES: + // case UPB_TYPE_MESSAGE: + // return DEREF(memory, VALUE); + // case UPB_TYPE_ENUM: { + // int32_t val = DEREF(memory, int32_t); + // VALUE symbol = enum_lookup(type_class, INT2NUM(val)); + // if (symbol == Qnil) { + // return INT2NUM(val); + // } else { + // return symbol; + // } + // } + case UPB_TYPE_INT32: + return int32_to_zval(DEREF(memory, int32_t)); + // TODO(teboring): Add it back. + // case UPB_TYPE_INT64: + // return LL2NUM(DEREF(memory, int64_t)); + // case UPB_TYPE_UINT32: + // return UINT2NUM(DEREF(memory, uint32_t)); + // case UPB_TYPE_UINT64: + // return ULL2NUM(DEREF(memory, uint64_t)); + default: + return EG(uninitialized_zval_ptr); + } +} + +void native_slot_init(upb_fieldtype_t type, void* memory) { + switch (type) { + case UPB_TYPE_FLOAT: + DEREF(memory, float) = 0.0; + break; + case UPB_TYPE_DOUBLE: + DEREF(memory, double) = 0.0; + break; + case UPB_TYPE_BOOL: + DEREF(memory, int8_t) = 0; + break; + // TODO(teboring): Add it back. + // case UPB_TYPE_STRING: + // case UPB_TYPE_BYTES: + // DEREF(memory, VALUE) = php_str_new2(""); + // php_enc_associate(DEREF(memory, VALUE), (type == UPB_TYPE_BYTES) + // ? kRubyString8bitEncoding + // : kRubyStringUtf8Encoding); + // break; + // case UPB_TYPE_MESSAGE: + // DEREF(memory, VALUE) = Qnil; + // break; + case UPB_TYPE_ENUM: + case UPB_TYPE_INT32: + DEREF(memory, int32_t) = 0; + break; + case UPB_TYPE_INT64: + DEREF(memory, int64_t) = 0; + break; + case UPB_TYPE_UINT32: + DEREF(memory, uint32_t) = 0; + break; + case UPB_TYPE_UINT64: + DEREF(memory, uint64_t) = 0; + break; + default: + break; + } +} + +void native_slot_set(upb_fieldtype_t type, /*VALUE type_class,*/ void* memory, + zval* value) { + native_slot_set_value_and_case(type, /*type_class,*/ memory, value, NULL, 0); +} + +void native_slot_set_value_and_case(upb_fieldtype_t type, /*VALUE type_class,*/ + void* memory, zval* value, + uint32_t* case_memory, + uint32_t case_number) { + switch (type) { + case UPB_TYPE_FLOAT: + if (!Z_TYPE_P(value) == IS_LONG) { + zend_error(E_ERROR, "Expected number type for float field."); + } + DEREF(memory, float) = Z_DVAL_P(value); + break; + case UPB_TYPE_DOUBLE: + // TODO(teboring): Add it back. + // if (!is_php_num(value)) { + // zend_error(E_ERROR, "Expected number type for double field."); + // } + // DEREF(memory, double) = Z_DVAL_P(value); + break; + case UPB_TYPE_BOOL: { + int8_t val = -1; + if (zval_is_true(value)) { + val = 1; + } else { + val = 0; + } + // TODO(teboring): Add it back. + // else if (value == Qfalse) { + // val = 0; + // } + // else { + // php_raise(php_eTypeError, "Invalid argument for boolean field."); + // } + DEREF(memory, int8_t) = val; + break; + } + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { + // TODO(teboring): Add it back. + // if (Z_TYPE_P(value) != IS_STRING) { + // zend_error(E_ERROR, "Invalid argument for string field."); + // } + // native_slot_validate_string_encoding(type, value); + // DEREF(memory, zval*) = value; + break; + } + case UPB_TYPE_MESSAGE: { + // TODO(teboring): Add it back. + // if (CLASS_OF(value) == CLASS_OF(Qnil)) { + // value = Qnil; + // } else if (CLASS_OF(value) != type_class) { + // php_raise(php_eTypeError, + // "Invalid type %s to assign to submessage field.", + // php_class2name(CLASS_OF(value))); + // } + // DEREF(memory, VALUE) = value; + break; + } + case UPB_TYPE_ENUM: { + // TODO(teboring): Add it back. + // int32_t int_val = 0; + // if (!is_php_num(value) && TYPE(value) != T_SYMBOL) { + // php_raise(php_eTypeError, + // "Expected number or symbol type for enum field."); + // } + // if (TYPE(value) == T_SYMBOL) { + // // Ensure that the given symbol exists in the enum module. + // VALUE lookup = php_funcall(type_class, php_intern("resolve"), 1, value); + // if (lookup == Qnil) { + // php_raise(php_eRangeError, "Unknown symbol value for enum field."); + // } else { + // int_val = NUM2INT(lookup); + // } + // } else { + // native_slot_check_int_range_precision(UPB_TYPE_INT32, value); + // int_val = NUM2INT(value); + // } + // DEREF(memory, int32_t) = int_val; + // break; + } + case UPB_TYPE_INT32: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT32: + case UPB_TYPE_UINT64: + native_slot_check_int_range_precision(type, value); + switch (type) { + case UPB_TYPE_INT32: + php_printf("Setting INT32 field\n"); + DEREF(memory, int32_t) = Z_LVAL_P(value); + break; + case UPB_TYPE_INT64: + // TODO(teboring): Add it back. + // DEREF(memory, int64_t) = NUM2LL(value); + break; + case UPB_TYPE_UINT32: + // TODO(teboring): Add it back. + // DEREF(memory, uint32_t) = NUM2UINT(value); + break; + case UPB_TYPE_UINT64: + // TODO(teboring): Add it back. + // DEREF(memory, uint64_t) = NUM2ULL(value); + break; + default: + break; + } + break; + default: + break; + } + + if (case_memory != NULL) { + *case_memory = case_number; + } +} + +// ----------------------------------------------------------------------------- +// Map field utilities. +// ---------------------------------------------------------------------------- + +const upb_msgdef* tryget_map_entry_msgdef(const upb_fielddef* field) { + const upb_msgdef* subdef; + if (upb_fielddef_label(field) != UPB_LABEL_REPEATED || + upb_fielddef_type(field) != UPB_TYPE_MESSAGE) { + return NULL; + } + subdef = upb_fielddef_msgsubdef(field); + return upb_msgdef_mapentry(subdef) ? subdef : NULL; +} + +const upb_msgdef* map_entry_msgdef(const upb_fielddef* field) { + const upb_msgdef* subdef = tryget_map_entry_msgdef(field); + assert(subdef); + return subdef; +} + +bool is_map_field(const upb_fielddef* field) { + return tryget_map_entry_msgdef(field) != NULL; +} + +// ----------------------------------------------------------------------------- +// Memory layout management. +// ----------------------------------------------------------------------------- + +static size_t align_up_to(size_t offset, size_t granularity) { + // Granularity must be a power of two. + return (offset + granularity - 1) & ~(granularity - 1); +} + +MessageLayout* create_layout(const upb_msgdef* msgdef) { + MessageLayout* layout = ALLOC(MessageLayout); + int nfields = upb_msgdef_numfields(msgdef); + upb_msg_field_iter it; + upb_msg_oneof_iter oit; + size_t off = 0; + + layout->fields = ALLOC_N(MessageField, nfields); + + for (upb_msg_field_begin(&it, msgdef); !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + const upb_fielddef* field = upb_msg_iter_field(&it); + size_t field_size; + + if (upb_fielddef_containingoneof(field)) { + // Oneofs are handled separately below. + continue; + } + + // Allocate |field_size| bytes for this field in the layout. + field_size = 0; + if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { + field_size = sizeof(zval*); + } else { + field_size = native_slot_size(upb_fielddef_type(field)); + } + + // Align current offset up to | size | granularity. + off = align_up_to(off, field_size); + layout->fields[upb_fielddef_index(field)].offset = off; + layout->fields[upb_fielddef_index(field)].case_offset = + MESSAGE_FIELD_NO_CASE; + off += field_size; + } + + // Handle oneofs now -- we iterate over oneofs specifically and allocate only + // one slot per oneof. + // + // We assign all value slots first, then pack the 'case' fields at the end, + // since in the common case (modern 64-bit platform) these are 8 bytes and 4 + // bytes respectively and we want to avoid alignment overhead. + // + // Note that we reserve 4 bytes (a uint32) per 'case' slot because the value + // space for oneof cases is conceptually as wide as field tag numbers. In + // practice, it's unlikely that a oneof would have more than e.g. 256 or 64K + // members (8 or 16 bits respectively), so conceivably we could assign + // consecutive case numbers and then pick a smaller oneof case slot size, but + // the complexity to implement this indirection is probably not worthwhile. + for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); + upb_msg_oneof_next(&oit)) { + const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); + upb_oneof_iter fit; + + // Always allocate NATIVE_SLOT_MAX_SIZE bytes, but share the slot between + // all fields. + size_t field_size = NATIVE_SLOT_MAX_SIZE; + // Align the offset . + off = align_up_to( off, field_size); + // Assign all fields in the oneof this same offset. + for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* field = upb_oneof_iter_field(&fit); + layout->fields[upb_fielddef_index(field)].offset = off; + } + off += field_size; + } + + // Now the case fields. + for (upb_msg_oneof_begin(&oit, msgdef); !upb_msg_oneof_done(&oit); + upb_msg_oneof_next(&oit)) { + const upb_oneofdef* oneof = upb_msg_iter_oneof(&oit); + upb_oneof_iter fit; + + size_t field_size = sizeof(uint32_t); + // Align the offset . + off = (off + field_size - 1) & ~(field_size - 1); + // Assign all fields in the oneof this same offset. + for (upb_oneof_begin(&fit, oneof); !upb_oneof_done(&fit); + upb_oneof_next(&fit)) { + const upb_fielddef* field = upb_oneof_iter_field(&fit); + layout->fields[upb_fielddef_index(field)].case_offset = off; + } + off += field_size; + } + + layout->size = off; + + layout->msgdef = msgdef; + upb_msgdef_ref(layout->msgdef, &layout->msgdef); + + return layout; +} + +void free_layout(MessageLayout* layout) { + FREE(layout->fields); + upb_msgdef_unref(layout->msgdef, &layout->msgdef); + FREE(layout); +} + +// TODO(teboring): Add it back. +// VALUE field_type_class(const upb_fielddef* field) { +// VALUE type_class = Qnil; +// if (upb_fielddef_type(field) == UPB_TYPE_MESSAGE) { +// VALUE submsgdesc = get_def_obj(upb_fielddef_subdef(field)); +// type_class = Descriptor_msgclass(submsgdesc); +// } else if (upb_fielddef_type(field) == UPB_TYPE_ENUM) { +// VALUE subenumdesc = get_def_obj(upb_fielddef_subdef(field)); +// type_class = EnumDescriptor_enummodule(subenumdesc); +// } +// return type_class; +// } + +static void* slot_memory(MessageLayout* layout, const void* storage, + const upb_fielddef* field) { + return ((uint8_t*)storage) + layout->fields[upb_fielddef_index(field)].offset; +} + +static uint32_t* slot_oneof_case(MessageLayout* layout, const void* storage, + const upb_fielddef* field) { + return (uint32_t*)(((uint8_t*)storage) + + layout->fields[upb_fielddef_index(field)].case_offset); +} + +void layout_set(MessageLayout* layout, void* storage, const upb_fielddef* field, + zval* val) { + void* memory = slot_memory(layout, storage, field); + uint32_t* oneof_case = slot_oneof_case(layout, storage, field); + + if (upb_fielddef_containingoneof(field)) { + if (Z_TYPE_P(val) == IS_NULL) { + // Assigning nil to a oneof field clears the oneof completely. + *oneof_case = ONEOF_CASE_NONE; + memset(memory, 0, NATIVE_SLOT_MAX_SIZE); + } else { + // The transition between field types for a single oneof (union) slot is + // somewhat complex because we need to ensure that a GC triggered at any + // point by a call into the Ruby VM sees a valid state for this field and + // does not either go off into the weeds (following what it thinks is a + // VALUE but is actually a different field type) or miss an object (seeing + // what it thinks is a primitive field but is actually a VALUE for the new + // field type). + // + // In order for the transition to be safe, the oneof case slot must be in + // sync with the value slot whenever the Ruby VM has been called. Thus, we + // use native_slot_set_value_and_case(), which ensures that both the value + // and case number are altered atomically (w.r.t. the Ruby VM). + native_slot_set_value_and_case(upb_fielddef_type(field), + /*field_type_class(field),*/ memory, val, + oneof_case, upb_fielddef_number(field)); + } + } else if (is_map_field(field)) { + // TODO(teboring): Add it back. + // check_map_field_type(val, field); + // DEREF(memory, zval*) = val; + } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { + // TODO(teboring): Add it back. + // check_repeated_field_type(val, field); + // DEREF(memory, zval*) = val; + } else { + native_slot_set(upb_fielddef_type(field), /*field_type_class(field),*/ memory, + val); + } +} + +void layout_init(MessageLayout* layout, void* storage) { + upb_msg_field_iter it; + for (upb_msg_field_begin(&it, layout->msgdef); !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + const upb_fielddef* field = upb_msg_iter_field(&it); + void* memory = slot_memory(layout, storage, field); + uint32_t* oneof_case = slot_oneof_case(layout, storage, field); + + if (upb_fielddef_containingoneof(field)) { + // TODO(teboring): Add it back. + // memset(memory, 0, NATIVE_SLOT_MAX_SIZE); + // *oneof_case = ONEOF_CASE_NONE; + } else if (is_map_field(field)) { + // TODO(teboring): Add it back. + // VALUE map = Qnil; + + // const upb_fielddef* key_field = map_field_key(field); + // const upb_fielddef* value_field = map_field_value(field); + // VALUE type_class = field_type_class(value_field); + + // if (type_class != Qnil) { + // VALUE args[3] = { + // fieldtype_to_php(upb_fielddef_type(key_field)), + // fieldtype_to_php(upb_fielddef_type(value_field)), type_class, + // }; + // map = php_class_new_instance(3, args, cMap); + // } else { + // VALUE args[2] = { + // fieldtype_to_php(upb_fielddef_type(key_field)), + // fieldtype_to_php(upb_fielddef_type(value_field)), + // }; + // map = php_class_new_instance(2, args, cMap); + // } + + // DEREF(memory, VALUE) = map; + } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { + // TODO(teboring): Add it back. + // VALUE ary = Qnil; + + // VALUE type_class = field_type_class(field); + + // if (type_class != Qnil) { + // VALUE args[2] = { + // fieldtype_to_php(upb_fielddef_type(field)), type_class, + // }; + // ary = php_class_new_instance(2, args, cRepeatedField); + // } else { + // VALUE args[1] = {fieldtype_to_php(upb_fielddef_type(field))}; + // ary = php_class_new_instance(1, args, cRepeatedField); + // } + + // DEREF(memory, VALUE) = ary; + } else { + native_slot_init(upb_fielddef_type(field), memory); + } + } +} + +zval* layout_get(MessageLayout* layout, const void* storage, + const upb_fielddef* field TSRMLS_DC) { + void* memory = slot_memory(layout, storage, field); + uint32_t* oneof_case = slot_oneof_case(layout, storage, field); + + if (upb_fielddef_containingoneof(field)) { + if (*oneof_case != upb_fielddef_number(field)) { + return NULL; + // TODO(teboring): Add it back. + // return Qnil; + } + return NULL; + // TODO(teboring): Add it back. + // return native_slot_get(upb_fielddef_type(field), field_type_class(field), + // memory); + } else if (upb_fielddef_label(field) == UPB_LABEL_REPEATED) { + return NULL; + // TODO(teboring): Add it back. + // return *((VALUE*)memory); + } else { + return native_slot_get( + upb_fielddef_type(field), /*field_type_class(field), */ + memory TSRMLS_CC); + } +} diff --git a/php/ext/google/protobuf/test.php b/php/ext/google/protobuf/test.php new file mode 100644 index 00000000..6bbadd48 --- /dev/null +++ b/php/ext/google/protobuf/test.php @@ -0,0 +1,15 @@ +addMessage("TestMessage") + ->optional("optional_int32_a", "int32", 1) + ->optional("optional_int32_b", "int32", 2) + ->finalizeToPool() + ->finalize(); + +$test_message = new \TestMessage(); + +?> diff --git a/php/ext/google/protobuf/upb.c b/php/ext/google/protobuf/upb.c new file mode 100644 index 00000000..048a163a --- /dev/null +++ b/php/ext/google/protobuf/upb.c @@ -0,0 +1,11990 @@ +// Amalgamated source file +#include "upb.h" + + +#include +#include + +typedef struct { + size_t len; + char str[1]; /* Null-terminated string data follows. */ +} str_t; + +static str_t *newstr(const char *data, size_t len) { + str_t *ret = malloc(sizeof(*ret) + len); + if (!ret) return NULL; + ret->len = len; + memcpy(ret->str, data, len); + ret->str[len] = '\0'; + return ret; +} + +static void freestr(str_t *s) { free(s); } + +/* isalpha() etc. from are locale-dependent, which we don't want. */ +static bool upb_isbetween(char c, char low, char high) { + return c >= low && c <= high; +} + +static bool upb_isletter(char c) { + return upb_isbetween(c, 'A', 'Z') || upb_isbetween(c, 'a', 'z') || c == '_'; +} + +static bool upb_isalphanum(char c) { + return upb_isletter(c) || upb_isbetween(c, '0', '9'); +} + +static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) { + bool start = true; + size_t i; + for (i = 0; i < len; i++) { + char c = str[i]; + if (c == '.') { + if (start || !full) { + upb_status_seterrf(s, "invalid name: unexpected '.' (%s)", str); + return false; + } + start = true; + } else if (start) { + if (!upb_isletter(c)) { + upb_status_seterrf( + s, "invalid name: path components must start with a letter (%s)", + str); + return false; + } + start = false; + } else { + if (!upb_isalphanum(c)) { + upb_status_seterrf(s, "invalid name: non-alphanumeric character (%s)", + str); + return false; + } + } + } + return !start; +} + + +/* upb_def ********************************************************************/ + +upb_deftype_t upb_def_type(const upb_def *d) { return d->type; } + +const char *upb_def_fullname(const upb_def *d) { return d->fullname; } + +bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) { + assert(!upb_def_isfrozen(def)); + if (!upb_isident(fullname, strlen(fullname), true, s)) return false; + free((void*)def->fullname); + def->fullname = upb_strdup(fullname); + return true; +} + +upb_def *upb_def_dup(const upb_def *def, const void *o) { + switch (def->type) { + case UPB_DEF_MSG: + return upb_msgdef_upcast_mutable( + upb_msgdef_dup(upb_downcast_msgdef(def), o)); + case UPB_DEF_FIELD: + return upb_fielddef_upcast_mutable( + upb_fielddef_dup(upb_downcast_fielddef(def), o)); + case UPB_DEF_ENUM: + return upb_enumdef_upcast_mutable( + upb_enumdef_dup(upb_downcast_enumdef(def), o)); + default: assert(false); return NULL; + } +} + +static bool upb_def_init(upb_def *def, upb_deftype_t type, + const struct upb_refcounted_vtbl *vtbl, + const void *owner) { + if (!upb_refcounted_init(upb_def_upcast_mutable(def), vtbl, owner)) return false; + def->type = type; + def->fullname = NULL; + def->came_from_user = false; + return true; +} + +static void upb_def_uninit(upb_def *def) { + free((void*)def->fullname); +} + +static const char *msgdef_name(const upb_msgdef *m) { + const char *name = upb_def_fullname(upb_msgdef_upcast(m)); + return name ? name : "(anonymous)"; +} + +static bool upb_validate_field(upb_fielddef *f, upb_status *s) { + if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { + upb_status_seterrmsg(s, "fielddef must have name and number set"); + return false; + } + + if (!f->type_is_set_) { + upb_status_seterrmsg(s, "fielddef type was not initialized"); + return false; + } + + if (upb_fielddef_lazy(f) && + upb_fielddef_descriptortype(f) != UPB_DESCRIPTOR_TYPE_MESSAGE) { + upb_status_seterrmsg(s, + "only length-delimited submessage fields may be lazy"); + return false; + } + + if (upb_fielddef_hassubdef(f)) { + const upb_def *subdef; + + if (f->subdef_is_symbolic) { + upb_status_seterrf(s, "field '%s.%s' has not been resolved", + msgdef_name(f->msg.def), upb_fielddef_name(f)); + return false; + } + + subdef = upb_fielddef_subdef(f); + if (subdef == NULL) { + upb_status_seterrf(s, "field %s.%s is missing required subdef", + msgdef_name(f->msg.def), upb_fielddef_name(f)); + return false; + } + + if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) { + upb_status_seterrf(s, + "subdef of field %s.%s is not frozen or being frozen", + msgdef_name(f->msg.def), upb_fielddef_name(f)); + return false; + } + } + + if (upb_fielddef_type(f) == UPB_TYPE_ENUM) { + bool has_default_name = upb_fielddef_enumhasdefaultstr(f); + bool has_default_number = upb_fielddef_enumhasdefaultint32(f); + + /* Previously verified by upb_validate_enumdef(). */ + assert(upb_enumdef_numvals(upb_fielddef_enumsubdef(f)) > 0); + + /* We've already validated that we have an associated enumdef and that it + * has at least one member, so at least one of these should be true. + * Because if the user didn't set anything, we'll pick up the enum's + * default, but if the user *did* set something we should at least pick up + * the one they set (int32 or string). */ + assert(has_default_name || has_default_number); + + if (!has_default_name) { + upb_status_seterrf(s, + "enum default for field %s.%s (%d) is not in the enum", + msgdef_name(f->msg.def), upb_fielddef_name(f), + upb_fielddef_defaultint32(f)); + return false; + } + + if (!has_default_number) { + upb_status_seterrf(s, + "enum default for field %s.%s (%s) is not in the enum", + msgdef_name(f->msg.def), upb_fielddef_name(f), + upb_fielddef_defaultstr(f, NULL)); + return false; + } + + /* Lift the effective numeric default into the field's default slot, in case + * we were only getting it "by reference" from the enumdef. */ + upb_fielddef_setdefaultint32(f, upb_fielddef_defaultint32(f)); + } + + /* Ensure that MapEntry submessages only appear as repeated fields, not + * optional/required (singular) fields. */ + if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE && + upb_fielddef_msgsubdef(f) != NULL) { + const upb_msgdef *subdef = upb_fielddef_msgsubdef(f); + if (upb_msgdef_mapentry(subdef) && !upb_fielddef_isseq(f)) { + upb_status_seterrf(s, + "Field %s refers to mapentry message but is not " + "a repeated field", + upb_fielddef_name(f) ? upb_fielddef_name(f) : + "(unnamed)"); + return false; + } + } + + return true; +} + +static bool upb_validate_enumdef(const upb_enumdef *e, upb_status *s) { + if (upb_enumdef_numvals(e) == 0) { + upb_status_seterrf(s, "enum %s has no members (must have at least one)", + upb_enumdef_fullname(e)); + return false; + } + + return true; +} + +/* All submessage fields are lower than all other fields. + * Secondly, fields are increasing in order. */ +uint32_t field_rank(const upb_fielddef *f) { + uint32_t ret = upb_fielddef_number(f); + const uint32_t high_bit = 1 << 30; + assert(ret < high_bit); + if (!upb_fielddef_issubmsg(f)) + ret |= high_bit; + return ret; +} + +int cmp_fields(const void *p1, const void *p2) { + const upb_fielddef *f1 = *(upb_fielddef*const*)p1; + const upb_fielddef *f2 = *(upb_fielddef*const*)p2; + return field_rank(f1) - field_rank(f2); +} + +static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { + /* Sort fields. upb internally relies on UPB_TYPE_MESSAGE fields having the + * lowest indexes, but we do not publicly guarantee this. */ + upb_msg_field_iter j; + int i; + uint32_t selector; + int n = upb_msgdef_numfields(m); + upb_fielddef **fields = malloc(n * sizeof(*fields)); + if (!fields) return false; + + m->submsg_field_count = 0; + for(i = 0, upb_msg_field_begin(&j, m); + !upb_msg_field_done(&j); + upb_msg_field_next(&j), i++) { + upb_fielddef *f = upb_msg_iter_field(&j); + assert(f->msg.def == m); + if (!upb_validate_field(f, s)) { + free(fields); + return false; + } + if (upb_fielddef_issubmsg(f)) { + m->submsg_field_count++; + } + fields[i] = f; + } + + qsort(fields, n, sizeof(*fields), cmp_fields); + + selector = UPB_STATIC_SELECTOR_COUNT + m->submsg_field_count; + for (i = 0; i < n; i++) { + upb_fielddef *f = fields[i]; + f->index_ = i; + f->selector_base = selector + upb_handlers_selectorbaseoffset(f); + selector += upb_handlers_selectorcount(f); + } + m->selector_count = selector; + +#ifndef NDEBUG + { + /* Verify that all selectors for the message are distinct. */ +#define TRY(type) \ + if (upb_handlers_getselector(f, type, &sel)) upb_inttable_insert(&t, sel, v); + + upb_inttable t; + upb_value v; + upb_selector_t sel; + + upb_inttable_init(&t, UPB_CTYPE_BOOL); + v = upb_value_bool(true); + upb_inttable_insert(&t, UPB_STARTMSG_SELECTOR, v); + upb_inttable_insert(&t, UPB_ENDMSG_SELECTOR, v); + for(upb_msg_field_begin(&j, m); + !upb_msg_field_done(&j); + upb_msg_field_next(&j)) { + upb_fielddef *f = upb_msg_iter_field(&j); + /* These calls will assert-fail in upb_table if the value already + * exists. */ + TRY(UPB_HANDLER_INT32); + TRY(UPB_HANDLER_INT64) + TRY(UPB_HANDLER_UINT32) + TRY(UPB_HANDLER_UINT64) + TRY(UPB_HANDLER_FLOAT) + TRY(UPB_HANDLER_DOUBLE) + TRY(UPB_HANDLER_BOOL) + TRY(UPB_HANDLER_STARTSTR) + TRY(UPB_HANDLER_STRING) + TRY(UPB_HANDLER_ENDSTR) + TRY(UPB_HANDLER_STARTSUBMSG) + TRY(UPB_HANDLER_ENDSUBMSG) + TRY(UPB_HANDLER_STARTSEQ) + TRY(UPB_HANDLER_ENDSEQ) + } + upb_inttable_uninit(&t); + } +#undef TRY +#endif + + free(fields); + return true; +} + +bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { + int i; + int maxdepth; + bool ret; + upb_status_clear(s); + + /* First perform validation, in two passes so we can check that we have a + * transitive closure without needing to search. */ + for (i = 0; i < n; i++) { + upb_def *def = defs[i]; + if (upb_def_isfrozen(def)) { + /* Could relax this requirement if it's annoying. */ + upb_status_seterrmsg(s, "def is already frozen"); + goto err; + } else if (def->type == UPB_DEF_FIELD) { + upb_status_seterrmsg(s, "standalone fielddefs can not be frozen"); + goto err; + } else if (def->type == UPB_DEF_ENUM) { + if (!upb_validate_enumdef(upb_dyncast_enumdef(def), s)) { + goto err; + } + } else { + /* Set now to detect transitive closure in the second pass. */ + def->came_from_user = true; + } + } + + /* Second pass of validation. Also assign selector bases and indexes, and + * compact tables. */ + for (i = 0; i < n; i++) { + upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]); + upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]); + if (m) { + upb_inttable_compact(&m->itof); + if (!assign_msg_indices(m, s)) { + goto err; + } + } else if (e) { + upb_inttable_compact(&e->iton); + } + } + + /* Def graph contains FieldDefs between each MessageDef, so double the + * limit. */ + maxdepth = UPB_MAX_MESSAGE_DEPTH * 2; + + /* Validation all passed; freeze the defs. */ + ret = upb_refcounted_freeze((upb_refcounted * const *)defs, n, s, maxdepth); + assert(!(s && ret != upb_ok(s))); + return ret; + +err: + for (i = 0; i < n; i++) { + defs[i]->came_from_user = false; + } + assert(!(s && upb_ok(s))); + return false; +} + + +/* upb_enumdef ****************************************************************/ + +static void upb_enumdef_free(upb_refcounted *r) { + upb_enumdef *e = (upb_enumdef*)r; + upb_inttable_iter i; + upb_inttable_begin(&i, &e->iton); + for( ; !upb_inttable_done(&i); upb_inttable_next(&i)) { + /* To clean up the upb_strdup() from upb_enumdef_addval(). */ + free(upb_value_getcstr(upb_inttable_iter_value(&i))); + } + upb_strtable_uninit(&e->ntoi); + upb_inttable_uninit(&e->iton); + upb_def_uninit(upb_enumdef_upcast_mutable(e)); + free(e); +} + +upb_enumdef *upb_enumdef_new(const void *owner) { + static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_enumdef_free}; + upb_enumdef *e = malloc(sizeof(*e)); + if (!e) return NULL; + if (!upb_def_init(upb_enumdef_upcast_mutable(e), UPB_DEF_ENUM, &vtbl, owner)) + goto err2; + if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2; + if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1; + return e; + +err1: + upb_strtable_uninit(&e->ntoi); +err2: + free(e); + return NULL; +} + +upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner) { + upb_enum_iter i; + upb_enumdef *new_e = upb_enumdef_new(owner); + if (!new_e) return NULL; + for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) { + bool success = upb_enumdef_addval( + new_e, upb_enum_iter_name(&i),upb_enum_iter_number(&i), NULL); + if (!success) { + upb_enumdef_unref(new_e, owner); + return NULL; + } + } + return new_e; +} + +bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status) { + upb_def *d = upb_enumdef_upcast_mutable(e); + return upb_def_freeze(&d, 1, status); +} + +const char *upb_enumdef_fullname(const upb_enumdef *e) { + return upb_def_fullname(upb_enumdef_upcast(e)); +} + +bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, + upb_status *s) { + return upb_def_setfullname(upb_enumdef_upcast_mutable(e), fullname, s); +} + +bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num, + upb_status *status) { + if (!upb_isident(name, strlen(name), false, status)) { + return false; + } + if (upb_enumdef_ntoiz(e, name, NULL)) { + upb_status_seterrf(status, "name '%s' is already defined", name); + return false; + } + if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) { + upb_status_seterrmsg(status, "out of memory"); + return false; + } + if (!upb_inttable_lookup(&e->iton, num, NULL) && + !upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) { + upb_status_seterrmsg(status, "out of memory"); + upb_strtable_remove(&e->ntoi, name, NULL); + return false; + } + if (upb_enumdef_numvals(e) == 1) { + bool ok = upb_enumdef_setdefault(e, num, NULL); + UPB_ASSERT_VAR(ok, ok); + } + return true; +} + +int32_t upb_enumdef_default(const upb_enumdef *e) { + assert(upb_enumdef_iton(e, e->defaultval)); + return e->defaultval; +} + +bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s) { + assert(!upb_enumdef_isfrozen(e)); + if (!upb_enumdef_iton(e, val)) { + upb_status_seterrf(s, "number '%d' is not in the enum.", val); + return false; + } + e->defaultval = val; + return true; +} + +int upb_enumdef_numvals(const upb_enumdef *e) { + return upb_strtable_count(&e->ntoi); +} + +void upb_enum_begin(upb_enum_iter *i, const upb_enumdef *e) { + /* We iterate over the ntoi table, to account for duplicate numbers. */ + upb_strtable_begin(i, &e->ntoi); +} + +void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); } +bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); } + +bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name, + size_t len, int32_t *num) { + upb_value v; + if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) { + return false; + } + if (num) *num = upb_value_getint32(v); + return true; +} + +const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) { + upb_value v; + return upb_inttable_lookup32(&def->iton, num, &v) ? + upb_value_getcstr(v) : NULL; +} + +const char *upb_enum_iter_name(upb_enum_iter *iter) { + return upb_strtable_iter_key(iter); +} + +int32_t upb_enum_iter_number(upb_enum_iter *iter) { + return upb_value_getint32(upb_strtable_iter_value(iter)); +} + + +/* upb_fielddef ***************************************************************/ + +static void upb_fielddef_init_default(upb_fielddef *f); + +static void upb_fielddef_uninit_default(upb_fielddef *f) { + if (f->type_is_set_ && f->default_is_string && f->defaultval.bytes) + freestr(f->defaultval.bytes); +} + +static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const upb_fielddef *f = (const upb_fielddef*)r; + if (upb_fielddef_containingtype(f)) { + visit(r, upb_msgdef_upcast2(upb_fielddef_containingtype(f)), closure); + } + if (upb_fielddef_containingoneof(f)) { + visit(r, upb_oneofdef_upcast2(upb_fielddef_containingoneof(f)), closure); + } + if (upb_fielddef_subdef(f)) { + visit(r, upb_def_upcast(upb_fielddef_subdef(f)), closure); + } +} + +static void freefield(upb_refcounted *r) { + upb_fielddef *f = (upb_fielddef*)r; + upb_fielddef_uninit_default(f); + if (f->subdef_is_symbolic) + free(f->sub.name); + upb_def_uninit(upb_fielddef_upcast_mutable(f)); + free(f); +} + +static const char *enumdefaultstr(const upb_fielddef *f) { + const upb_enumdef *e; + assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); + e = upb_fielddef_enumsubdef(f); + if (f->default_is_string && f->defaultval.bytes) { + /* Default was explicitly set as a string. */ + str_t *s = f->defaultval.bytes; + return s->str; + } else if (e) { + if (!f->default_is_string) { + /* Default was explicitly set as an integer; look it up in enumdef. */ + const char *name = upb_enumdef_iton(e, f->defaultval.sint); + if (name) { + return name; + } + } else { + /* Default is completely unset; pull enumdef default. */ + if (upb_enumdef_numvals(e) > 0) { + const char *name = upb_enumdef_iton(e, upb_enumdef_default(e)); + assert(name); + return name; + } + } + } + return NULL; +} + +static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) { + const upb_enumdef *e; + assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); + e = upb_fielddef_enumsubdef(f); + if (!f->default_is_string) { + /* Default was explicitly set as an integer. */ + *val = f->defaultval.sint; + return true; + } else if (e) { + if (f->defaultval.bytes) { + /* Default was explicitly set as a str; try to lookup corresponding int. */ + str_t *s = f->defaultval.bytes; + if (upb_enumdef_ntoiz(e, s->str, val)) { + return true; + } + } else { + /* Default is unset; try to pull in enumdef default. */ + if (upb_enumdef_numvals(e) > 0) { + *val = upb_enumdef_default(e); + return true; + } + } + } + return false; +} + +upb_fielddef *upb_fielddef_new(const void *o) { + static const struct upb_refcounted_vtbl vtbl = {visitfield, freefield}; + upb_fielddef *f = malloc(sizeof(*f)); + if (!f) return NULL; + if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD, &vtbl, o)) { + free(f); + return NULL; + } + f->msg.def = NULL; + f->sub.def = NULL; + f->oneof = NULL; + f->subdef_is_symbolic = false; + f->msg_is_symbolic = false; + f->label_ = UPB_LABEL_OPTIONAL; + f->type_ = UPB_TYPE_INT32; + f->number_ = 0; + f->type_is_set_ = false; + f->tagdelim = false; + f->is_extension_ = false; + f->lazy_ = false; + f->packed_ = true; + + /* For the moment we default this to UPB_INTFMT_VARIABLE, since it will work + * with all integer types and is in some since more "default" since the most + * normal-looking proto2 types int32/int64/uint32/uint64 use variable. + * + * Other options to consider: + * - there is no default; users must set this manually (like type). + * - default signed integers to UPB_INTFMT_ZIGZAG, since it's more likely to + * be an optimal default for signed integers. */ + f->intfmt = UPB_INTFMT_VARIABLE; + return f; +} + +upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { + const char *srcname; + upb_fielddef *newf = upb_fielddef_new(owner); + if (!newf) return NULL; + upb_fielddef_settype(newf, upb_fielddef_type(f)); + upb_fielddef_setlabel(newf, upb_fielddef_label(f)); + upb_fielddef_setnumber(newf, upb_fielddef_number(f), NULL); + upb_fielddef_setname(newf, upb_fielddef_name(f), NULL); + if (f->default_is_string && f->defaultval.bytes) { + str_t *s = f->defaultval.bytes; + upb_fielddef_setdefaultstr(newf, s->str, s->len, NULL); + } else { + newf->default_is_string = f->default_is_string; + newf->defaultval = f->defaultval; + } + + if (f->subdef_is_symbolic) { + srcname = f->sub.name; /* Might be NULL. */ + } else { + srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL; + } + if (srcname) { + char *newname = malloc(strlen(f->sub.def->fullname) + 2); + if (!newname) { + upb_fielddef_unref(newf, owner); + return NULL; + } + strcpy(newname, "."); + strcat(newname, f->sub.def->fullname); + upb_fielddef_setsubdefname(newf, newname, NULL); + free(newname); + } + + return newf; +} + +bool upb_fielddef_typeisset(const upb_fielddef *f) { + return f->type_is_set_; +} + +upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f) { + assert(f->type_is_set_); + return f->type_; +} + +uint32_t upb_fielddef_index(const upb_fielddef *f) { + return f->index_; +} + +upb_label_t upb_fielddef_label(const upb_fielddef *f) { + return f->label_; +} + +upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f) { + return f->intfmt; +} + +bool upb_fielddef_istagdelim(const upb_fielddef *f) { + return f->tagdelim; +} + +uint32_t upb_fielddef_number(const upb_fielddef *f) { + return f->number_; +} + +bool upb_fielddef_isextension(const upb_fielddef *f) { + return f->is_extension_; +} + +bool upb_fielddef_lazy(const upb_fielddef *f) { + return f->lazy_; +} + +bool upb_fielddef_packed(const upb_fielddef *f) { + return f->packed_; +} + +const char *upb_fielddef_name(const upb_fielddef *f) { + return upb_def_fullname(upb_fielddef_upcast(f)); +} + +const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) { + return f->msg_is_symbolic ? NULL : f->msg.def; +} + +const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f) { + return f->oneof; +} + +upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) { + return (upb_msgdef*)upb_fielddef_containingtype(f); +} + +const char *upb_fielddef_containingtypename(upb_fielddef *f) { + return f->msg_is_symbolic ? f->msg.name : NULL; +} + +static void release_containingtype(upb_fielddef *f) { + if (f->msg_is_symbolic) free(f->msg.name); +} + +bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, + upb_status *s) { + assert(!upb_fielddef_isfrozen(f)); + if (upb_fielddef_containingtype(f)) { + upb_status_seterrmsg(s, "field has already been added to a message."); + return false; + } + /* TODO: validate name (upb_isident() doesn't quite work atm because this name + * may have a leading "."). */ + release_containingtype(f); + f->msg.name = upb_strdup(name); + f->msg_is_symbolic = true; + return true; +} + +bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) { + if (upb_fielddef_containingtype(f) || upb_fielddef_containingoneof(f)) { + upb_status_seterrmsg(s, "Already added to message or oneof"); + return false; + } + return upb_def_setfullname(upb_fielddef_upcast_mutable(f), name, s); +} + +static void chkdefaulttype(const upb_fielddef *f, upb_fieldtype_t type) { + UPB_UNUSED(f); + UPB_UNUSED(type); + assert(f->type_is_set_ && upb_fielddef_type(f) == type); +} + +int64_t upb_fielddef_defaultint64(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_INT64); + return f->defaultval.sint; +} + +int32_t upb_fielddef_defaultint32(const upb_fielddef *f) { + if (f->type_is_set_ && upb_fielddef_type(f) == UPB_TYPE_ENUM) { + int32_t val; + bool ok = enumdefaultint32(f, &val); + UPB_ASSERT_VAR(ok, ok); + return val; + } else { + chkdefaulttype(f, UPB_TYPE_INT32); + return f->defaultval.sint; + } +} + +uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_UINT64); + return f->defaultval.uint; +} + +uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_UINT32); + return f->defaultval.uint; +} + +bool upb_fielddef_defaultbool(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_BOOL); + return f->defaultval.uint; +} + +float upb_fielddef_defaultfloat(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_FLOAT); + return f->defaultval.flt; +} + +double upb_fielddef_defaultdouble(const upb_fielddef *f) { + chkdefaulttype(f, UPB_TYPE_DOUBLE); + return f->defaultval.dbl; +} + +const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len) { + assert(f->type_is_set_); + assert(upb_fielddef_type(f) == UPB_TYPE_STRING || + upb_fielddef_type(f) == UPB_TYPE_BYTES || + upb_fielddef_type(f) == UPB_TYPE_ENUM); + + if (upb_fielddef_type(f) == UPB_TYPE_ENUM) { + const char *ret = enumdefaultstr(f); + assert(ret); + /* Enum defaults can't have embedded NULLs. */ + if (len) *len = strlen(ret); + return ret; + } + + if (f->default_is_string) { + str_t *str = f->defaultval.bytes; + if (len) *len = str->len; + return str->str; + } + + return NULL; +} + +static void upb_fielddef_init_default(upb_fielddef *f) { + f->default_is_string = false; + switch (upb_fielddef_type(f)) { + case UPB_TYPE_DOUBLE: f->defaultval.dbl = 0; break; + case UPB_TYPE_FLOAT: f->defaultval.flt = 0; break; + case UPB_TYPE_INT32: + case UPB_TYPE_INT64: f->defaultval.sint = 0; break; + case UPB_TYPE_UINT64: + case UPB_TYPE_UINT32: + case UPB_TYPE_BOOL: f->defaultval.uint = 0; break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + f->defaultval.bytes = newstr("", 0); + f->default_is_string = true; + break; + case UPB_TYPE_MESSAGE: break; + case UPB_TYPE_ENUM: + /* This is our special sentinel that indicates "not set" for an enum. */ + f->default_is_string = true; + f->defaultval.bytes = NULL; + break; + } +} + +const upb_def *upb_fielddef_subdef(const upb_fielddef *f) { + return f->subdef_is_symbolic ? NULL : f->sub.def; +} + +const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) { + const upb_def *def = upb_fielddef_subdef(f); + return def ? upb_dyncast_msgdef(def) : NULL; +} + +const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f) { + const upb_def *def = upb_fielddef_subdef(f); + return def ? upb_dyncast_enumdef(def) : NULL; +} + +upb_def *upb_fielddef_subdef_mutable(upb_fielddef *f) { + return (upb_def*)upb_fielddef_subdef(f); +} + +const char *upb_fielddef_subdefname(const upb_fielddef *f) { + if (f->subdef_is_symbolic) { + return f->sub.name; + } else if (f->sub.def) { + return upb_def_fullname(f->sub.def); + } else { + return NULL; + } +} + +bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) { + if (upb_fielddef_containingtype(f)) { + upb_status_seterrmsg( + s, "cannot change field number after adding to a message"); + return false; + } + if (number == 0 || number > UPB_MAX_FIELDNUMBER) { + upb_status_seterrf(s, "invalid field number (%u)", number); + return false; + } + f->number_ = number; + return true; +} + +void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type) { + assert(!upb_fielddef_isfrozen(f)); + assert(upb_fielddef_checktype(type)); + upb_fielddef_uninit_default(f); + f->type_ = type; + f->type_is_set_ = true; + upb_fielddef_init_default(f); +} + +void upb_fielddef_setdescriptortype(upb_fielddef *f, int type) { + assert(!upb_fielddef_isfrozen(f)); + switch (type) { + case UPB_DESCRIPTOR_TYPE_DOUBLE: + upb_fielddef_settype(f, UPB_TYPE_DOUBLE); + break; + case UPB_DESCRIPTOR_TYPE_FLOAT: + upb_fielddef_settype(f, UPB_TYPE_FLOAT); + break; + case UPB_DESCRIPTOR_TYPE_INT64: + case UPB_DESCRIPTOR_TYPE_SFIXED64: + case UPB_DESCRIPTOR_TYPE_SINT64: + upb_fielddef_settype(f, UPB_TYPE_INT64); + break; + case UPB_DESCRIPTOR_TYPE_UINT64: + case UPB_DESCRIPTOR_TYPE_FIXED64: + upb_fielddef_settype(f, UPB_TYPE_UINT64); + break; + case UPB_DESCRIPTOR_TYPE_INT32: + case UPB_DESCRIPTOR_TYPE_SFIXED32: + case UPB_DESCRIPTOR_TYPE_SINT32: + upb_fielddef_settype(f, UPB_TYPE_INT32); + break; + case UPB_DESCRIPTOR_TYPE_UINT32: + case UPB_DESCRIPTOR_TYPE_FIXED32: + upb_fielddef_settype(f, UPB_TYPE_UINT32); + break; + case UPB_DESCRIPTOR_TYPE_BOOL: + upb_fielddef_settype(f, UPB_TYPE_BOOL); + break; + case UPB_DESCRIPTOR_TYPE_STRING: + upb_fielddef_settype(f, UPB_TYPE_STRING); + break; + case UPB_DESCRIPTOR_TYPE_BYTES: + upb_fielddef_settype(f, UPB_TYPE_BYTES); + break; + case UPB_DESCRIPTOR_TYPE_GROUP: + case UPB_DESCRIPTOR_TYPE_MESSAGE: + upb_fielddef_settype(f, UPB_TYPE_MESSAGE); + break; + case UPB_DESCRIPTOR_TYPE_ENUM: + upb_fielddef_settype(f, UPB_TYPE_ENUM); + break; + default: assert(false); + } + + if (type == UPB_DESCRIPTOR_TYPE_FIXED64 || + type == UPB_DESCRIPTOR_TYPE_FIXED32 || + type == UPB_DESCRIPTOR_TYPE_SFIXED64 || + type == UPB_DESCRIPTOR_TYPE_SFIXED32) { + upb_fielddef_setintfmt(f, UPB_INTFMT_FIXED); + } else if (type == UPB_DESCRIPTOR_TYPE_SINT64 || + type == UPB_DESCRIPTOR_TYPE_SINT32) { + upb_fielddef_setintfmt(f, UPB_INTFMT_ZIGZAG); + } else { + upb_fielddef_setintfmt(f, UPB_INTFMT_VARIABLE); + } + + upb_fielddef_settagdelim(f, type == UPB_DESCRIPTOR_TYPE_GROUP); +} + +upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) { + switch (upb_fielddef_type(f)) { + case UPB_TYPE_FLOAT: return UPB_DESCRIPTOR_TYPE_FLOAT; + case UPB_TYPE_DOUBLE: return UPB_DESCRIPTOR_TYPE_DOUBLE; + case UPB_TYPE_BOOL: return UPB_DESCRIPTOR_TYPE_BOOL; + case UPB_TYPE_STRING: return UPB_DESCRIPTOR_TYPE_STRING; + case UPB_TYPE_BYTES: return UPB_DESCRIPTOR_TYPE_BYTES; + case UPB_TYPE_ENUM: return UPB_DESCRIPTOR_TYPE_ENUM; + case UPB_TYPE_INT32: + switch (upb_fielddef_intfmt(f)) { + case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT32; + case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED32; + case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT32; + } + case UPB_TYPE_INT64: + switch (upb_fielddef_intfmt(f)) { + case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_INT64; + case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_SFIXED64; + case UPB_INTFMT_ZIGZAG: return UPB_DESCRIPTOR_TYPE_SINT64; + } + case UPB_TYPE_UINT32: + switch (upb_fielddef_intfmt(f)) { + case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT32; + case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED32; + case UPB_INTFMT_ZIGZAG: return -1; + } + case UPB_TYPE_UINT64: + switch (upb_fielddef_intfmt(f)) { + case UPB_INTFMT_VARIABLE: return UPB_DESCRIPTOR_TYPE_UINT64; + case UPB_INTFMT_FIXED: return UPB_DESCRIPTOR_TYPE_FIXED64; + case UPB_INTFMT_ZIGZAG: return -1; + } + case UPB_TYPE_MESSAGE: + return upb_fielddef_istagdelim(f) ? + UPB_DESCRIPTOR_TYPE_GROUP : UPB_DESCRIPTOR_TYPE_MESSAGE; + } + return 0; +} + +void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) { + assert(!upb_fielddef_isfrozen(f)); + f->is_extension_ = is_extension; +} + +void upb_fielddef_setlazy(upb_fielddef *f, bool lazy) { + assert(!upb_fielddef_isfrozen(f)); + f->lazy_ = lazy; +} + +void upb_fielddef_setpacked(upb_fielddef *f, bool packed) { + assert(!upb_fielddef_isfrozen(f)); + f->packed_ = packed; +} + +void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) { + assert(!upb_fielddef_isfrozen(f)); + assert(upb_fielddef_checklabel(label)); + f->label_ = label; +} + +void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt) { + assert(!upb_fielddef_isfrozen(f)); + assert(upb_fielddef_checkintfmt(fmt)); + f->intfmt = fmt; +} + +void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim) { + assert(!upb_fielddef_isfrozen(f)); + f->tagdelim = tag_delim; + f->tagdelim = tag_delim; +} + +static bool checksetdefault(upb_fielddef *f, upb_fieldtype_t type) { + if (!f->type_is_set_ || upb_fielddef_isfrozen(f) || + upb_fielddef_type(f) != type) { + assert(false); + return false; + } + if (f->default_is_string) { + str_t *s = f->defaultval.bytes; + assert(s || type == UPB_TYPE_ENUM); + if (s) freestr(s); + } + f->default_is_string = false; + return true; +} + +void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t value) { + if (checksetdefault(f, UPB_TYPE_INT64)) + f->defaultval.sint = value; +} + +void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t value) { + if ((upb_fielddef_type(f) == UPB_TYPE_ENUM && + checksetdefault(f, UPB_TYPE_ENUM)) || + checksetdefault(f, UPB_TYPE_INT32)) { + f->defaultval.sint = value; + } +} + +void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t value) { + if (checksetdefault(f, UPB_TYPE_UINT64)) + f->defaultval.uint = value; +} + +void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t value) { + if (checksetdefault(f, UPB_TYPE_UINT32)) + f->defaultval.uint = value; +} + +void upb_fielddef_setdefaultbool(upb_fielddef *f, bool value) { + if (checksetdefault(f, UPB_TYPE_BOOL)) + f->defaultval.uint = value; +} + +void upb_fielddef_setdefaultfloat(upb_fielddef *f, float value) { + if (checksetdefault(f, UPB_TYPE_FLOAT)) + f->defaultval.flt = value; +} + +void upb_fielddef_setdefaultdouble(upb_fielddef *f, double value) { + if (checksetdefault(f, UPB_TYPE_DOUBLE)) + f->defaultval.dbl = value; +} + +bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, + upb_status *s) { + str_t *str2; + assert(upb_fielddef_isstring(f) || f->type_ == UPB_TYPE_ENUM); + if (f->type_ == UPB_TYPE_ENUM && !upb_isident(str, len, false, s)) + return false; + + if (f->default_is_string) { + str_t *s = f->defaultval.bytes; + assert(s || f->type_ == UPB_TYPE_ENUM); + if (s) freestr(s); + } else { + assert(f->type_ == UPB_TYPE_ENUM); + } + + str2 = newstr(str, len); + f->defaultval.bytes = str2; + f->default_is_string = true; + return true; +} + +void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str, + upb_status *s) { + assert(f->type_is_set_); + upb_fielddef_setdefaultstr(f, str, str ? strlen(str) : 0, s); +} + +bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f) { + int32_t val; + assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); + return enumdefaultint32(f, &val); +} + +bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f) { + assert(f->type_is_set_ && f->type_ == UPB_TYPE_ENUM); + return enumdefaultstr(f) != NULL; +} + +static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef, + upb_status *s) { + if (f->type_ == UPB_TYPE_MESSAGE) { + if (upb_dyncast_msgdef(subdef)) return true; + upb_status_seterrmsg(s, "invalid subdef type for this submessage field"); + return false; + } else if (f->type_ == UPB_TYPE_ENUM) { + if (upb_dyncast_enumdef(subdef)) return true; + upb_status_seterrmsg(s, "invalid subdef type for this enum field"); + return false; + } else { + upb_status_seterrmsg(s, "only message and enum fields can have a subdef"); + return false; + } +} + +static void release_subdef(upb_fielddef *f) { + if (f->subdef_is_symbolic) { + free(f->sub.name); + } else if (f->sub.def) { + upb_unref2(f->sub.def, f); + } +} + +bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef, + upb_status *s) { + assert(!upb_fielddef_isfrozen(f)); + assert(upb_fielddef_hassubdef(f)); + if (subdef && !upb_subdef_typecheck(f, subdef, s)) return false; + release_subdef(f); + f->sub.def = subdef; + f->subdef_is_symbolic = false; + if (f->sub.def) upb_ref2(f->sub.def, f); + return true; +} + +bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef, + upb_status *s) { + return upb_fielddef_setsubdef(f, upb_msgdef_upcast(subdef), s); +} + +bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef, + upb_status *s) { + return upb_fielddef_setsubdef(f, upb_enumdef_upcast(subdef), s); +} + +bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, + upb_status *s) { + assert(!upb_fielddef_isfrozen(f)); + if (!upb_fielddef_hassubdef(f)) { + upb_status_seterrmsg(s, "field type does not accept a subdef"); + return false; + } + /* TODO: validate name (upb_isident() doesn't quite work atm because this name + * may have a leading "."). */ + release_subdef(f); + f->sub.name = upb_strdup(name); + f->subdef_is_symbolic = true; + return true; +} + +bool upb_fielddef_issubmsg(const upb_fielddef *f) { + return upb_fielddef_type(f) == UPB_TYPE_MESSAGE; +} + +bool upb_fielddef_isstring(const upb_fielddef *f) { + return upb_fielddef_type(f) == UPB_TYPE_STRING || + upb_fielddef_type(f) == UPB_TYPE_BYTES; +} + +bool upb_fielddef_isseq(const upb_fielddef *f) { + return upb_fielddef_label(f) == UPB_LABEL_REPEATED; +} + +bool upb_fielddef_isprimitive(const upb_fielddef *f) { + return !upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f); +} + +bool upb_fielddef_ismap(const upb_fielddef *f) { + return upb_fielddef_isseq(f) && upb_fielddef_issubmsg(f) && + upb_msgdef_mapentry(upb_fielddef_msgsubdef(f)); +} + +bool upb_fielddef_hassubdef(const upb_fielddef *f) { + return upb_fielddef_issubmsg(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM; +} + +static bool between(int32_t x, int32_t low, int32_t high) { + return x >= low && x <= high; +} + +bool upb_fielddef_checklabel(int32_t label) { return between(label, 1, 3); } +bool upb_fielddef_checktype(int32_t type) { return between(type, 1, 11); } +bool upb_fielddef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } + +bool upb_fielddef_checkdescriptortype(int32_t type) { + return between(type, 1, 18); +} + +/* upb_msgdef *****************************************************************/ + +static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + upb_msg_oneof_iter o; + const upb_msgdef *m = (const upb_msgdef*)r; + upb_msg_field_iter i; + for(upb_msg_field_begin(&i, m); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + upb_fielddef *f = upb_msg_iter_field(&i); + visit(r, upb_fielddef_upcast2(f), closure); + } + for(upb_msg_oneof_begin(&o, m); + !upb_msg_oneof_done(&o); + upb_msg_oneof_next(&o)) { + upb_oneofdef *f = upb_msg_iter_oneof(&o); + visit(r, upb_oneofdef_upcast2(f), closure); + } +} + +static void freemsg(upb_refcounted *r) { + upb_msgdef *m = (upb_msgdef*)r; + upb_strtable_uninit(&m->ntoo); + upb_strtable_uninit(&m->ntof); + upb_inttable_uninit(&m->itof); + upb_def_uninit(upb_msgdef_upcast_mutable(m)); + free(m); +} + +upb_msgdef *upb_msgdef_new(const void *owner) { + static const struct upb_refcounted_vtbl vtbl = {visitmsg, freemsg}; + upb_msgdef *m = malloc(sizeof(*m)); + if (!m) return NULL; + if (!upb_def_init(upb_msgdef_upcast_mutable(m), UPB_DEF_MSG, &vtbl, owner)) + goto err2; + if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err3; + if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err2; + if (!upb_strtable_init(&m->ntoo, UPB_CTYPE_PTR)) goto err1; + m->map_entry = false; + return m; + +err1: + upb_strtable_uninit(&m->ntof); +err2: + upb_inttable_uninit(&m->itof); +err3: + free(m); + return NULL; +} + +upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { + bool ok; + upb_msg_field_iter i; + upb_msg_oneof_iter o; + + upb_msgdef *newm = upb_msgdef_new(owner); + if (!newm) return NULL; + ok = upb_def_setfullname(upb_msgdef_upcast_mutable(newm), + upb_def_fullname(upb_msgdef_upcast(m)), + NULL); + newm->map_entry = m->map_entry; + UPB_ASSERT_VAR(ok, ok); + for(upb_msg_field_begin(&i, m); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + upb_fielddef *f = upb_fielddef_dup(upb_msg_iter_field(&i), &f); + /* Fields in oneofs are dup'd below. */ + if (upb_fielddef_containingoneof(f)) continue; + if (!f || !upb_msgdef_addfield(newm, f, &f, NULL)) { + upb_msgdef_unref(newm, owner); + return NULL; + } + } + for(upb_msg_oneof_begin(&o, m); + !upb_msg_oneof_done(&o); + upb_msg_oneof_next(&o)) { + upb_oneofdef *f = upb_oneofdef_dup(upb_msg_iter_oneof(&o), &f); + if (!f || !upb_msgdef_addoneof(newm, f, &f, NULL)) { + upb_msgdef_unref(newm, owner); + return NULL; + } + } + return newm; +} + +bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status) { + upb_def *d = upb_msgdef_upcast_mutable(m); + return upb_def_freeze(&d, 1, status); +} + +const char *upb_msgdef_fullname(const upb_msgdef *m) { + return upb_def_fullname(upb_msgdef_upcast(m)); +} + +bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, + upb_status *s) { + return upb_def_setfullname(upb_msgdef_upcast_mutable(m), fullname, s); +} + +/* Helper: check that the field |f| is safe to add to msgdef |m|. Set an error + * on status |s| and return false if not. */ +static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f, + upb_status *s) { + if (upb_fielddef_containingtype(f) != NULL) { + upb_status_seterrmsg(s, "fielddef already belongs to a message"); + return false; + } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { + upb_status_seterrmsg(s, "field name or number were not set"); + return false; + } else if (upb_msgdef_ntofz(m, upb_fielddef_name(f)) || + upb_msgdef_itof(m, upb_fielddef_number(f))) { + upb_status_seterrmsg(s, "duplicate field name or number for field"); + return false; + } + return true; +} + +static void add_field(upb_msgdef *m, upb_fielddef *f, const void *ref_donor) { + release_containingtype(f); + f->msg.def = m; + f->msg_is_symbolic = false; + upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f)); + upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f)); + upb_ref2(f, m); + upb_ref2(m, f); + if (ref_donor) upb_fielddef_unref(f, ref_donor); +} + +bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor, + upb_status *s) { + /* TODO: extensions need to have a separate namespace, because proto2 allows a + * top-level extension (ie. one not in any package) to have the same name as a + * field from the message. + * + * This also implies that there needs to be a separate lookup-by-name method + * for extensions. It seems desirable for iteration to return both extensions + * and non-extensions though. + * + * We also need to validate that the field number is in an extension range iff + * it is an extension. + * + * This method is idempotent. Check if |f| is already part of this msgdef and + * return immediately if so. */ + if (upb_fielddef_containingtype(f) == m) { + return true; + } + + /* Check constraints for all fields before performing any action. */ + if (!check_field_add(m, f, s)) { + return false; + } else if (upb_fielddef_containingoneof(f) != NULL) { + /* Fields in a oneof can only be added by adding the oneof to the msgdef. */ + upb_status_seterrmsg(s, "fielddef is part of a oneof"); + return false; + } + + /* Constraint checks ok, perform the action. */ + add_field(m, f, ref_donor); + return true; +} + +bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, + upb_status *s) { + upb_oneof_iter it; + + /* Check various conditions that would prevent this oneof from being added. */ + if (upb_oneofdef_containingtype(o)) { + upb_status_seterrmsg(s, "oneofdef already belongs to a message"); + return false; + } else if (upb_oneofdef_name(o) == NULL) { + upb_status_seterrmsg(s, "oneofdef name was not set"); + return false; + } else if (upb_msgdef_ntooz(m, upb_oneofdef_name(o))) { + upb_status_seterrmsg(s, "duplicate oneof name"); + return false; + } + + /* Check that all of the oneof's fields do not conflict with names or numbers + * of fields already in the message. */ + for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) { + const upb_fielddef *f = upb_oneof_iter_field(&it); + if (!check_field_add(m, f, s)) { + return false; + } + } + + /* Everything checks out -- commit now. */ + + /* Add oneof itself first. */ + o->parent = m; + upb_strtable_insert(&m->ntoo, upb_oneofdef_name(o), upb_value_ptr(o)); + upb_ref2(o, m); + upb_ref2(m, o); + + /* Add each field of the oneof directly to the msgdef. */ + for (upb_oneof_begin(&it, o); !upb_oneof_done(&it); upb_oneof_next(&it)) { + upb_fielddef *f = upb_oneof_iter_field(&it); + add_field(m, f, NULL); + } + + if (ref_donor) upb_oneofdef_unref(o, ref_donor); + + return true; +} + +const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { + upb_value val; + return upb_inttable_lookup32(&m->itof, i, &val) ? + upb_value_getptr(val) : NULL; +} + +const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, + size_t len) { + upb_value val; + return upb_strtable_lookup2(&m->ntof, name, len, &val) ? + upb_value_getptr(val) : NULL; +} + +const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, + size_t len) { + upb_value val; + return upb_strtable_lookup2(&m->ntoo, name, len, &val) ? + upb_value_getptr(val) : NULL; +} + +int upb_msgdef_numfields(const upb_msgdef *m) { + return upb_strtable_count(&m->ntof); +} + +int upb_msgdef_numoneofs(const upb_msgdef *m) { + return upb_strtable_count(&m->ntoo); +} + +void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) { + assert(!upb_msgdef_isfrozen(m)); + m->map_entry = map_entry; +} + +bool upb_msgdef_mapentry(const upb_msgdef *m) { + return m->map_entry; +} + +void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m) { + upb_inttable_begin(iter, &m->itof); +} + +void upb_msg_field_next(upb_msg_field_iter *iter) { upb_inttable_next(iter); } + +bool upb_msg_field_done(const upb_msg_field_iter *iter) { + return upb_inttable_done(iter); +} + +upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter) { + return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter)); +} + +void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) { + upb_inttable_iter_setdone(iter); +} + +void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) { + upb_strtable_begin(iter, &m->ntoo); +} + +void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { upb_strtable_next(iter); } + +bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) { + return upb_strtable_done(iter); +} + +upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter) { + return (upb_oneofdef*)upb_value_getptr(upb_strtable_iter_value(iter)); +} + +void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter) { + upb_strtable_iter_setdone(iter); +} + +/* upb_oneofdef ***************************************************************/ + +static void visitoneof(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const upb_oneofdef *o = (const upb_oneofdef*)r; + upb_oneof_iter i; + for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) { + const upb_fielddef *f = upb_oneof_iter_field(&i); + visit(r, upb_fielddef_upcast2(f), closure); + } + if (o->parent) { + visit(r, upb_msgdef_upcast2(o->parent), closure); + } +} + +static void freeoneof(upb_refcounted *r) { + upb_oneofdef *o = (upb_oneofdef*)r; + upb_strtable_uninit(&o->ntof); + upb_inttable_uninit(&o->itof); + upb_def_uninit(upb_oneofdef_upcast_mutable(o)); + free(o); +} + +upb_oneofdef *upb_oneofdef_new(const void *owner) { + static const struct upb_refcounted_vtbl vtbl = {visitoneof, freeoneof}; + upb_oneofdef *o = malloc(sizeof(*o)); + o->parent = NULL; + if (!o) return NULL; + if (!upb_def_init(upb_oneofdef_upcast_mutable(o), UPB_DEF_ONEOF, &vtbl, + owner)) + goto err2; + if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2; + if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1; + return o; + +err1: + upb_inttable_uninit(&o->itof); +err2: + free(o); + return NULL; +} + +upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) { + bool ok; + upb_oneof_iter i; + upb_oneofdef *newo = upb_oneofdef_new(owner); + if (!newo) return NULL; + ok = upb_def_setfullname(upb_oneofdef_upcast_mutable(newo), + upb_def_fullname(upb_oneofdef_upcast(o)), NULL); + UPB_ASSERT_VAR(ok, ok); + for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) { + upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f); + if (!f || !upb_oneofdef_addfield(newo, f, &f, NULL)) { + upb_oneofdef_unref(newo, owner); + return NULL; + } + } + return newo; +} + +const char *upb_oneofdef_name(const upb_oneofdef *o) { + return upb_def_fullname(upb_oneofdef_upcast(o)); +} + +bool upb_oneofdef_setname(upb_oneofdef *o, const char *fullname, + upb_status *s) { + if (upb_oneofdef_containingtype(o)) { + upb_status_seterrmsg(s, "oneof already added to a message"); + return false; + } + return upb_def_setfullname(upb_oneofdef_upcast_mutable(o), fullname, s); +} + +const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) { + return o->parent; +} + +int upb_oneofdef_numfields(const upb_oneofdef *o) { + return upb_strtable_count(&o->ntof); +} + +bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f, + const void *ref_donor, + upb_status *s) { + assert(!upb_oneofdef_isfrozen(o)); + assert(!o->parent || !upb_msgdef_isfrozen(o->parent)); + + /* This method is idempotent. Check if |f| is already part of this oneofdef + * and return immediately if so. */ + if (upb_fielddef_containingoneof(f) == o) { + return true; + } + + /* The field must have an OPTIONAL label. */ + if (upb_fielddef_label(f) != UPB_LABEL_OPTIONAL) { + upb_status_seterrmsg(s, "fields in oneof must have OPTIONAL label"); + return false; + } + + /* Check that no field with this name or number exists already in the oneof. + * Also check that the field is not already part of a oneof. */ + if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { + upb_status_seterrmsg(s, "field name or number were not set"); + return false; + } else if (upb_oneofdef_itof(o, upb_fielddef_number(f)) || + upb_oneofdef_ntofz(o, upb_fielddef_name(f))) { + upb_status_seterrmsg(s, "duplicate field name or number"); + return false; + } else if (upb_fielddef_containingoneof(f) != NULL) { + upb_status_seterrmsg(s, "fielddef already belongs to a oneof"); + return false; + } + + /* We allow adding a field to the oneof either if the field is not part of a + * msgdef, or if it is and we are also part of the same msgdef. */ + if (o->parent == NULL) { + /* If we're not in a msgdef, the field cannot be either. Otherwise we would + * need to magically add this oneof to a msgdef to remain consistent, which + * is surprising behavior. */ + if (upb_fielddef_containingtype(f) != NULL) { + upb_status_seterrmsg(s, "fielddef already belongs to a message, but " + "oneof does not"); + return false; + } + } else { + /* If we're in a msgdef, the user can add fields that either aren't in any + * msgdef (in which case they're added to our msgdef) or already a part of + * our msgdef. */ + if (upb_fielddef_containingtype(f) != NULL && + upb_fielddef_containingtype(f) != o->parent) { + upb_status_seterrmsg(s, "fielddef belongs to a different message " + "than oneof"); + return false; + } + } + + /* Commit phase. First add the field to our parent msgdef, if any, because + * that may fail; then add the field to our own tables. */ + + if (o->parent != NULL && upb_fielddef_containingtype(f) == NULL) { + if (!upb_msgdef_addfield((upb_msgdef*)o->parent, f, NULL, s)) { + return false; + } + } + + release_containingtype(f); + f->oneof = o; + upb_inttable_insert(&o->itof, upb_fielddef_number(f), upb_value_ptr(f)); + upb_strtable_insert(&o->ntof, upb_fielddef_name(f), upb_value_ptr(f)); + upb_ref2(f, o); + upb_ref2(o, f); + if (ref_donor) upb_fielddef_unref(f, ref_donor); + + return true; +} + +const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, + const char *name, size_t length) { + upb_value val; + return upb_strtable_lookup2(&o->ntof, name, length, &val) ? + upb_value_getptr(val) : NULL; +} + +const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num) { + upb_value val; + return upb_inttable_lookup32(&o->itof, num, &val) ? + upb_value_getptr(val) : NULL; +} + +void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o) { + upb_inttable_begin(iter, &o->itof); +} + +void upb_oneof_next(upb_oneof_iter *iter) { + upb_inttable_next(iter); +} + +bool upb_oneof_done(upb_oneof_iter *iter) { + return upb_inttable_done(iter); +} + +upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter) { + return (upb_fielddef*)upb_value_getptr(upb_inttable_iter_value(iter)); +} + +void upb_oneof_iter_setdone(upb_oneof_iter *iter) { + upb_inttable_iter_setdone(iter); +} + + +#include +#include +#include + +typedef struct cleanup_ent { + upb_cleanup_func *cleanup; + void *ud; + struct cleanup_ent *next; +} cleanup_ent; + +static void *seeded_alloc(void *ud, void *ptr, size_t oldsize, size_t size); + +/* Default allocator **********************************************************/ + +/* Just use realloc, keeping all allocated blocks in a linked list to destroy at + * the end. */ + +typedef struct mem_block { + /* List is doubly-linked, because in cases where realloc() moves an existing + * block, we need to be able to remove the old pointer from the list + * efficiently. */ + struct mem_block *prev, *next; +#ifndef NDEBUG + size_t size; /* Doesn't include mem_block structure. */ +#endif +} mem_block; + +typedef struct { + mem_block *head; +} default_alloc_ud; + +static void *default_alloc(void *_ud, void *ptr, size_t oldsize, size_t size) { + default_alloc_ud *ud = _ud; + mem_block *from, *block; + void *ret; + UPB_UNUSED(oldsize); + + from = ptr ? (void*)((char*)ptr - sizeof(mem_block)) : NULL; + +#ifndef NDEBUG + if (from) { + assert(oldsize <= from->size); + } +#endif + + /* TODO(haberman): we probably need to provide even better alignment here, + * like 16-byte alignment of the returned data pointer. */ + block = realloc(from, size + sizeof(mem_block)); + if (!block) return NULL; + ret = (char*)block + sizeof(*block); + +#ifndef NDEBUG + block->size = size; +#endif + + if (from) { + if (block != from) { + /* The block was moved, so pointers in next and prev blocks must be + * updated to its new location. */ + if (block->next) block->next->prev = block; + if (block->prev) block->prev->next = block; + if (ud->head == from) ud->head = block; + } + } else { + /* Insert at head of linked list. */ + block->prev = NULL; + block->next = ud->head; + if (block->next) block->next->prev = block; + ud->head = block; + } + + return ret; +} + +static void default_alloc_cleanup(void *_ud) { + default_alloc_ud *ud = _ud; + mem_block *block = ud->head; + + while (block) { + void *to_free = block; + block = block->next; + free(to_free); + } +} + + +/* Standard error functions ***************************************************/ + +static bool default_err(void *ud, const upb_status *status) { + UPB_UNUSED(ud); + UPB_UNUSED(status); + return false; +} + +static bool write_err_to(void *ud, const upb_status *status) { + upb_status *copy_to = ud; + upb_status_copy(copy_to, status); + return false; +} + + +/* upb_env ********************************************************************/ + +void upb_env_init(upb_env *e) { + default_alloc_ud *ud = (default_alloc_ud*)&e->default_alloc_ud; + e->ok_ = true; + e->bytes_allocated = 0; + e->cleanup_head = NULL; + + ud->head = NULL; + + /* Set default functions. */ + upb_env_setallocfunc(e, default_alloc, ud); + upb_env_seterrorfunc(e, default_err, NULL); +} + +void upb_env_uninit(upb_env *e) { + cleanup_ent *ent = e->cleanup_head; + + while (ent) { + ent->cleanup(ent->ud); + ent = ent->next; + } + + /* Must do this after running cleanup functions, because this will delete + the memory we store our cleanup entries in! */ + if (e->alloc == default_alloc) { + default_alloc_cleanup(e->alloc_ud); + } +} + +UPB_FORCEINLINE void upb_env_setallocfunc(upb_env *e, upb_alloc_func *alloc, + void *ud) { + e->alloc = alloc; + e->alloc_ud = ud; +} + +UPB_FORCEINLINE void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, + void *ud) { + e->err = func; + e->err_ud = ud; +} + +void upb_env_reporterrorsto(upb_env *e, upb_status *status) { + e->err = write_err_to; + e->err_ud = status; +} + +bool upb_env_ok(const upb_env *e) { + return e->ok_; +} + +bool upb_env_reporterror(upb_env *e, const upb_status *status) { + e->ok_ = false; + return e->err(e->err_ud, status); +} + +bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud) { + cleanup_ent *ent = upb_env_malloc(e, sizeof(cleanup_ent)); + if (!ent) return false; + + ent->cleanup = func; + ent->ud = ud; + ent->next = e->cleanup_head; + e->cleanup_head = ent; + + return true; +} + +void *upb_env_malloc(upb_env *e, size_t size) { + e->bytes_allocated += size; + if (e->alloc == seeded_alloc) { + /* This is equivalent to the next branch, but allows inlining for a + * measurable perf benefit. */ + return seeded_alloc(e->alloc_ud, NULL, 0, size); + } else { + return e->alloc(e->alloc_ud, NULL, 0, size); + } +} + +void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size) { + char *ret; + assert(oldsize <= size); + ret = e->alloc(e->alloc_ud, ptr, oldsize, size); + +#ifndef NDEBUG + /* Overwrite non-preserved memory to ensure callers are passing the oldsize + * that they truly require. */ + memset(ret + oldsize, 0xff, size - oldsize); +#endif + + return ret; +} + +size_t upb_env_bytesallocated(const upb_env *e) { + return e->bytes_allocated; +} + + +/* upb_seededalloc ************************************************************/ + +/* Be conservative and choose 16 in case anyone is using SSE. */ +static const size_t maxalign = 16; + +static size_t align_up(size_t size) { + return ((size + maxalign - 1) / maxalign) * maxalign; +} + +UPB_FORCEINLINE static void *seeded_alloc(void *ud, void *ptr, size_t oldsize, + size_t size) { + upb_seededalloc *a = ud; + + size = align_up(size); + + assert(a->mem_limit >= a->mem_ptr); + + if (oldsize == 0 && size <= (size_t)(a->mem_limit - a->mem_ptr)) { + /* Fast path: we can satisfy from the initial allocation. */ + void *ret = a->mem_ptr; + a->mem_ptr += size; + return ret; + } else { + char *chptr = ptr; + /* Slow path: fallback to other allocator. */ + a->need_cleanup = true; + /* Is `ptr` part of the user-provided initial block? Don't pass it to the + * default allocator if so; otherwise, it may try to realloc() the block. */ + if (chptr >= a->mem_base && chptr < a->mem_limit) { + void *ret; + assert(chptr + oldsize <= a->mem_limit); + ret = a->alloc(a->alloc_ud, NULL, 0, size); + if (ret) memcpy(ret, ptr, oldsize); + return ret; + } else { + return a->alloc(a->alloc_ud, ptr, oldsize, size); + } + } +} + +void upb_seededalloc_init(upb_seededalloc *a, void *mem, size_t len) { + default_alloc_ud *ud = (default_alloc_ud*)&a->default_alloc_ud; + a->mem_base = mem; + a->mem_ptr = mem; + a->mem_limit = (char*)mem + len; + a->need_cleanup = false; + a->returned_allocfunc = false; + + ud->head = NULL; + + upb_seededalloc_setfallbackalloc(a, default_alloc, ud); +} + +void upb_seededalloc_uninit(upb_seededalloc *a) { + if (a->alloc == default_alloc && a->need_cleanup) { + default_alloc_cleanup(a->alloc_ud); + } +} + +UPB_FORCEINLINE void upb_seededalloc_setfallbackalloc(upb_seededalloc *a, + upb_alloc_func *alloc, + void *ud) { + assert(!a->returned_allocfunc); + a->alloc = alloc; + a->alloc_ud = ud; +} + +upb_alloc_func *upb_seededalloc_getallocfunc(upb_seededalloc *a) { + a->returned_allocfunc = true; + return seeded_alloc; +} +/* +** TODO(haberman): it's unclear whether a lot of the consistency checks should +** assert() or return false. +*/ + + +#include +#include + + + +/* Defined for the sole purpose of having a unique pointer value for + * UPB_NO_CLOSURE. */ +char _upb_noclosure; + +static void freehandlers(upb_refcounted *r) { + upb_handlers *h = (upb_handlers*)r; + + upb_inttable_iter i; + upb_inttable_begin(&i, &h->cleanup_); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + void *val = (void*)upb_inttable_iter_key(&i); + upb_value func_val = upb_inttable_iter_value(&i); + upb_handlerfree *func = upb_value_getfptr(func_val); + func(val); + } + + upb_inttable_uninit(&h->cleanup_); + upb_msgdef_unref(h->msg, h); + free(h->sub); + free(h); +} + +static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const upb_handlers *h = (const upb_handlers*)r; + upb_msg_field_iter i; + for(upb_msg_field_begin(&i, h->msg); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + upb_fielddef *f = upb_msg_iter_field(&i); + const upb_handlers *sub; + if (!upb_fielddef_issubmsg(f)) continue; + sub = upb_handlers_getsubhandlers(h, f); + if (sub) visit(r, upb_handlers_upcast(sub), closure); + } +} + +static const struct upb_refcounted_vtbl vtbl = {visithandlers, freehandlers}; + +typedef struct { + upb_inttable tab; /* maps upb_msgdef* -> upb_handlers*. */ + upb_handlers_callback *callback; + const void *closure; +} dfs_state; + +/* TODO(haberman): discard upb_handlers* objects that do not actually have any + * handlers set and cannot reach any upb_handlers* object that does. This is + * slightly tricky to do correctly. */ +static upb_handlers *newformsg(const upb_msgdef *m, const void *owner, + dfs_state *s) { + upb_msg_field_iter i; + upb_handlers *h = upb_handlers_new(m, owner); + if (!h) return NULL; + if (!upb_inttable_insertptr(&s->tab, m, upb_value_ptr(h))) goto oom; + + s->callback(s->closure, h); + + /* For each submessage field, get or create a handlers object and set it as + * the subhandlers. */ + for(upb_msg_field_begin(&i, m); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + upb_fielddef *f = upb_msg_iter_field(&i); + const upb_msgdef *subdef; + upb_value subm_ent; + + if (!upb_fielddef_issubmsg(f)) continue; + + subdef = upb_downcast_msgdef(upb_fielddef_subdef(f)); + if (upb_inttable_lookupptr(&s->tab, subdef, &subm_ent)) { + upb_handlers_setsubhandlers(h, f, upb_value_getptr(subm_ent)); + } else { + upb_handlers *sub_mh = newformsg(subdef, &sub_mh, s); + if (!sub_mh) goto oom; + upb_handlers_setsubhandlers(h, f, sub_mh); + upb_handlers_unref(sub_mh, &sub_mh); + } + } + return h; + +oom: + upb_handlers_unref(h, owner); + return NULL; +} + +/* Given a selector for a STARTSUBMSG handler, resolves to a pointer to the + * subhandlers for this submessage field. */ +#define SUBH(h, selector) (h->sub[selector]) + +/* The selector for a submessage field is the field index. */ +#define SUBH_F(h, f) SUBH(h, f->index_) + +static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + upb_selector_t sel; + assert(!upb_handlers_isfrozen(h)); + if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) { + upb_status_seterrf( + &h->status_, "type mismatch: field %s does not belong to message %s", + upb_fielddef_name(f), upb_msgdef_fullname(upb_handlers_msgdef(h))); + return -1; + } + if (!upb_handlers_getselector(f, type, &sel)) { + upb_status_seterrf( + &h->status_, + "type mismatch: cannot register handler type %d for field %s", + type, upb_fielddef_name(f)); + return -1; + } + return sel; +} + +static upb_selector_t handlers_getsel(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + int32_t sel = trygetsel(h, f, type); + assert(sel >= 0); + return sel; +} + +static const void **returntype(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + return &h->table[handlers_getsel(h, f, type)].attr.return_closure_type_; +} + +static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f, + upb_handlertype_t type, upb_func *func, + upb_handlerattr *attr) { + upb_handlerattr set_attr = UPB_HANDLERATTR_INITIALIZER; + const void *closure_type; + const void **context_closure_type; + + assert(!upb_handlers_isfrozen(h)); + + if (sel < 0) { + upb_status_seterrmsg(&h->status_, + "incorrect handler type for this field."); + return false; + } + + if (h->table[sel].func) { + upb_status_seterrmsg(&h->status_, + "cannot change handler once it has been set."); + return false; + } + + if (attr) { + set_attr = *attr; + } + + /* Check that the given closure type matches the closure type that has been + * established for this context (if any). */ + closure_type = upb_handlerattr_closuretype(&set_attr); + + if (type == UPB_HANDLER_STRING) { + context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR); + } else if (f && upb_fielddef_isseq(f) && + type != UPB_HANDLER_STARTSEQ && + type != UPB_HANDLER_ENDSEQ) { + context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ); + } else { + context_closure_type = &h->top_closure_type; + } + + if (closure_type && *context_closure_type && + closure_type != *context_closure_type) { + /* TODO(haberman): better message for debugging. */ + if (f) { + upb_status_seterrf(&h->status_, + "closure type does not match for field %s", + upb_fielddef_name(f)); + } else { + upb_status_seterrmsg( + &h->status_, "closure type does not match for message-level handler"); + } + return false; + } + + if (closure_type) + *context_closure_type = closure_type; + + /* If this is a STARTSEQ or STARTSTR handler, check that the returned pointer + * matches any pre-existing expectations about what type is expected. */ + if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) { + const void *return_type = upb_handlerattr_returnclosuretype(&set_attr); + const void *table_return_type = + upb_handlerattr_returnclosuretype(&h->table[sel].attr); + if (return_type && table_return_type && return_type != table_return_type) { + upb_status_seterrmsg(&h->status_, "closure return type does not match"); + return false; + } + + if (table_return_type && !return_type) + upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type); + } + + h->table[sel].func = (upb_func*)func; + h->table[sel].attr = set_attr; + return true; +} + +/* Returns the effective closure type for this handler (which will propagate + * from outer frames if this frame has no START* handler). Not implemented for + * UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is + * the effective closure type is unspecified (either no handler was registered + * to specify it or the handler that was registered did not specify the closure + * type). */ +const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + const void *ret; + upb_selector_t sel; + + assert(type != UPB_HANDLER_STRING); + ret = h->top_closure_type; + + if (upb_fielddef_isseq(f) && + type != UPB_HANDLER_STARTSEQ && + type != UPB_HANDLER_ENDSEQ && + h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)].func) { + ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + } + + if (type == UPB_HANDLER_STRING && + h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSTR)].func) { + ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + } + + /* The effective type of the submessage; not used yet. + * if (type == SUBMESSAGE && + * h->table[sel = handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) { + * ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + * } */ + + return ret; +} + +/* Checks whether the START* handler specified by f & type is missing even + * though it is required to convert the established type of an outer frame + * ("closure_type") into the established type of an inner frame (represented in + * the return closure type of this handler's attr. */ +bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type, + upb_status *status) { + const void *closure_type; + const upb_handlerattr *attr; + const void *return_closure_type; + + upb_selector_t sel = handlers_getsel(h, f, type); + if (h->table[sel].func) return true; + closure_type = effective_closure_type(h, f, type); + attr = &h->table[sel].attr; + return_closure_type = upb_handlerattr_returnclosuretype(attr); + if (closure_type && return_closure_type && + closure_type != return_closure_type) { + upb_status_seterrf(status, + "expected start handler to return sub type for field %f", + upb_fielddef_name(f)); + return false; + } + return true; +} + +/* Public interface ***********************************************************/ + +upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) { + int extra; + upb_handlers *h; + + assert(upb_msgdef_isfrozen(md)); + + extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1); + h = calloc(sizeof(*h) + extra, 1); + if (!h) return NULL; + + h->msg = md; + upb_msgdef_ref(h->msg, h); + upb_status_clear(&h->status_); + h->sub = calloc(md->submsg_field_count, sizeof(*h->sub)); + if (!h->sub) goto oom; + if (!upb_refcounted_init(upb_handlers_upcast_mutable(h), &vtbl, owner)) + goto oom; + if (!upb_inttable_init(&h->cleanup_, UPB_CTYPE_FPTR)) goto oom; + + /* calloc() above initialized all handlers to NULL. */ + return h; + +oom: + freehandlers(upb_handlers_upcast_mutable(h)); + return NULL; +} + +const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, + const void *owner, + upb_handlers_callback *callback, + const void *closure) { + dfs_state state; + upb_handlers *ret; + bool ok; + upb_refcounted *r; + + state.callback = callback; + state.closure = closure; + if (!upb_inttable_init(&state.tab, UPB_CTYPE_PTR)) return NULL; + + ret = newformsg(m, owner, &state); + + upb_inttable_uninit(&state.tab); + if (!ret) return NULL; + + r = upb_handlers_upcast_mutable(ret); + ok = upb_refcounted_freeze(&r, 1, NULL, UPB_MAX_HANDLER_DEPTH); + UPB_ASSERT_VAR(ok, ok); + + return ret; +} + +const upb_status *upb_handlers_status(upb_handlers *h) { + assert(!upb_handlers_isfrozen(h)); + return &h->status_; +} + +void upb_handlers_clearerr(upb_handlers *h) { + assert(!upb_handlers_isfrozen(h)); + upb_status_clear(&h->status_); +} + +#define SETTER(name, handlerctype, handlertype) \ + bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \ + handlerctype func, upb_handlerattr *attr) { \ + int32_t sel = trygetsel(h, f, handlertype); \ + return doset(h, sel, f, handlertype, (upb_func*)func, attr); \ + } + +SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32) +SETTER(int64, upb_int64_handlerfunc*, UPB_HANDLER_INT64) +SETTER(uint32, upb_uint32_handlerfunc*, UPB_HANDLER_UINT32) +SETTER(uint64, upb_uint64_handlerfunc*, UPB_HANDLER_UINT64) +SETTER(float, upb_float_handlerfunc*, UPB_HANDLER_FLOAT) +SETTER(double, upb_double_handlerfunc*, UPB_HANDLER_DOUBLE) +SETTER(bool, upb_bool_handlerfunc*, UPB_HANDLER_BOOL) +SETTER(startstr, upb_startstr_handlerfunc*, UPB_HANDLER_STARTSTR) +SETTER(string, upb_string_handlerfunc*, UPB_HANDLER_STRING) +SETTER(endstr, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSTR) +SETTER(startseq, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSEQ) +SETTER(startsubmsg, upb_startfield_handlerfunc*, UPB_HANDLER_STARTSUBMSG) +SETTER(endsubmsg, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSUBMSG) +SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ) + +#undef SETTER + +bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, + upb_handlerattr *attr) { + return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32, + (upb_func *)func, attr); +} + +bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, + upb_handlerattr *attr) { + assert(!upb_handlers_isfrozen(h)); + return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32, + (upb_func *)func, attr); +} + +bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, + const upb_handlers *sub) { + assert(sub); + assert(!upb_handlers_isfrozen(h)); + assert(upb_fielddef_issubmsg(f)); + if (SUBH_F(h, f)) return false; /* Can't reset. */ + if (upb_msgdef_upcast(upb_handlers_msgdef(sub)) != upb_fielddef_subdef(f)) { + return false; + } + SUBH_F(h, f) = sub; + upb_ref2(sub, h); + return true; +} + +const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, + const upb_fielddef *f) { + assert(upb_fielddef_issubmsg(f)); + return SUBH_F(h, f); +} + +bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel, + upb_handlerattr *attr) { + if (!upb_handlers_gethandler(h, sel)) + return false; + *attr = h->table[sel].attr; + return true; +} + +const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, + upb_selector_t sel) { + /* STARTSUBMSG selector in sel is the field's selector base. */ + return SUBH(h, sel - UPB_STATIC_SELECTOR_COUNT); +} + +const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } + +bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *func) { + bool ok; + if (upb_inttable_lookupptr(&h->cleanup_, p, NULL)) { + return false; + } + ok = upb_inttable_insertptr(&h->cleanup_, p, upb_value_fptr(func)); + UPB_ASSERT_VAR(ok, ok); + return true; +} + + +/* "Static" methods ***********************************************************/ + +bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { + /* TODO: verify we have a transitive closure. */ + int i; + for (i = 0; i < n; i++) { + upb_msg_field_iter j; + upb_handlers *h = handlers[i]; + + if (!upb_ok(&h->status_)) { + upb_status_seterrf(s, "handlers for message %s had error status: %s", + upb_msgdef_fullname(upb_handlers_msgdef(h)), + upb_status_errmsg(&h->status_)); + return false; + } + + /* Check that there are no closure mismatches due to missing Start* handlers + * or subhandlers with different type-level types. */ + for(upb_msg_field_begin(&j, h->msg); + !upb_msg_field_done(&j); + upb_msg_field_next(&j)) { + + const upb_fielddef *f = upb_msg_iter_field(&j); + if (upb_fielddef_isseq(f)) { + if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s)) + return false; + } + + if (upb_fielddef_isstring(f)) { + if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s)) + return false; + } + + if (upb_fielddef_issubmsg(f)) { + bool hashandler = false; + if (upb_handlers_gethandler( + h, handlers_getsel(h, f, UPB_HANDLER_STARTSUBMSG)) || + upb_handlers_gethandler( + h, handlers_getsel(h, f, UPB_HANDLER_ENDSUBMSG))) { + hashandler = true; + } + + if (upb_fielddef_isseq(f) && + (upb_handlers_gethandler( + h, handlers_getsel(h, f, UPB_HANDLER_STARTSEQ)) || + upb_handlers_gethandler( + h, handlers_getsel(h, f, UPB_HANDLER_ENDSEQ)))) { + hashandler = true; + } + + if (hashandler && !upb_handlers_getsubhandlers(h, f)) { + /* For now we add an empty subhandlers in this case. It makes the + * decoder code generator simpler, because it only has to handle two + * cases (submessage has handlers or not) as opposed to three + * (submessage has handlers in enclosing message but no subhandlers). + * + * This makes parsing less efficient in the case that we want to + * notice a submessage but skip its contents (like if we're testing + * for submessage presence or counting the number of repeated + * submessages). In this case we will end up parsing the submessage + * field by field and throwing away the results for each, instead of + * skipping the whole delimited thing at once. If this is an issue we + * can revisit it, but do remember that this only arises when you have + * handlers (startseq/startsubmsg/endsubmsg/endseq) set for the + * submessage but no subhandlers. The uses cases for this are + * limited. */ + upb_handlers *sub = upb_handlers_new(upb_fielddef_msgsubdef(f), &sub); + upb_handlers_setsubhandlers(h, f, sub); + upb_handlers_unref(sub, &sub); + } + + /* TODO(haberman): check type of submessage. + * This is slightly tricky; also consider whether we should check that + * they match at setsubhandlers time. */ + } + } + } + + if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s, + UPB_MAX_HANDLER_DEPTH)) { + return false; + } + + return true; +} + +upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f) { + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_ENUM: return UPB_HANDLER_INT32; + case UPB_TYPE_INT64: return UPB_HANDLER_INT64; + case UPB_TYPE_UINT32: return UPB_HANDLER_UINT32; + case UPB_TYPE_UINT64: return UPB_HANDLER_UINT64; + case UPB_TYPE_FLOAT: return UPB_HANDLER_FLOAT; + case UPB_TYPE_DOUBLE: return UPB_HANDLER_DOUBLE; + case UPB_TYPE_BOOL: return UPB_HANDLER_BOOL; + default: assert(false); return -1; /* Invalid input. */ + } +} + +bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, + upb_selector_t *s) { + switch (type) { + case UPB_HANDLER_INT32: + case UPB_HANDLER_INT64: + case UPB_HANDLER_UINT32: + case UPB_HANDLER_UINT64: + case UPB_HANDLER_FLOAT: + case UPB_HANDLER_DOUBLE: + case UPB_HANDLER_BOOL: + if (!upb_fielddef_isprimitive(f) || + upb_handlers_getprimitivehandlertype(f) != type) + return false; + *s = f->selector_base; + break; + case UPB_HANDLER_STRING: + if (upb_fielddef_isstring(f)) { + *s = f->selector_base; + } else if (upb_fielddef_lazy(f)) { + *s = f->selector_base + 3; + } else { + return false; + } + break; + case UPB_HANDLER_STARTSTR: + if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) { + *s = f->selector_base + 1; + } else { + return false; + } + break; + case UPB_HANDLER_ENDSTR: + if (upb_fielddef_isstring(f) || upb_fielddef_lazy(f)) { + *s = f->selector_base + 2; + } else { + return false; + } + break; + case UPB_HANDLER_STARTSEQ: + if (!upb_fielddef_isseq(f)) return false; + *s = f->selector_base - 2; + break; + case UPB_HANDLER_ENDSEQ: + if (!upb_fielddef_isseq(f)) return false; + *s = f->selector_base - 1; + break; + case UPB_HANDLER_STARTSUBMSG: + if (!upb_fielddef_issubmsg(f)) return false; + /* Selectors for STARTSUBMSG are at the beginning of the table so that the + * selector can also be used as an index into the "sub" array of + * subhandlers. The indexes for the two into these two tables are the + * same, except that in the handler table the static selectors come first. */ + *s = f->index_ + UPB_STATIC_SELECTOR_COUNT; + break; + case UPB_HANDLER_ENDSUBMSG: + if (!upb_fielddef_issubmsg(f)) return false; + *s = f->selector_base; + break; + } + assert((size_t)*s < upb_fielddef_containingtype(f)->selector_count); + return true; +} + +uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f) { + return upb_fielddef_isseq(f) ? 2 : 0; +} + +uint32_t upb_handlers_selectorcount(const upb_fielddef *f) { + uint32_t ret = 1; + if (upb_fielddef_isseq(f)) ret += 2; /* STARTSEQ/ENDSEQ */ + if (upb_fielddef_isstring(f)) ret += 2; /* [STRING]/STARTSTR/ENDSTR */ + if (upb_fielddef_issubmsg(f)) { + /* ENDSUBMSG (STARTSUBMSG is at table beginning) */ + ret += 0; + if (upb_fielddef_lazy(f)) { + /* STARTSTR/ENDSTR/STRING (for lazy) */ + ret += 3; + } + } + return ret; +} + + +/* upb_handlerattr ************************************************************/ + +void upb_handlerattr_init(upb_handlerattr *attr) { + upb_handlerattr from = UPB_HANDLERATTR_INITIALIZER; + memcpy(attr, &from, sizeof(*attr)); +} + +void upb_handlerattr_uninit(upb_handlerattr *attr) { + UPB_UNUSED(attr); +} + +bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd) { + attr->handler_data_ = hd; + return true; +} + +bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) { + attr->closure_type_ = type; + return true; +} + +const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) { + return attr->closure_type_; +} + +bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, + const void *type) { + attr->return_closure_type_ = type; + return true; +} + +const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) { + return attr->return_closure_type_; +} + +bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) { + attr->alwaysok_ = alwaysok; + return true; +} + +bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) { + return attr->alwaysok_; +} + +/* upb_bufhandle **************************************************************/ + +size_t upb_bufhandle_objofs(const upb_bufhandle *h) { + return h->objofs_; +} + +/* upb_byteshandler ***********************************************************/ + +void upb_byteshandler_init(upb_byteshandler* h) { + memset(h, 0, sizeof(*h)); +} + +/* For when we support handlerfree callbacks. */ +void upb_byteshandler_uninit(upb_byteshandler* h) { + UPB_UNUSED(h); +} + +bool upb_byteshandler_setstartstr(upb_byteshandler *h, + upb_startstr_handlerfunc *func, void *d) { + h->table[UPB_STARTSTR_SELECTOR].func = (upb_func*)func; + h->table[UPB_STARTSTR_SELECTOR].attr.handler_data_ = d; + return true; +} + +bool upb_byteshandler_setstring(upb_byteshandler *h, + upb_string_handlerfunc *func, void *d) { + h->table[UPB_STRING_SELECTOR].func = (upb_func*)func; + h->table[UPB_STRING_SELECTOR].attr.handler_data_ = d; + return true; +} + +bool upb_byteshandler_setendstr(upb_byteshandler *h, + upb_endfield_handlerfunc *func, void *d) { + h->table[UPB_ENDSTR_SELECTOR].func = (upb_func*)func; + h->table[UPB_ENDSTR_SELECTOR].attr.handler_data_ = d; + return true; +} +/* +** upb::RefCounted Implementation +** +** Our key invariants are: +** 1. reference cycles never span groups +** 2. for ref2(to, from), we increment to's count iff group(from) != group(to) +** +** The previous two are how we avoid leaking cycles. Other important +** invariants are: +** 3. for mutable objects "from" and "to", if there exists a ref2(to, from) +** this implies group(from) == group(to). (In practice, what we implement +** is even stronger; "from" and "to" will share a group if there has *ever* +** been a ref2(to, from), but all that is necessary for correctness is the +** weaker one). +** 4. mutable and immutable objects are never in the same group. +*/ + + +#include +#include + +static void freeobj(upb_refcounted *o); + +const char untracked_val; +const void *UPB_UNTRACKED_REF = &untracked_val; + +/* arch-specific atomic primitives *******************************************/ + +#ifdef UPB_THREAD_UNSAFE /*---------------------------------------------------*/ + +static void atomic_inc(uint32_t *a) { (*a)++; } +static bool atomic_dec(uint32_t *a) { return --(*a) == 0; } + +#elif defined(__GNUC__) || defined(__clang__) /*------------------------------*/ + +static void atomic_inc(uint32_t *a) { __sync_fetch_and_add(a, 1); } +static bool atomic_dec(uint32_t *a) { return __sync_sub_and_fetch(a, 1) == 0; } + +#elif defined(WIN32) /*-------------------------------------------------------*/ + +#include + +static void atomic_inc(upb_atomic_t *a) { InterlockedIncrement(&a->val); } +static bool atomic_dec(upb_atomic_t *a) { + return InterlockedDecrement(&a->val) == 0; +} + +#else +#error Atomic primitives not defined for your platform/CPU. \ + Implement them or compile with UPB_THREAD_UNSAFE. +#endif + +/* All static objects point to this refcount. + * It is special-cased in ref/unref below. */ +uint32_t static_refcount = -1; + +/* We can avoid atomic ops for statically-declared objects. + * This is a minor optimization but nice since we can avoid degrading under + * contention in this case. */ + +static void refgroup(uint32_t *group) { + if (group != &static_refcount) + atomic_inc(group); +} + +static bool unrefgroup(uint32_t *group) { + if (group == &static_refcount) { + return false; + } else { + return atomic_dec(group); + } +} + + +/* Reference tracking (debug only) ********************************************/ + +#ifdef UPB_DEBUG_REFS + +#ifdef UPB_THREAD_UNSAFE + +static void upb_lock() {} +static void upb_unlock() {} + +#else + +/* User must define functions that lock/unlock a global mutex and link this + * file against them. */ +void upb_lock(); +void upb_unlock(); + +#endif + +/* UPB_DEBUG_REFS mode counts on being able to malloc() memory in some + * code-paths that can normally never fail, like upb_refcounted_ref(). Since + * we have no way to propagage out-of-memory errors back to the user, and since + * these errors can only occur in UPB_DEBUG_REFS mode, we immediately fail. */ +#define CHECK_OOM(predicate) if (!(predicate)) { assert(predicate); exit(1); } + +typedef struct { + int count; /* How many refs there are (duplicates only allowed for ref2). */ + bool is_ref2; +} trackedref; + +static trackedref *trackedref_new(bool is_ref2) { + trackedref *ret = malloc(sizeof(*ret)); + CHECK_OOM(ret); + ret->count = 1; + ret->is_ref2 = is_ref2; + return ret; +} + +static void track(const upb_refcounted *r, const void *owner, bool ref2) { + upb_value v; + + assert(owner); + if (owner == UPB_UNTRACKED_REF) return; + + upb_lock(); + if (upb_inttable_lookupptr(r->refs, owner, &v)) { + trackedref *ref = upb_value_getptr(v); + /* Since we allow multiple ref2's for the same to/from pair without + * allocating separate memory for each one, we lose the fine-grained + * tracking behavior we get with regular refs. Since ref2s only happen + * inside upb, we'll accept this limitation until/unless there is a really + * difficult upb-internal bug that can't be figured out without it. */ + assert(ref2); + assert(ref->is_ref2); + ref->count++; + } else { + trackedref *ref = trackedref_new(ref2); + bool ok = upb_inttable_insertptr(r->refs, owner, upb_value_ptr(ref)); + CHECK_OOM(ok); + if (ref2) { + /* We know this cast is safe when it is a ref2, because it's coming from + * another refcounted object. */ + const upb_refcounted *from = owner; + assert(!upb_inttable_lookupptr(from->ref2s, r, NULL)); + ok = upb_inttable_insertptr(from->ref2s, r, upb_value_ptr(NULL)); + CHECK_OOM(ok); + } + } + upb_unlock(); +} + +static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { + upb_value v; + bool found; + trackedref *ref; + + assert(owner); + if (owner == UPB_UNTRACKED_REF) return; + + upb_lock(); + found = upb_inttable_lookupptr(r->refs, owner, &v); + /* This assert will fail if an owner attempts to release a ref it didn't have. */ + UPB_ASSERT_VAR(found, found); + ref = upb_value_getptr(v); + assert(ref->is_ref2 == ref2); + if (--ref->count == 0) { + free(ref); + upb_inttable_removeptr(r->refs, owner, NULL); + if (ref2) { + /* We know this cast is safe when it is a ref2, because it's coming from + * another refcounted object. */ + const upb_refcounted *from = owner; + bool removed = upb_inttable_removeptr(from->ref2s, r, NULL); + assert(removed); + } + } + upb_unlock(); +} + +static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { + upb_value v; + bool found; + trackedref *ref; + + upb_lock(); + found = upb_inttable_lookupptr(r->refs, owner, &v); + UPB_ASSERT_VAR(found, found); + ref = upb_value_getptr(v); + assert(ref->is_ref2 == ref2); + upb_unlock(); +} + +/* Populates the given UPB_CTYPE_INT32 inttable with counts of ref2's that + * originate from the given owner. */ +static void getref2s(const upb_refcounted *owner, upb_inttable *tab) { + upb_inttable_iter i; + + upb_lock(); + upb_inttable_begin(&i, owner->ref2s); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_value v; + upb_value count; + trackedref *ref; + bool ok; + bool found; + + upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i); + + /* To get the count we need to look in the target's table. */ + found = upb_inttable_lookupptr(to->refs, owner, &v); + assert(found); + ref = upb_value_getptr(v); + count = upb_value_int32(ref->count); + + ok = upb_inttable_insertptr(tab, to, count); + CHECK_OOM(ok); + } + upb_unlock(); +} + +typedef struct { + upb_inttable ref2; + const upb_refcounted *obj; +} check_state; + +static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj, + void *closure) { + check_state *s = closure; + upb_inttable *ref2 = &s->ref2; + upb_value v; + bool removed; + int32_t newcount; + + assert(obj == s->obj); + assert(subobj); + removed = upb_inttable_removeptr(ref2, subobj, &v); + /* The following assertion will fail if the visit() function visits a subobj + * that it did not have a ref2 on, or visits the same subobj too many times. */ + assert(removed); + newcount = upb_value_getint32(v) - 1; + if (newcount > 0) { + upb_inttable_insert(ref2, (uintptr_t)subobj, upb_value_int32(newcount)); + } +} + +static void visit(const upb_refcounted *r, upb_refcounted_visit *v, + void *closure) { + bool ok; + + /* In DEBUG_REFS mode we know what existing ref2 refs there are, so we know + * exactly the set of nodes that visit() should visit. So we verify visit()'s + * correctness here. */ + check_state state; + state.obj = r; + ok = upb_inttable_init(&state.ref2, UPB_CTYPE_INT32); + CHECK_OOM(ok); + getref2s(r, &state.ref2); + + /* This should visit any children in the ref2 table. */ + if (r->vtbl->visit) r->vtbl->visit(r, visit_check, &state); + + /* This assertion will fail if the visit() function missed any children. */ + assert(upb_inttable_count(&state.ref2) == 0); + upb_inttable_uninit(&state.ref2); + if (r->vtbl->visit) r->vtbl->visit(r, v, closure); +} + +static bool trackinit(upb_refcounted *r) { + r->refs = malloc(sizeof(*r->refs)); + r->ref2s = malloc(sizeof(*r->ref2s)); + if (!r->refs || !r->ref2s) goto err1; + + if (!upb_inttable_init(r->refs, UPB_CTYPE_PTR)) goto err1; + if (!upb_inttable_init(r->ref2s, UPB_CTYPE_PTR)) goto err2; + return true; + +err2: + upb_inttable_uninit(r->refs); +err1: + free(r->refs); + free(r->ref2s); + return false; +} + +static void trackfree(const upb_refcounted *r) { + upb_inttable_uninit(r->refs); + upb_inttable_uninit(r->ref2s); + free(r->refs); + free(r->ref2s); +} + +#else + +static void track(const upb_refcounted *r, const void *owner, bool ref2) { + UPB_UNUSED(r); + UPB_UNUSED(owner); + UPB_UNUSED(ref2); +} + +static void untrack(const upb_refcounted *r, const void *owner, bool ref2) { + UPB_UNUSED(r); + UPB_UNUSED(owner); + UPB_UNUSED(ref2); +} + +static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { + UPB_UNUSED(r); + UPB_UNUSED(owner); + UPB_UNUSED(ref2); +} + +static bool trackinit(upb_refcounted *r) { + UPB_UNUSED(r); + return true; +} + +static void trackfree(const upb_refcounted *r) { + UPB_UNUSED(r); +} + +static void visit(const upb_refcounted *r, upb_refcounted_visit *v, + void *closure) { + if (r->vtbl->visit) r->vtbl->visit(r, v, closure); +} + +#endif /* UPB_DEBUG_REFS */ + + +/* freeze() *******************************************************************/ + +/* The freeze() operation is by far the most complicated part of this scheme. + * We compute strongly-connected components and then mutate the graph such that + * we preserve the invariants documented at the top of this file. And we must + * handle out-of-memory errors gracefully (without leaving the graph + * inconsistent), which adds to the fun. */ + +/* The state used by the freeze operation (shared across many functions). */ +typedef struct { + int depth; + int maxdepth; + uint64_t index; + /* Maps upb_refcounted* -> attributes (color, etc). attr layout varies by + * color. */ + upb_inttable objattr; + upb_inttable stack; /* stack of upb_refcounted* for Tarjan's algorithm. */ + upb_inttable groups; /* array of uint32_t*, malloc'd refcounts for new groups */ + upb_status *status; + jmp_buf err; +} tarjan; + +static void release_ref2(const upb_refcounted *obj, + const upb_refcounted *subobj, + void *closure); + +/* Node attributes -----------------------------------------------------------*/ + +/* After our analysis phase all nodes will be either GRAY or WHITE. */ + +typedef enum { + BLACK = 0, /* Object has not been seen. */ + GRAY, /* Object has been found via a refgroup but may not be reachable. */ + GREEN, /* Object is reachable and is currently on the Tarjan stack. */ + WHITE /* Object is reachable and has been assigned a group (SCC). */ +} color_t; + +UPB_NORETURN static void err(tarjan *t) { longjmp(t->err, 1); } +UPB_NORETURN static void oom(tarjan *t) { + upb_status_seterrmsg(t->status, "out of memory"); + err(t); +} + +static uint64_t trygetattr(const tarjan *t, const upb_refcounted *r) { + upb_value v; + return upb_inttable_lookupptr(&t->objattr, r, &v) ? + upb_value_getuint64(v) : 0; +} + +static uint64_t getattr(const tarjan *t, const upb_refcounted *r) { + upb_value v; + bool found = upb_inttable_lookupptr(&t->objattr, r, &v); + UPB_ASSERT_VAR(found, found); + return upb_value_getuint64(v); +} + +static void setattr(tarjan *t, const upb_refcounted *r, uint64_t attr) { + upb_inttable_removeptr(&t->objattr, r, NULL); + upb_inttable_insertptr(&t->objattr, r, upb_value_uint64(attr)); +} + +static color_t color(tarjan *t, const upb_refcounted *r) { + return trygetattr(t, r) & 0x3; /* Color is always stored in the low 2 bits. */ +} + +static void set_gray(tarjan *t, const upb_refcounted *r) { + assert(color(t, r) == BLACK); + setattr(t, r, GRAY); +} + +/* Pushes an obj onto the Tarjan stack and sets it to GREEN. */ +static void push(tarjan *t, const upb_refcounted *r) { + assert(color(t, r) == BLACK || color(t, r) == GRAY); + /* This defines the attr layout for the GREEN state. "index" and "lowlink" + * get 31 bits, which is plenty (limit of 2B objects frozen at a time). */ + setattr(t, r, GREEN | (t->index << 2) | (t->index << 33)); + if (++t->index == 0x80000000) { + upb_status_seterrmsg(t->status, "too many objects to freeze"); + err(t); + } + upb_inttable_push(&t->stack, upb_value_ptr((void*)r)); +} + +/* Pops an obj from the Tarjan stack and sets it to WHITE, with a ptr to its + * SCC group. */ +static upb_refcounted *pop(tarjan *t) { + upb_refcounted *r = upb_value_getptr(upb_inttable_pop(&t->stack)); + assert(color(t, r) == GREEN); + /* This defines the attr layout for nodes in the WHITE state. + * Top of group stack is [group, NULL]; we point at group. */ + setattr(t, r, WHITE | (upb_inttable_count(&t->groups) - 2) << 8); + return r; +} + +static void tarjan_newgroup(tarjan *t) { + uint32_t *group = malloc(sizeof(*group)); + if (!group) oom(t); + /* Push group and empty group leader (we'll fill in leader later). */ + if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) || + !upb_inttable_push(&t->groups, upb_value_ptr(NULL))) { + free(group); + oom(t); + } + *group = 0; +} + +static uint32_t idx(tarjan *t, const upb_refcounted *r) { + assert(color(t, r) == GREEN); + return (getattr(t, r) >> 2) & 0x7FFFFFFF; +} + +static uint32_t lowlink(tarjan *t, const upb_refcounted *r) { + if (color(t, r) == GREEN) { + return getattr(t, r) >> 33; + } else { + return UINT32_MAX; + } +} + +static void set_lowlink(tarjan *t, const upb_refcounted *r, uint32_t lowlink) { + assert(color(t, r) == GREEN); + setattr(t, r, ((uint64_t)lowlink << 33) | (getattr(t, r) & 0x1FFFFFFFF)); +} + +static uint32_t *group(tarjan *t, upb_refcounted *r) { + uint64_t groupnum; + upb_value v; + bool found; + + assert(color(t, r) == WHITE); + groupnum = getattr(t, r) >> 8; + found = upb_inttable_lookup(&t->groups, groupnum, &v); + UPB_ASSERT_VAR(found, found); + return upb_value_getptr(v); +} + +/* If the group leader for this object's group has not previously been set, + * the given object is assigned to be its leader. */ +static upb_refcounted *groupleader(tarjan *t, upb_refcounted *r) { + uint64_t leader_slot; + upb_value v; + bool found; + + assert(color(t, r) == WHITE); + leader_slot = (getattr(t, r) >> 8) + 1; + found = upb_inttable_lookup(&t->groups, leader_slot, &v); + UPB_ASSERT_VAR(found, found); + if (upb_value_getptr(v)) { + return upb_value_getptr(v); + } else { + upb_inttable_remove(&t->groups, leader_slot, NULL); + upb_inttable_insert(&t->groups, leader_slot, upb_value_ptr(r)); + return r; + } +} + + +/* Tarjan's algorithm --------------------------------------------------------*/ + +/* See: + * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */ +static void do_tarjan(const upb_refcounted *obj, tarjan *t); + +static void tarjan_visit(const upb_refcounted *obj, + const upb_refcounted *subobj, + void *closure) { + tarjan *t = closure; + if (++t->depth > t->maxdepth) { + upb_status_seterrf(t->status, "graph too deep to freeze (%d)", t->maxdepth); + err(t); + } else if (subobj->is_frozen || color(t, subobj) == WHITE) { + /* Do nothing: we don't want to visit or color already-frozen nodes, + * and WHITE nodes have already been assigned a SCC. */ + } else if (color(t, subobj) < GREEN) { + /* Subdef has not yet been visited; recurse on it. */ + do_tarjan(subobj, t); + set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), lowlink(t, subobj))); + } else if (color(t, subobj) == GREEN) { + /* Subdef is in the stack and hence in the current SCC. */ + set_lowlink(t, obj, UPB_MIN(lowlink(t, obj), idx(t, subobj))); + } + --t->depth; +} + +static void do_tarjan(const upb_refcounted *obj, tarjan *t) { + if (color(t, obj) == BLACK) { + /* We haven't seen this object's group; mark the whole group GRAY. */ + const upb_refcounted *o = obj; + do { set_gray(t, o); } while ((o = o->next) != obj); + } + + push(t, obj); + visit(obj, tarjan_visit, t); + if (lowlink(t, obj) == idx(t, obj)) { + tarjan_newgroup(t); + while (pop(t) != obj) + ; + } +} + + +/* freeze() ------------------------------------------------------------------*/ + +static void crossref(const upb_refcounted *r, const upb_refcounted *subobj, + void *_t) { + tarjan *t = _t; + assert(color(t, r) > BLACK); + if (color(t, subobj) > BLACK && r->group != subobj->group) { + /* Previously this ref was not reflected in subobj->group because they + * were in the same group; now that they are split a ref must be taken. */ + refgroup(subobj->group); + } +} + +static bool freeze(upb_refcounted *const*roots, int n, upb_status *s, + int maxdepth) { + volatile bool ret = false; + int i; + upb_inttable_iter iter; + + /* We run in two passes so that we can allocate all memory before performing + * any mutation of the input -- this allows us to leave the input unchanged + * in the case of memory allocation failure. */ + tarjan t; + t.index = 0; + t.depth = 0; + t.maxdepth = maxdepth; + t.status = s; + if (!upb_inttable_init(&t.objattr, UPB_CTYPE_UINT64)) goto err1; + if (!upb_inttable_init(&t.stack, UPB_CTYPE_PTR)) goto err2; + if (!upb_inttable_init(&t.groups, UPB_CTYPE_PTR)) goto err3; + if (setjmp(t.err) != 0) goto err4; + + + for (i = 0; i < n; i++) { + if (color(&t, roots[i]) < GREEN) { + do_tarjan(roots[i], &t); + } + } + + /* If we've made it this far, no further errors are possible so it's safe to + * mutate the objects without risk of leaving them in an inconsistent state. */ + ret = true; + + /* The transformation that follows requires care. The preconditions are: + * - all objects in attr map are WHITE or GRAY, and are in mutable groups + * (groups of all mutable objs) + * - no ref2(to, from) refs have incremented count(to) if both "to" and + * "from" are in our attr map (this follows from invariants (2) and (3)) */ + + /* Pass 1: we remove WHITE objects from their mutable groups, and add them to + * new groups according to the SCC's we computed. These new groups will + * consist of only frozen objects. None will be immediately collectible, + * because WHITE objects are by definition reachable from one of "roots", + * which the caller must own refs on. */ + upb_inttable_begin(&iter, &t.objattr); + for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) { + upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter); + /* Since removal from a singly-linked list requires access to the object's + * predecessor, we consider obj->next instead of obj for moving. With the + * while() loop we guarantee that we will visit every node's predecessor. + * Proof: + * 1. every node's predecessor is in our attr map. + * 2. though the loop body may change a node's predecessor, it will only + * change it to be the node we are currently operating on, so with a + * while() loop we guarantee ourselves the chance to remove each node. */ + while (color(&t, obj->next) == WHITE && + group(&t, obj->next) != obj->next->group) { + upb_refcounted *leader; + + /* Remove from old group. */ + upb_refcounted *move = obj->next; + if (obj == move) { + /* Removing the last object from a group. */ + assert(*obj->group == obj->individual_count); + free(obj->group); + } else { + obj->next = move->next; + /* This may decrease to zero; we'll collect GRAY objects (if any) that + * remain in the group in the third pass. */ + assert(*move->group >= move->individual_count); + *move->group -= move->individual_count; + } + + /* Add to new group. */ + leader = groupleader(&t, move); + if (move == leader) { + /* First object added to new group is its leader. */ + move->group = group(&t, move); + move->next = move; + *move->group = move->individual_count; + } else { + /* Group already has at least one object in it. */ + assert(leader->group == group(&t, move)); + move->group = group(&t, move); + move->next = leader->next; + leader->next = move; + *move->group += move->individual_count; + } + + move->is_frozen = true; + } + } + + /* Pass 2: GRAY and WHITE objects "obj" with ref2(to, obj) references must + * increment count(to) if group(obj) != group(to) (which could now be the + * case if "to" was just frozen). */ + upb_inttable_begin(&iter, &t.objattr); + for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) { + upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter); + visit(obj, crossref, &t); + } + + /* Pass 3: GRAY objects are collected if their group's refcount dropped to + * zero when we removed its white nodes. This can happen if they had only + * been kept alive by virtue of sharing a group with an object that was just + * frozen. + * + * It is important that we do this last, since the GRAY object's free() + * function could call unref2() on just-frozen objects, which will decrement + * refs that were added in pass 2. */ + upb_inttable_begin(&iter, &t.objattr); + for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) { + upb_refcounted *obj = (upb_refcounted*)upb_inttable_iter_key(&iter); + if (obj->group == NULL || *obj->group == 0) { + if (obj->group) { + upb_refcounted *o; + + /* We eagerly free() the group's count (since we can't easily determine + * the group's remaining size it's the easiest way to ensure it gets + * done). */ + free(obj->group); + + /* Visit to release ref2's (done in a separate pass since release_ref2 + * depends on o->group being unmodified so it can test merged()). */ + o = obj; + do { visit(o, release_ref2, NULL); } while ((o = o->next) != obj); + + /* Mark "group" fields as NULL so we know to free the objects later in + * this loop, but also don't try to delete the group twice. */ + o = obj; + do { o->group = NULL; } while ((o = o->next) != obj); + } + freeobj(obj); + } + } + +err4: + if (!ret) { + upb_inttable_begin(&iter, &t.groups); + for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) + free(upb_value_getptr(upb_inttable_iter_value(&iter))); + } + upb_inttable_uninit(&t.groups); +err3: + upb_inttable_uninit(&t.stack); +err2: + upb_inttable_uninit(&t.objattr); +err1: + return ret; +} + + +/* Misc internal functions ***************************************************/ + +static bool merged(const upb_refcounted *r, const upb_refcounted *r2) { + return r->group == r2->group; +} + +static void merge(upb_refcounted *r, upb_refcounted *from) { + upb_refcounted *base; + upb_refcounted *tmp; + + if (merged(r, from)) return; + *r->group += *from->group; + free(from->group); + base = from; + + /* Set all refcount pointers in the "from" chain to the merged refcount. + * + * TODO(haberman): this linear algorithm can result in an overall O(n^2) bound + * if the user continuously extends a group by one object. Prevent this by + * using one of the techniques in this paper: + * ftp://www.ncedc.org/outgoing/geomorph/dino/orals/p245-tarjan.pdf */ + do { from->group = r->group; } while ((from = from->next) != base); + + /* Merge the two circularly linked lists by swapping their next pointers. */ + tmp = r->next; + r->next = base->next; + base->next = tmp; +} + +static void unref(const upb_refcounted *r); + +static void release_ref2(const upb_refcounted *obj, + const upb_refcounted *subobj, + void *closure) { + UPB_UNUSED(closure); + untrack(subobj, obj, true); + if (!merged(obj, subobj)) { + assert(subobj->is_frozen); + unref(subobj); + } +} + +static void unref(const upb_refcounted *r) { + if (unrefgroup(r->group)) { + const upb_refcounted *o; + + free(r->group); + + /* In two passes, since release_ref2 needs a guarantee that any subobjs + * are alive. */ + o = r; + do { visit(o, release_ref2, NULL); } while((o = o->next) != r); + + o = r; + do { + const upb_refcounted *next = o->next; + assert(o->is_frozen || o->individual_count == 0); + freeobj((upb_refcounted*)o); + o = next; + } while(o != r); + } +} + +static void freeobj(upb_refcounted *o) { + trackfree(o); + o->vtbl->free((upb_refcounted*)o); +} + + +/* Public interface ***********************************************************/ + +bool upb_refcounted_init(upb_refcounted *r, + const struct upb_refcounted_vtbl *vtbl, + const void *owner) { +#ifndef NDEBUG + /* Endianness check. This is unrelated to upb_refcounted, it's just a + * convenient place to put the check that we can be assured will run for + * basically every program using upb. */ + const int x = 1; +#ifdef UPB_BIG_ENDIAN + assert(*(char*)&x != 1); +#else + assert(*(char*)&x == 1); +#endif +#endif + + r->next = r; + r->vtbl = vtbl; + r->individual_count = 0; + r->is_frozen = false; + r->group = malloc(sizeof(*r->group)); + if (!r->group) return false; + *r->group = 0; + if (!trackinit(r)) { + free(r->group); + return false; + } + upb_refcounted_ref(r, owner); + return true; +} + +bool upb_refcounted_isfrozen(const upb_refcounted *r) { + return r->is_frozen; +} + +void upb_refcounted_ref(const upb_refcounted *r, const void *owner) { + track(r, owner, false); + if (!r->is_frozen) + ((upb_refcounted*)r)->individual_count++; + refgroup(r->group); +} + +void upb_refcounted_unref(const upb_refcounted *r, const void *owner) { + untrack(r, owner, false); + if (!r->is_frozen) + ((upb_refcounted*)r)->individual_count--; + unref(r); +} + +void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from) { + assert(!from->is_frozen); /* Non-const pointer implies this. */ + track(r, from, true); + if (r->is_frozen) { + refgroup(r->group); + } else { + merge((upb_refcounted*)r, from); + } +} + +void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from) { + assert(!from->is_frozen); /* Non-const pointer implies this. */ + untrack(r, from, true); + if (r->is_frozen) { + unref(r); + } else { + assert(merged(r, from)); + } +} + +void upb_refcounted_donateref( + const upb_refcounted *r, const void *from, const void *to) { + assert(from != to); + if (to != NULL) + upb_refcounted_ref(r, to); + if (from != NULL) + upb_refcounted_unref(r, from); +} + +void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) { + checkref(r, owner, false); +} + +bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, + int maxdepth) { + int i; + for (i = 0; i < n; i++) { + assert(!roots[i]->is_frozen); + } + return freeze(roots, n, s, maxdepth); +} + + +#include + +/* Fallback implementation if the shim is not specialized by the JIT. */ +#define SHIM_WRITER(type, ctype) \ + bool upb_shim_set ## type (void *c, const void *hd, ctype val) { \ + uint8_t *m = c; \ + const upb_shim_data *d = hd; \ + if (d->hasbit > 0) \ + *(uint8_t*)&m[d->hasbit / 8] |= 1 << (d->hasbit % 8); \ + *(ctype*)&m[d->offset] = val; \ + return true; \ + } \ + +SHIM_WRITER(double, double) +SHIM_WRITER(float, float) +SHIM_WRITER(int32, int32_t) +SHIM_WRITER(int64, int64_t) +SHIM_WRITER(uint32, uint32_t) +SHIM_WRITER(uint64, uint64_t) +SHIM_WRITER(bool, bool) +#undef SHIM_WRITER + +bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, + int32_t hasbit) { + upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; + bool ok; + + upb_shim_data *d = malloc(sizeof(*d)); + if (!d) return false; + d->offset = offset; + d->hasbit = hasbit; + + upb_handlerattr_sethandlerdata(&attr, d); + upb_handlerattr_setalwaysok(&attr, true); + upb_handlers_addcleanup(h, d, free); + +#define TYPE(u, l) \ + case UPB_TYPE_##u: \ + ok = upb_handlers_set##l(h, f, upb_shim_set##l, &attr); break; + + ok = false; + + switch (upb_fielddef_type(f)) { + TYPE(INT64, int64); + TYPE(INT32, int32); + TYPE(ENUM, int32); + TYPE(UINT64, uint64); + TYPE(UINT32, uint32); + TYPE(DOUBLE, double); + TYPE(FLOAT, float); + TYPE(BOOL, bool); + default: assert(false); break; + } +#undef TYPE + + upb_handlerattr_uninit(&attr); + return ok; +} + +const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s, + upb_fieldtype_t *type) { + upb_func *f = upb_handlers_gethandler(h, s); + + if ((upb_int64_handlerfunc*)f == upb_shim_setint64) { + *type = UPB_TYPE_INT64; + } else if ((upb_int32_handlerfunc*)f == upb_shim_setint32) { + *type = UPB_TYPE_INT32; + } else if ((upb_uint64_handlerfunc*)f == upb_shim_setuint64) { + *type = UPB_TYPE_UINT64; + } else if ((upb_uint32_handlerfunc*)f == upb_shim_setuint32) { + *type = UPB_TYPE_UINT32; + } else if ((upb_double_handlerfunc*)f == upb_shim_setdouble) { + *type = UPB_TYPE_DOUBLE; + } else if ((upb_float_handlerfunc*)f == upb_shim_setfloat) { + *type = UPB_TYPE_FLOAT; + } else if ((upb_bool_handlerfunc*)f == upb_shim_setbool) { + *type = UPB_TYPE_BOOL; + } else { + return NULL; + } + + return (const upb_shim_data*)upb_handlers_gethandlerdata(h, s); +} + + +#include +#include + +static void upb_symtab_free(upb_refcounted *r) { + upb_symtab *s = (upb_symtab*)r; + upb_strtable_iter i; + upb_strtable_begin(&i, &s->symtab); + for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { + const upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); + upb_def_unref(def, s); + } + upb_strtable_uninit(&s->symtab); + free(s); +} + + +upb_symtab *upb_symtab_new(const void *owner) { + static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free}; + upb_symtab *s = malloc(sizeof(*s)); + upb_refcounted_init(upb_symtab_upcast_mutable(s), &vtbl, owner); + upb_strtable_init(&s->symtab, UPB_CTYPE_PTR); + return s; +} + +void upb_symtab_freeze(upb_symtab *s) { + upb_refcounted *r; + bool ok; + + assert(!upb_symtab_isfrozen(s)); + r = upb_symtab_upcast_mutable(s); + /* The symtab does not take ref2's (see refcounted.h) on the defs, because + * defs cannot refer back to the table and therefore cannot create cycles. So + * 0 will suffice for maxdepth here. */ + ok = upb_refcounted_freeze(&r, 1, NULL, 0); + UPB_ASSERT_VAR(ok, ok); +} + +const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym) { + upb_value v; + upb_def *ret = upb_strtable_lookup(&s->symtab, sym, &v) ? + upb_value_getptr(v) : NULL; + return ret; +} + +const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym) { + upb_value v; + upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ? + upb_value_getptr(v) : NULL; + return def ? upb_dyncast_msgdef(def) : NULL; +} + +const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym) { + upb_value v; + upb_def *def = upb_strtable_lookup(&s->symtab, sym, &v) ? + upb_value_getptr(v) : NULL; + return def ? upb_dyncast_enumdef(def) : NULL; +} + +/* Given a symbol and the base symbol inside which it is defined, find the + * symbol's definition in t. */ +static upb_def *upb_resolvename(const upb_strtable *t, + const char *base, const char *sym) { + if(strlen(sym) == 0) return NULL; + if(sym[0] == '.') { + /* Symbols starting with '.' are absolute, so we do a single lookup. + * Slice to omit the leading '.' */ + upb_value v; + return upb_strtable_lookup(t, sym + 1, &v) ? upb_value_getptr(v) : NULL; + } else { + /* Remove components from base until we find an entry or run out. + * TODO: This branch is totally broken, but currently not used. */ + (void)base; + assert(false); + return NULL; + } +} + +const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, + const char *sym) { + upb_def *ret = upb_resolvename(&s->symtab, base, sym); + return ret; +} + +/* Starts a depth-first traversal at "def", recursing into any subdefs + * (ie. submessage types). Adds duplicates of existing defs to addtab + * wherever necessary, so that the resulting symtab will be consistent once + * addtab is added. + * + * More specifically, if any def D is found in the DFS that: + * + * 1. can reach a def that is being replaced by something in addtab, AND + * + * 2. is not itself being replaced already (ie. this name doesn't already + * exist in addtab) + * + * ...then a duplicate (new copy) of D will be added to addtab. + * + * Returns true if this happened for any def reachable from "def." + * + * It is slightly tricky to do this correctly in the presence of cycles. If we + * detect that our DFS has hit a cycle, we might not yet know if any SCCs on + * our stack can reach a def in addtab or not. Once we figure this out, that + * answer needs to apply to *all* defs in these SCCs, even if we visited them + * already. So a straight up one-pass cycle-detecting DFS won't work. + * + * To work around this problem, we traverse each SCC (which we already + * computed, since these defs are frozen) as a single node. We first compute + * whether the SCC as a whole can reach any def in addtab, then we dup (or not) + * the entire SCC. This requires breaking the encapsulation of upb_refcounted, + * since that is where we get the data about what SCC we are in. */ +static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab, + const void *new_owner, upb_inttable *seen, + upb_status *s) { + upb_value v; + bool need_dup; + const upb_def *base; + const void* memoize_key; + + /* Memoize results of this function for efficiency (since we're traversing a + * DAG this is not needed to limit the depth of the search). + * + * We memoize by SCC instead of by individual def. */ + memoize_key = def->base.group; + + if (upb_inttable_lookupptr(seen, memoize_key, &v)) + return upb_value_getbool(v); + + /* Visit submessages for all messages in the SCC. */ + need_dup = false; + base = def; + do { + upb_value v; + const upb_msgdef *m; + + assert(upb_def_isfrozen(def)); + if (def->type == UPB_DEF_FIELD) continue; + if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) { + need_dup = true; + } + + /* For messages, continue the recursion by visiting all subdefs, but only + * ones in different SCCs. */ + m = upb_dyncast_msgdef(def); + if (m) { + upb_msg_field_iter i; + for(upb_msg_field_begin(&i, m); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + upb_fielddef *f = upb_msg_iter_field(&i); + const upb_def *subdef; + + if (!upb_fielddef_hassubdef(f)) continue; + subdef = upb_fielddef_subdef(f); + + /* Skip subdefs in this SCC. */ + if (def->base.group == subdef->base.group) continue; + + /* |= to avoid short-circuit; we need its side-effects. */ + need_dup |= upb_resolve_dfs(subdef, addtab, new_owner, seen, s); + if (!upb_ok(s)) return false; + } + } + } while ((def = (upb_def*)def->base.next) != base); + + if (need_dup) { + /* Dup all defs in this SCC that don't already have entries in addtab. */ + def = base; + do { + const char *name; + + if (def->type == UPB_DEF_FIELD) continue; + name = upb_def_fullname(def); + if (!upb_strtable_lookup(addtab, name, NULL)) { + upb_def *newdef = upb_def_dup(def, new_owner); + if (!newdef) goto oom; + newdef->came_from_user = false; + if (!upb_strtable_insert(addtab, name, upb_value_ptr(newdef))) + goto oom; + } + } while ((def = (upb_def*)def->base.next) != base); + } + + upb_inttable_insertptr(seen, memoize_key, upb_value_bool(need_dup)); + return need_dup; + +oom: + upb_status_seterrmsg(s, "out of memory"); + return false; +} + +/* TODO(haberman): we need a lot more testing of error conditions. + * The came_from_user stuff in particular is not tested. */ +bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, + upb_status *status) { + int i; + upb_strtable_iter iter; + upb_def **add_defs = NULL; + upb_strtable addtab; + upb_inttable seen; + + assert(!upb_symtab_isfrozen(s)); + if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) { + upb_status_seterrmsg(status, "out of memory"); + return false; + } + + /* Add new defs to our "add" set. */ + for (i = 0; i < n; i++) { + upb_def *def = defs[i]; + const char *fullname; + upb_fielddef *f; + + if (upb_def_isfrozen(def)) { + upb_status_seterrmsg(status, "added defs must be mutable"); + goto err; + } + assert(!upb_def_isfrozen(def)); + fullname = upb_def_fullname(def); + if (!fullname) { + upb_status_seterrmsg( + status, "Anonymous defs cannot be added to a symtab"); + goto err; + } + + f = upb_dyncast_fielddef_mutable(def); + + if (f) { + if (!upb_fielddef_containingtypename(f)) { + upb_status_seterrmsg(status, + "Standalone fielddefs must have a containing type " + "(extendee) name set"); + goto err; + } + } else { + if (upb_strtable_lookup(&addtab, fullname, NULL)) { + upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); + goto err; + } + /* We need this to back out properly, because if there is a failure we + * need to donate the ref back to the caller. */ + def->came_from_user = true; + upb_def_donateref(def, ref_donor, s); + if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) + goto oom_err; + } + } + + /* Add standalone fielddefs (ie. extensions) to the appropriate messages. + * If the appropriate message only exists in the existing symtab, duplicate + * it so we have a mutable copy we can add the fields to. */ + for (i = 0; i < n; i++) { + upb_def *def = defs[i]; + upb_fielddef *f = upb_dyncast_fielddef_mutable(def); + const char *msgname; + upb_value v; + upb_msgdef *m; + + if (!f) continue; + msgname = upb_fielddef_containingtypename(f); + /* We validated this earlier in this function. */ + assert(msgname); + + /* If the extendee name is absolutely qualified, move past the initial ".". + * TODO(haberman): it is not obvious what it would mean if this was not + * absolutely qualified. */ + if (msgname[0] == '.') { + msgname++; + } + + if (upb_strtable_lookup(&addtab, msgname, &v)) { + /* Extendee is in the set of defs the user asked us to add. */ + m = upb_value_getptr(v); + } else { + /* Need to find and dup the extendee from the existing symtab. */ + const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname); + if (!frozen_m) { + upb_status_seterrf(status, + "Tried to extend message %s that does not exist " + "in this SymbolTable.", + msgname); + goto err; + } + m = upb_msgdef_dup(frozen_m, s); + if (!m) goto oom_err; + if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) { + upb_msgdef_unref(m, s); + goto oom_err; + } + } + + if (!upb_msgdef_addfield(m, f, ref_donor, status)) { + goto err; + } + } + + /* Add dups of any existing def that can reach a def with the same name as + * anything in our "add" set. */ + if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err; + upb_strtable_begin(&iter, &s->symtab); + for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { + upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); + upb_resolve_dfs(def, &addtab, s, &seen, status); + if (!upb_ok(status)) goto err; + } + upb_inttable_uninit(&seen); + + /* Now using the table, resolve symbolic references for subdefs. */ + upb_strtable_begin(&iter, &addtab); + for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { + const char *base; + upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); + upb_msgdef *m = upb_dyncast_msgdef_mutable(def); + upb_msg_field_iter j; + + if (!m) continue; + /* Type names are resolved relative to the message in which they appear. */ + base = upb_msgdef_fullname(m); + + for(upb_msg_field_begin(&j, m); + !upb_msg_field_done(&j); + upb_msg_field_next(&j)) { + upb_fielddef *f = upb_msg_iter_field(&j); + const char *name = upb_fielddef_subdefname(f); + if (name && !upb_fielddef_subdef(f)) { + /* Try the lookup in the current set of to-be-added defs first. If not + * there, try existing defs. */ + upb_def *subdef = upb_resolvename(&addtab, base, name); + if (subdef == NULL) { + subdef = upb_resolvename(&s->symtab, base, name); + } + if (subdef == NULL) { + upb_status_seterrf( + status, "couldn't resolve name '%s' in message '%s'", name, base); + goto err; + } else if (!upb_fielddef_setsubdef(f, subdef, status)) { + goto err; + } + } + } + } + + /* We need an array of the defs in addtab, for passing to upb_def_freeze. */ + add_defs = malloc(sizeof(void*) * upb_strtable_count(&addtab)); + if (add_defs == NULL) goto oom_err; + upb_strtable_begin(&iter, &addtab); + for (n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { + add_defs[n++] = upb_value_getptr(upb_strtable_iter_value(&iter)); + } + + if (!upb_def_freeze(add_defs, n, status)) goto err; + + /* This must be delayed until all errors have been detected, since error + * recovery code uses this table to cleanup defs. */ + upb_strtable_uninit(&addtab); + + /* TODO(haberman) we don't properly handle errors after this point (like + * OOM in upb_strtable_insert() below). */ + for (i = 0; i < n; i++) { + upb_def *def = add_defs[i]; + const char *name = upb_def_fullname(def); + upb_value v; + bool success; + + if (upb_strtable_remove(&s->symtab, name, &v)) { + const upb_def *def = upb_value_getptr(v); + upb_def_unref(def, s); + } + success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def)); + UPB_ASSERT_VAR(success, success == true); + } + free(add_defs); + return true; + +oom_err: + upb_status_seterrmsg(status, "out of memory"); +err: { + /* For defs the user passed in, we need to donate the refs back. For defs + * we dup'd, we need to just unref them. */ + upb_strtable_begin(&iter, &addtab); + for (; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { + upb_def *def = upb_value_getptr(upb_strtable_iter_value(&iter)); + bool came_from_user = def->came_from_user; + def->came_from_user = false; + if (came_from_user) { + upb_def_donateref(def, s, ref_donor); + } else { + upb_def_unref(def, s); + } + } + } + upb_strtable_uninit(&addtab); + free(add_defs); + assert(!upb_ok(status)); + return false; +} + +/* Iteration. */ + +static void advance_to_matching(upb_symtab_iter *iter) { + if (iter->type == UPB_DEF_ANY) + return; + + while (!upb_strtable_done(&iter->iter) && + iter->type != upb_symtab_iter_def(iter)->type) { + upb_strtable_next(&iter->iter); + } +} + +void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s, + upb_deftype_t type) { + upb_strtable_begin(&iter->iter, &s->symtab); + iter->type = type; + advance_to_matching(iter); +} + +void upb_symtab_next(upb_symtab_iter *iter) { + upb_strtable_next(&iter->iter); + advance_to_matching(iter); +} + +bool upb_symtab_done(const upb_symtab_iter *iter) { + return upb_strtable_done(&iter->iter); +} + +const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) { + return upb_value_getptr(upb_strtable_iter_value(&iter->iter)); +} +/* +** upb_table Implementation +** +** Implementation is heavily inspired by Lua's ltable.c. +*/ + + +#include +#include + +#define UPB_MAXARRSIZE 16 /* 64k. */ + +/* From Chromium. */ +#define ARRAY_SIZE(x) \ + ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) + +static const double MAX_LOAD = 0.85; + +/* The minimum utilization of the array part of a mixed hash/array table. This + * is a speed/memory-usage tradeoff (though it's not straightforward because of + * cache effects). The lower this is, the more memory we'll use. */ +static const double MIN_DENSITY = 0.1; + +bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; } + +int log2ceil(uint64_t v) { + int ret = 0; + bool pow2 = is_pow2(v); + while (v >>= 1) ret++; + ret = pow2 ? ret : ret + 1; /* Ceiling. */ + return UPB_MIN(UPB_MAXARRSIZE, ret); +} + +char *upb_strdup(const char *s) { + return upb_strdup2(s, strlen(s)); +} + +char *upb_strdup2(const char *s, size_t len) { + size_t n; + char *p; + + /* Prevent overflow errors. */ + if (len == SIZE_MAX) return NULL; + /* Always null-terminate, even if binary data; but don't rely on the input to + * have a null-terminating byte since it may be a raw binary buffer. */ + n = len + 1; + p = malloc(n); + if (p) { + memcpy(p, s, len); + p[len] = 0; + } + return p; +} + +/* A type to represent the lookup key of either a strtable or an inttable. */ +typedef union { + uintptr_t num; + struct { + const char *str; + size_t len; + } str; +} lookupkey_t; + +static lookupkey_t strkey2(const char *str, size_t len) { + lookupkey_t k; + k.str.str = str; + k.str.len = len; + return k; +} + +static lookupkey_t intkey(uintptr_t key) { + lookupkey_t k; + k.num = key; + return k; +} + +typedef uint32_t hashfunc_t(upb_tabkey key); +typedef bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2); + +/* Base table (shared code) ***************************************************/ + +/* For when we need to cast away const. */ +static upb_tabent *mutable_entries(upb_table *t) { + return (upb_tabent*)t->entries; +} + +static bool isfull(upb_table *t) { + return (double)(t->count + 1) / upb_table_size(t) > MAX_LOAD; +} + +static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2) { + size_t bytes; + + t->count = 0; + t->ctype = ctype; + t->size_lg2 = size_lg2; + t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; + bytes = upb_table_size(t) * sizeof(upb_tabent); + if (bytes > 0) { + t->entries = malloc(bytes); + if (!t->entries) return false; + memset(mutable_entries(t), 0, bytes); + } else { + t->entries = NULL; + } + return true; +} + +static void uninit(upb_table *t) { free(mutable_entries(t)); } + +static upb_tabent *emptyent(upb_table *t) { + upb_tabent *e = mutable_entries(t) + upb_table_size(t); + while (1) { if (upb_tabent_isempty(--e)) return e; assert(e > t->entries); } +} + +static upb_tabent *getentry_mutable(upb_table *t, uint32_t hash) { + return (upb_tabent*)upb_getentry(t, hash); +} + +static const upb_tabent *findentry(const upb_table *t, lookupkey_t key, + uint32_t hash, eqlfunc_t *eql) { + const upb_tabent *e; + + if (t->size_lg2 == 0) return NULL; + e = upb_getentry(t, hash); + if (upb_tabent_isempty(e)) return NULL; + while (1) { + if (eql(e->key, key)) return e; + if ((e = e->next) == NULL) return NULL; + } +} + +static upb_tabent *findentry_mutable(upb_table *t, lookupkey_t key, + uint32_t hash, eqlfunc_t *eql) { + return (upb_tabent*)findentry(t, key, hash, eql); +} + +static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v, + uint32_t hash, eqlfunc_t *eql) { + const upb_tabent *e = findentry(t, key, hash, eql); + if (e) { + if (v) { + _upb_value_setval(v, e->val.val, t->ctype); + } + return true; + } else { + return false; + } +} + +/* The given key must not already exist in the table. */ +static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey, + upb_value val, uint32_t hash, + hashfunc_t *hashfunc, eqlfunc_t *eql) { + upb_tabent *mainpos_e; + upb_tabent *our_e; + + UPB_UNUSED(eql); + UPB_UNUSED(key); + assert(findentry(t, key, hash, eql) == NULL); + assert(val.ctype == t->ctype); + + t->count++; + mainpos_e = getentry_mutable(t, hash); + our_e = mainpos_e; + + if (upb_tabent_isempty(mainpos_e)) { + /* Our main position is empty; use it. */ + our_e->next = NULL; + } else { + /* Collision. */ + upb_tabent *new_e = emptyent(t); + /* Head of collider's chain. */ + upb_tabent *chain = getentry_mutable(t, hashfunc(mainpos_e->key)); + if (chain == mainpos_e) { + /* Existing ent is in its main posisiton (it has the same hash as us, and + * is the head of our chain). Insert to new ent and append to this chain. */ + new_e->next = mainpos_e->next; + mainpos_e->next = new_e; + our_e = new_e; + } else { + /* Existing ent is not in its main position (it is a node in some other + * chain). This implies that no existing ent in the table has our hash. + * Evict it (updating its chain) and use its ent for head of our chain. */ + *new_e = *mainpos_e; /* copies next. */ + while (chain->next != mainpos_e) { + chain = (upb_tabent*)chain->next; + assert(chain); + } + chain->next = new_e; + our_e = mainpos_e; + our_e->next = NULL; + } + } + our_e->key = tabkey; + our_e->val.val = val.val; + assert(findentry(t, key, hash, eql) == our_e); +} + +static bool rm(upb_table *t, lookupkey_t key, upb_value *val, + upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql) { + upb_tabent *chain = getentry_mutable(t, hash); + if (upb_tabent_isempty(chain)) return false; + if (eql(chain->key, key)) { + /* Element to remove is at the head of its chain. */ + t->count--; + if (val) { + _upb_value_setval(val, chain->val.val, t->ctype); + } + if (chain->next) { + upb_tabent *move = (upb_tabent*)chain->next; + *chain = *move; + if (removed) *removed = move->key; + move->key = 0; /* Make the slot empty. */ + } else { + if (removed) *removed = chain->key; + chain->key = 0; /* Make the slot empty. */ + } + return true; + } else { + /* Element to remove is either in a non-head position or not in the + * table. */ + while (chain->next && !eql(chain->next->key, key)) + chain = (upb_tabent*)chain->next; + if (chain->next) { + /* Found element to remove. */ + upb_tabent *rm; + + if (val) { + _upb_value_setval(val, chain->next->val.val, t->ctype); + } + rm = (upb_tabent*)chain->next; + if (removed) *removed = rm->key; + rm->key = 0; + chain->next = rm->next; + t->count--; + return true; + } else { + return false; + } + } +} + +static size_t next(const upb_table *t, size_t i) { + do { + if (++i >= upb_table_size(t)) + return SIZE_MAX; + } while(upb_tabent_isempty(&t->entries[i])); + + return i; +} + +static size_t begin(const upb_table *t) { + return next(t, -1); +} + + +/* upb_strtable ***************************************************************/ + +/* A simple "subclass" of upb_table that only adds a hash function for strings. */ + +static upb_tabkey strcopy(lookupkey_t k2) { + char *str = malloc(k2.str.len + sizeof(uint32_t) + 1); + if (str == NULL) return 0; + memcpy(str, &k2.str.len, sizeof(uint32_t)); + memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len + 1); + return (uintptr_t)str; +} + +static uint32_t strhash(upb_tabkey key) { + uint32_t len; + char *str = upb_tabstr(key, &len); + return MurmurHash2(str, len, 0); +} + +static bool streql(upb_tabkey k1, lookupkey_t k2) { + uint32_t len; + char *str = upb_tabstr(k1, &len); + return len == k2.str.len && memcmp(str, k2.str.str, len) == 0; +} + +bool upb_strtable_init(upb_strtable *t, upb_ctype_t ctype) { + return init(&t->t, ctype, 2); +} + +void upb_strtable_uninit(upb_strtable *t) { + size_t i; + for (i = 0; i < upb_table_size(&t->t); i++) + free((void*)t->t.entries[i].key); + uninit(&t->t); +} + +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2) { + upb_strtable new_table; + upb_strtable_iter i; + + if (!init(&new_table.t, t->t.ctype, size_lg2)) + return false; + upb_strtable_begin(&i, t); + for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) { + upb_strtable_insert2( + &new_table, + upb_strtable_iter_key(&i), + upb_strtable_iter_keylength(&i), + upb_strtable_iter_value(&i)); + } + upb_strtable_uninit(t); + *t = new_table; + return true; +} + +bool upb_strtable_insert2(upb_strtable *t, const char *k, size_t len, + upb_value v) { + lookupkey_t key; + upb_tabkey tabkey; + uint32_t hash; + + if (isfull(&t->t)) { + /* Need to resize. New table of double the size, add old elements to it. */ + if (!upb_strtable_resize(t, t->t.size_lg2 + 1)) { + return false; + } + } + + key = strkey2(k, len); + tabkey = strcopy(key); + if (tabkey == 0) return false; + + hash = MurmurHash2(key.str.str, key.str.len, 0); + insert(&t->t, key, tabkey, v, hash, &strhash, &streql); + return true; +} + +bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, + upb_value *v) { + uint32_t hash = MurmurHash2(key, len, 0); + return lookup(&t->t, strkey2(key, len), v, hash, &streql); +} + +bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len, + upb_value *val) { + uint32_t hash = MurmurHash2(key, strlen(key), 0); + upb_tabkey tabkey; + if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { + free((void*)tabkey); + return true; + } else { + return false; + } +} + +/* Iteration */ + +static const upb_tabent *str_tabent(const upb_strtable_iter *i) { + return &i->t->t.entries[i->index]; +} + +void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t) { + i->t = t; + i->index = begin(&t->t); +} + +void upb_strtable_next(upb_strtable_iter *i) { + i->index = next(&i->t->t, i->index); +} + +bool upb_strtable_done(const upb_strtable_iter *i) { + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(str_tabent(i)); +} + +const char *upb_strtable_iter_key(upb_strtable_iter *i) { + assert(!upb_strtable_done(i)); + return upb_tabstr(str_tabent(i)->key, NULL); +} + +size_t upb_strtable_iter_keylength(upb_strtable_iter *i) { + uint32_t len; + assert(!upb_strtable_done(i)); + upb_tabstr(str_tabent(i)->key, &len); + return len; +} + +upb_value upb_strtable_iter_value(const upb_strtable_iter *i) { + assert(!upb_strtable_done(i)); + return _upb_value_val(str_tabent(i)->val.val, i->t->t.ctype); +} + +void upb_strtable_iter_setdone(upb_strtable_iter *i) { + i->index = SIZE_MAX; +} + +bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, + const upb_strtable_iter *i2) { + if (upb_strtable_done(i1) && upb_strtable_done(i2)) + return true; + return i1->t == i2->t && i1->index == i2->index; +} + + +/* upb_inttable ***************************************************************/ + +/* For inttables we use a hybrid structure where small keys are kept in an + * array and large keys are put in the hash table. */ + +static uint32_t inthash(upb_tabkey key) { return upb_inthash(key); } + +static bool inteql(upb_tabkey k1, lookupkey_t k2) { + return k1 == k2.num; +} + +static upb_tabval *mutable_array(upb_inttable *t) { + return (upb_tabval*)t->array; +} + +static upb_tabval *inttable_val(upb_inttable *t, uintptr_t key) { + if (key < t->array_size) { + return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL; + } else { + upb_tabent *e = + findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); + return e ? &e->val : NULL; + } +} + +static const upb_tabval *inttable_val_const(const upb_inttable *t, + uintptr_t key) { + return inttable_val((upb_inttable*)t, key); +} + +size_t upb_inttable_count(const upb_inttable *t) { + return t->t.count + t->array_count; +} + +static void check(upb_inttable *t) { + UPB_UNUSED(t); +#if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) + { + /* This check is very expensive (makes inserts/deletes O(N)). */ + size_t count = 0; + upb_inttable_iter i; + upb_inttable_begin(&i, t); + for(; !upb_inttable_done(&i); upb_inttable_next(&i), count++) { + assert(upb_inttable_lookup(t, upb_inttable_iter_key(&i), NULL)); + } + assert(count == upb_inttable_count(t)); + } +#endif +} + +bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype, + size_t asize, int hsize_lg2) { + size_t array_bytes; + + if (!init(&t->t, ctype, hsize_lg2)) return false; + /* Always make the array part at least 1 long, so that we know key 0 + * won't be in the hash part, which simplifies things. */ + t->array_size = UPB_MAX(1, asize); + t->array_count = 0; + array_bytes = t->array_size * sizeof(upb_value); + t->array = malloc(array_bytes); + if (!t->array) { + uninit(&t->t); + return false; + } + memset(mutable_array(t), 0xff, array_bytes); + check(t); + return true; +} + +bool upb_inttable_init(upb_inttable *t, upb_ctype_t ctype) { + return upb_inttable_sizedinit(t, ctype, 0, 4); +} + +void upb_inttable_uninit(upb_inttable *t) { + uninit(&t->t); + free(mutable_array(t)); +} + +bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { + /* XXX: Table can't store value (uint64_t)-1. Need to somehow statically + * guarantee that this is not necessary, or fix the limitation. */ + upb_tabval tabval; + tabval.val = val.val; + UPB_UNUSED(tabval); + assert(upb_arrhas(tabval)); + + if (key < t->array_size) { + assert(!upb_arrhas(t->array[key])); + t->array_count++; + mutable_array(t)[key].val = val.val; + } else { + if (isfull(&t->t)) { + /* Need to resize the hash part, but we re-use the array part. */ + size_t i; + upb_table new_table; + if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1)) + return false; + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { + const upb_tabent *e = &t->t.entries[i]; + uint32_t hash; + upb_value v; + + _upb_value_setval(&v, e->val.val, t->t.ctype); + hash = upb_inthash(e->key); + insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql); + } + + assert(t->t.count == new_table.count); + + uninit(&t->t); + t->t = new_table; + } + insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); + } + check(t); + return true; +} + +bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v) { + const upb_tabval *table_v = inttable_val_const(t, key); + if (!table_v) return false; + if (v) _upb_value_setval(v, table_v->val, t->t.ctype); + return true; +} + +bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val) { + upb_tabval *table_v = inttable_val(t, key); + if (!table_v) return false; + table_v->val = val.val; + return true; +} + +bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { + bool success; + if (key < t->array_size) { + if (upb_arrhas(t->array[key])) { + upb_tabval empty = UPB_TABVALUE_EMPTY_INIT; + t->array_count--; + if (val) { + _upb_value_setval(val, t->array[key].val, t->t.ctype); + } + mutable_array(t)[key] = empty; + success = true; + } else { + success = false; + } + } else { + upb_tabkey removed; + uint32_t hash = upb_inthash(key); + success = rm(&t->t, intkey(key), val, &removed, hash, &inteql); + } + check(t); + return success; +} + +bool upb_inttable_push(upb_inttable *t, upb_value val) { + return upb_inttable_insert(t, upb_inttable_count(t), val); +} + +upb_value upb_inttable_pop(upb_inttable *t) { + upb_value val; + bool ok = upb_inttable_remove(t, upb_inttable_count(t) - 1, &val); + UPB_ASSERT_VAR(ok, ok); + return val; +} + +bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val) { + return upb_inttable_insert(t, (uintptr_t)key, val); +} + +bool upb_inttable_lookupptr(const upb_inttable *t, const void *key, + upb_value *v) { + return upb_inttable_lookup(t, (uintptr_t)key, v); +} + +bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { + return upb_inttable_remove(t, (uintptr_t)key, val); +} + +void upb_inttable_compact(upb_inttable *t) { + /* Create a power-of-two histogram of the table keys. */ + int counts[UPB_MAXARRSIZE + 1] = {0}; + uintptr_t max_key = 0; + upb_inttable_iter i; + size_t arr_size; + int arr_count; + upb_inttable new_t; + + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t key = upb_inttable_iter_key(&i); + if (key > max_key) { + max_key = key; + } + counts[log2ceil(key)]++; + } + + arr_size = 1; + arr_count = upb_inttable_count(t); + + if (upb_inttable_count(t) >= max_key * MIN_DENSITY) { + /* We can put 100% of the entries in the array part. */ + arr_size = max_key + 1; + } else { + /* Find the largest power of two that satisfies the MIN_DENSITY + * definition. */ + int size_lg2; + for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 1; size_lg2--) { + arr_size = 1 << size_lg2; + arr_count -= counts[size_lg2]; + if (arr_count >= arr_size * MIN_DENSITY) { + break; + } + } + } + + /* Array part must always be at least 1 entry large to catch lookups of key + * 0. Key 0 must always be in the array part because "0" in the hash part + * denotes an empty entry. */ + arr_size = UPB_MAX(arr_size, 1); + + { + /* Insert all elements into new, perfectly-sized table. */ + int hash_count = upb_inttable_count(t) - arr_count; + int hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; + int hashsize_lg2 = log2ceil(hash_size); + + assert(hash_count >= 0); + upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2); + upb_inttable_begin(&i, t); + for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { + uintptr_t k = upb_inttable_iter_key(&i); + upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i)); + } + assert(new_t.array_size == arr_size); + assert(new_t.t.size_lg2 == hashsize_lg2); + } + upb_inttable_uninit(t); + *t = new_t; +} + +/* Iteration. */ + +static const upb_tabent *int_tabent(const upb_inttable_iter *i) { + assert(!i->array_part); + return &i->t->t.entries[i->index]; +} + +static upb_tabval int_arrent(const upb_inttable_iter *i) { + assert(i->array_part); + return i->t->array[i->index]; +} + +void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t) { + i->t = t; + i->index = -1; + i->array_part = true; + upb_inttable_next(i); +} + +void upb_inttable_next(upb_inttable_iter *iter) { + const upb_inttable *t = iter->t; + if (iter->array_part) { + while (++iter->index < t->array_size) { + if (upb_arrhas(int_arrent(iter))) { + return; + } + } + iter->array_part = false; + iter->index = begin(&t->t); + } else { + iter->index = next(&t->t, iter->index); + } +} + +bool upb_inttable_done(const upb_inttable_iter *i) { + if (i->array_part) { + return i->index >= i->t->array_size || + !upb_arrhas(int_arrent(i)); + } else { + return i->index >= upb_table_size(&i->t->t) || + upb_tabent_isempty(int_tabent(i)); + } +} + +uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i) { + assert(!upb_inttable_done(i)); + return i->array_part ? i->index : int_tabent(i)->key; +} + +upb_value upb_inttable_iter_value(const upb_inttable_iter *i) { + assert(!upb_inttable_done(i)); + return _upb_value_val( + i->array_part ? i->t->array[i->index].val : int_tabent(i)->val.val, + i->t->t.ctype); +} + +void upb_inttable_iter_setdone(upb_inttable_iter *i) { + i->index = SIZE_MAX; + i->array_part = false; +} + +bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, + const upb_inttable_iter *i2) { + if (upb_inttable_done(i1) && upb_inttable_done(i2)) + return true; + return i1->t == i2->t && i1->index == i2->index && + i1->array_part == i2->array_part; +} + +#ifdef UPB_UNALIGNED_READS_OK +/* ----------------------------------------------------------------------------- + * MurmurHash2, by Austin Appleby (released as public domain). + * Reformatted and C99-ified by Joshua Haberman. + * Note - This code makes a few assumptions about how your machine behaves - + * 1. We can read a 4-byte value from any address without crashing + * 2. sizeof(int) == 4 (in upb this limitation is removed by using uint32_t + * And it has a few limitations - + * 1. It will not work incrementally. + * 2. It will not produce the same results on little-endian and big-endian + * machines. */ +uint32_t MurmurHash2(const void *key, size_t len, uint32_t seed) { + /* 'm' and 'r' are mixing constants generated offline. + * They're not really 'magic', they just happen to work well. */ + const uint32_t m = 0x5bd1e995; + const int32_t r = 24; + + /* Initialize the hash to a 'random' value */ + uint32_t h = seed ^ len; + + /* Mix 4 bytes at a time into the hash */ + const uint8_t * data = (const uint8_t *)key; + while(len >= 4) { + uint32_t k = *(uint32_t *)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + /* Handle the last few bytes of the input array */ + switch(len) { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; h *= m; + }; + + /* Do a few final mixes of the hash to ensure the last few + * bytes are well-incorporated. */ + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +#else /* !UPB_UNALIGNED_READS_OK */ + +/* ----------------------------------------------------------------------------- + * MurmurHashAligned2, by Austin Appleby + * Same algorithm as MurmurHash2, but only does aligned reads - should be safer + * on certain platforms. + * Performance will be lower than MurmurHash2 */ + +#define MIX(h,k,m) { k *= m; k ^= k >> r; k *= m; h *= m; h ^= k; } + +uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed) { + const uint32_t m = 0x5bd1e995; + const int32_t r = 24; + const uint8_t * data = (const uint8_t *)key; + uint32_t h = seed ^ len; + uint8_t align = (uintptr_t)data & 3; + + if(align && (len >= 4)) { + /* Pre-load the temp registers */ + uint32_t t = 0, d = 0; + int32_t sl; + int32_t sr; + + switch(align) { + case 1: t |= data[2] << 16; + case 2: t |= data[1] << 8; + case 3: t |= data[0]; + } + + t <<= (8 * align); + + data += 4-align; + len -= 4-align; + + sl = 8 * (4-align); + sr = 8 * align; + + /* Mix */ + + while(len >= 4) { + uint32_t k; + + d = *(uint32_t *)data; + t = (t >> sr) | (d << sl); + + k = t; + + MIX(h,k,m); + + t = d; + + data += 4; + len -= 4; + } + + /* Handle leftover data in temp registers */ + + d = 0; + + if(len >= align) { + uint32_t k; + + switch(align) { + case 3: d |= data[2] << 16; + case 2: d |= data[1] << 8; + case 1: d |= data[0]; + } + + k = (t >> sr) | (d << sl); + MIX(h,k,m); + + data += align; + len -= align; + + /* ---------- + * Handle tail bytes */ + + switch(len) { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; h *= m; + }; + } else { + switch(len) { + case 3: d |= data[2] << 16; + case 2: d |= data[1] << 8; + case 1: d |= data[0]; + case 0: h ^= (t >> sr) | (d << sl); h *= m; + } + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } else { + while(len >= 4) { + uint32_t k = *(uint32_t *)data; + + MIX(h,k,m); + + data += 4; + len -= 4; + } + + /* ---------- + * Handle tail bytes */ + + switch(len) { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; h *= m; + }; + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; + } +} +#undef MIX + +#endif /* UPB_UNALIGNED_READS_OK */ + +#include +#include +#include +#include +#include +#include +#include + +bool upb_dumptostderr(void *closure, const upb_status* status) { + UPB_UNUSED(closure); + fprintf(stderr, "%s\n", upb_status_errmsg(status)); + return false; +} + +/* Guarantee null-termination and provide ellipsis truncation. + * It may be tempting to "optimize" this by initializing these final + * four bytes up-front and then being careful never to overwrite them, + * this is safer and simpler. */ +static void nullz(upb_status *status) { + const char *ellipsis = "..."; + size_t len = strlen(ellipsis); + assert(sizeof(status->msg) > len); + memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len); +} + +void upb_status_clear(upb_status *status) { + if (!status) return; + status->ok_ = true; + status->code_ = 0; + status->msg[0] = '\0'; +} + +bool upb_ok(const upb_status *status) { return status->ok_; } + +upb_errorspace *upb_status_errspace(const upb_status *status) { + return status->error_space_; +} + +int upb_status_errcode(const upb_status *status) { return status->code_; } + +const char *upb_status_errmsg(const upb_status *status) { return status->msg; } + +void upb_status_seterrmsg(upb_status *status, const char *msg) { + if (!status) return; + status->ok_ = false; + strncpy(status->msg, msg, sizeof(status->msg)); + nullz(status); +} + +void upb_status_seterrf(upb_status *status, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + upb_status_vseterrf(status, fmt, args); + va_end(args); +} + +void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) { + if (!status) return; + status->ok_ = false; + _upb_vsnprintf(status->msg, sizeof(status->msg), fmt, args); + nullz(status); +} + +void upb_status_seterrcode(upb_status *status, upb_errorspace *space, + int code) { + if (!status) return; + status->ok_ = false; + status->error_space_ = space; + status->code_ = code; + space->set_message(status, code); +} + +void upb_status_copy(upb_status *to, const upb_status *from) { + if (!to) return; + *to = *from; +} +/* This file was generated by upbc (the upb compiler). + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + + +static const upb_msgdef msgs[20]; +static const upb_fielddef fields[81]; +static const upb_enumdef enums[4]; +static const upb_tabent strentries[236]; +static const upb_tabent intentries[14]; +static const upb_tabval arrays[232]; + +#ifdef UPB_DEBUG_REFS +static upb_inttable reftables[212]; +#endif + +static const upb_msgdef msgs[20] = { + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 27, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 8, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[0]),&reftables[0], &reftables[1]), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[8], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]),&reftables[2], &reftables[3]), + UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[20]),&reftables[4], &reftables[5]), + UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 7, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[15], 8, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[24]),&reftables[6], &reftables[7]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[23], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]),&reftables[8], &reftables[9]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[27], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[32]),&reftables[10], &reftables[11]), + UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 19, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 9, 8), UPB_STRTABLE_INIT(8, 15, UPB_CTYPE_PTR, 4, &strentries[36]),&reftables[12], &reftables[13]), + UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 14, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[40], 32, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[52]),&reftables[14], &reftables[15]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 39, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[72], 12, 11), UPB_STRTABLE_INIT(11, 15, UPB_CTYPE_PTR, 4, &strentries[68]),&reftables[16], &reftables[17]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[84], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[84]),&reftables[18], &reftables[19]), + UPB_MSGDEF_INIT("google.protobuf.FileOptions", 21, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[86], 64, 9), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[88]),&reftables[20], &reftables[21]), + UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[150], 16, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[104]),&reftables[22], &reftables[23]), + UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 13, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[166], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &strentries[108]),&reftables[24], &reftables[25]), + UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[10], &arrays[171], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[116]),&reftables[26], &reftables[27]), + UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[175], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[120]),&reftables[28], &reftables[29]), + UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 6, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[12], &arrays[179], 4, 0), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[124]),&reftables[30], &reftables[31]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[183], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[128]),&reftables[32], &reftables[33]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 14, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[185], 5, 4), UPB_STRTABLE_INIT(4, 7, UPB_CTYPE_PTR, 3, &strentries[132]),&reftables[34], &reftables[35]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[190], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[140]),&reftables[36], &reftables[37]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[199], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[156]),&reftables[38], &reftables[39]), +}; + +static const upb_fielddef fields[81] = { + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "aggregate_value", 8, &msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "allow_alias", 2, &msgs[3], NULL, 6, 1, {0},&reftables[42], &reftables[43]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "cc_generic_services", 16, &msgs[10], NULL, 17, 6, {0},&reftables[44], &reftables[45]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "ctype", 1, &msgs[7], (const upb_def*)(&enums[2]), 6, 1, {0},&reftables[46], &reftables[47]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "default_value", 7, &msgs[6], NULL, 16, 7, {0},&reftables[48], &reftables[49]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "dependency", 3, &msgs[8], NULL, 30, 8, {0},&reftables[50], &reftables[51]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[7], NULL, 8, 3, {0},&reftables[52], &reftables[53]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, false, false, "double_value", 6, &msgs[18], NULL, 11, 4, {0},&reftables[54], &reftables[55]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[1], NULL, 3, 1, {0},&reftables[56], &reftables[57]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], (const upb_def*)(&msgs[2]), 16, 2, {0},&reftables[58], &reftables[59]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[8], (const upb_def*)(&msgs[2]), 13, 1, {0},&reftables[60], &reftables[61]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "experimental_map_key", 9, &msgs[7], NULL, 10, 5, {0},&reftables[62], &reftables[63]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "extendee", 2, &msgs[6], NULL, 7, 2, {0},&reftables[64], &reftables[65]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 7, &msgs[8], (const upb_def*)(&msgs[6]), 19, 3, {0},&reftables[66], &reftables[67]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 6, &msgs[0], (const upb_def*)(&msgs[6]), 22, 4, {0},&reftables[68], &reftables[69]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension_range", 5, &msgs[0], (const upb_def*)(&msgs[1]), 19, 3, {0},&reftables[70], &reftables[71]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "field", 2, &msgs[0], (const upb_def*)(&msgs[6]), 10, 0, {0},&reftables[72], &reftables[73]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "file", 1, &msgs[9], (const upb_def*)(&msgs[8]), 5, 0, {0},&reftables[74], &reftables[75]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "go_package", 11, &msgs[10], NULL, 14, 5, {0},&reftables[76], &reftables[77]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "identifier_value", 3, &msgs[18], NULL, 6, 1, {0},&reftables[78], &reftables[79]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "input_type", 2, &msgs[12], NULL, 7, 2, {0},&reftables[80], &reftables[81]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, false, false, "is_extension", 2, &msgs[19], NULL, 5, 1, {0},&reftables[82], &reftables[83]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generate_equals_and_hash", 20, &msgs[10], NULL, 20, 9, {0},&reftables[84], &reftables[85]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_generic_services", 17, &msgs[10], NULL, 18, 7, {0},&reftables[86], &reftables[87]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "java_multiple_files", 10, &msgs[10], NULL, 13, 4, {0},&reftables[88], &reftables[89]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_outer_classname", 8, &msgs[10], NULL, 9, 2, {0},&reftables[90], &reftables[91]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "java_package", 1, &msgs[10], NULL, 6, 1, {0},&reftables[92], &reftables[93]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "label", 4, &msgs[6], (const upb_def*)(&enums[0]), 11, 4, {0},&reftables[94], &reftables[95]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "lazy", 5, &msgs[7], NULL, 9, 4, {0},&reftables[96], &reftables[97]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "leading_comments", 3, &msgs[17], NULL, 8, 2, {0},&reftables[98], &reftables[99]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "location", 1, &msgs[16], (const upb_def*)(&msgs[17]), 5, 0, {0},&reftables[100], &reftables[101]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "message_set_wire_format", 1, &msgs[11], NULL, 6, 1, {0},&reftables[102], &reftables[103]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "message_type", 4, &msgs[8], (const upb_def*)(&msgs[0]), 10, 0, {0},&reftables[104], &reftables[105]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "method", 2, &msgs[14], (const upb_def*)(&msgs[12]), 6, 0, {0},&reftables[106], &reftables[107]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[8], NULL, 22, 6, {0},&reftables[108], &reftables[109]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[14], NULL, 8, 2, {0},&reftables[110], &reftables[111]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[18], (const upb_def*)(&msgs[19]), 5, 0, {0},&reftables[112], &reftables[113]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[4], NULL, 4, 1, {0},&reftables[114], &reftables[115]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[0], NULL, 24, 6, {0},&reftables[116], &reftables[117]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[12], NULL, 4, 1, {0},&reftables[118], &reftables[119]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[2], NULL, 8, 2, {0},&reftables[120], &reftables[121]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[6], NULL, 4, 1, {0},&reftables[122], &reftables[123]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, false, false, "name_part", 1, &msgs[19], NULL, 2, 0, {0},&reftables[124], &reftables[125]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, false, false, "negative_int_value", 5, &msgs[18], NULL, 10, 3, {0},&reftables[126], &reftables[127]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "nested_type", 3, &msgs[0], (const upb_def*)(&msgs[0]), 13, 1, {0},&reftables[128], &reftables[129]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "no_standard_descriptor_accessor", 2, &msgs[11], NULL, 7, 2, {0},&reftables[130], &reftables[131]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[6], NULL, 10, 3, {0},&reftables[132], &reftables[133]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[4], NULL, 7, 2, {0},&reftables[134], &reftables[135]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "optimize_for", 9, &msgs[10], (const upb_def*)(&enums[3]), 12, 3, {0},&reftables[136], &reftables[137]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], (const upb_def*)(&msgs[11]), 23, 5, {0},&reftables[138], &reftables[139]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[2], (const upb_def*)(&msgs[3]), 7, 1, {0},&reftables[140], &reftables[141]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[6], (const upb_def*)(&msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[4], (const upb_def*)(&msgs[5]), 3, 0, {0},&reftables[144], &reftables[145]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[8], (const upb_def*)(&msgs[10]), 20, 4, {0},&reftables[146], &reftables[147]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[14], (const upb_def*)(&msgs[15]), 7, 1, {0},&reftables[148], &reftables[149]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[12], (const upb_def*)(&msgs[13]), 3, 0, {0},&reftables[150], &reftables[151]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "output_type", 3, &msgs[12], NULL, 10, 3, {0},&reftables[152], &reftables[153]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "package", 2, &msgs[8], NULL, 25, 7, {0},&reftables[154], &reftables[155]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "packed", 2, &msgs[7], NULL, 7, 2, {0},&reftables[156], &reftables[157]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "path", 1, &msgs[17], NULL, 4, 0, {0},&reftables[158], &reftables[159]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, false, false, "positive_int_value", 4, &msgs[18], NULL, 9, 2, {0},&reftables[160], &reftables[161]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "public_dependency", 10, &msgs[8], NULL, 35, 9, {0},&reftables[162], &reftables[163]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "py_generic_services", 18, &msgs[10], NULL, 19, 8, {0},&reftables[164], &reftables[165]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "service", 6, &msgs[8], (const upb_def*)(&msgs[14]), 16, 2, {0},&reftables[166], &reftables[167]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "source_code_info", 9, &msgs[8], (const upb_def*)(&msgs[16]), 21, 5, {0},&reftables[168], &reftables[169]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "span", 2, &msgs[17], NULL, 7, 1, {0},&reftables[170], &reftables[171]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 2, 0, {0},&reftables[172], &reftables[173]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, false, false, "string_value", 7, &msgs[18], NULL, 12, 5, {0},&reftables[174], &reftables[175]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "trailing_comments", 4, &msgs[17], NULL, 11, 3, {0},&reftables[176], &reftables[177]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "type", 5, &msgs[6], (const upb_def*)(&enums[1]), 12, 5, {0},&reftables[178], &reftables[179]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "type_name", 6, &msgs[6], NULL, 13, 6, {0},&reftables[180], &reftables[181]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[5], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[15], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[184], &reftables[185]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[3], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[186], &reftables[187]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[13], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[188], &reftables[189]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[10], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[190], &reftables[191]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[192], &reftables[193]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[7], (const upb_def*)(&msgs[18]), 5, 0, {0},&reftables[194], &reftables[195]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "value", 2, &msgs[2], (const upb_def*)(&msgs[4]), 6, 0, {0},&reftables[196], &reftables[197]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "weak", 10, &msgs[7], NULL, 13, 6, {0},&reftables[198], &reftables[199]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "weak_dependency", 11, &msgs[8], NULL, 38, 10, {0},&reftables[200], &reftables[201]), +}; + +static const upb_enumdef enums[4] = { + UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Label", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[160]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[202], 4, 3), 0, &reftables[202], &reftables[203]), + UPB_ENUMDEF_INIT("google.protobuf.FieldDescriptorProto.Type", UPB_STRTABLE_INIT(18, 31, UPB_CTYPE_INT32, 5, &strentries[164]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[206], 19, 18), 0, &reftables[204], &reftables[205]), + UPB_ENUMDEF_INIT("google.protobuf.FieldOptions.CType", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[196]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[225], 3, 3), 0, &reftables[206], &reftables[207]), + UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[200]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[228], 4, 3), 0, &reftables[208], &reftables[209]), +}; + +static const upb_tabent strentries[236] = { + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[38]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "field"), UPB_TABVALUE_PTR_INIT(&fields[16]), NULL}, + {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "extension_range"), UPB_TABVALUE_PTR_INIT(&fields[15]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "nested_type"), UPB_TABVALUE_PTR_INIT(&fields[44]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[49]), NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[9]), &strentries[14]}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[66]), NULL}, + {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[8]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "value"), UPB_TABVALUE_PTR_INIT(&fields[78]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[50]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[40]), &strentries[22]}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "allow_alias"), UPB_TABVALUE_PTR_INIT(&fields[1]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[47]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[52]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[37]), &strentries[30]}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "label"), UPB_TABVALUE_PTR_INIT(&fields[27]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[41]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[46]), &strentries[49]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "type_name"), UPB_TABVALUE_PTR_INIT(&fields[70]), NULL}, + {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "extendee"), UPB_TABVALUE_PTR_INIT(&fields[12]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "type"), UPB_TABVALUE_PTR_INIT(&fields[69]), &strentries[48]}, + {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "default_value"), UPB_TABVALUE_PTR_INIT(&fields[4]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[51]), NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "experimental_map_key"), UPB_TABVALUE_PTR_INIT(&fields[11]), &strentries[67]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "weak"), UPB_TABVALUE_PTR_INIT(&fields[79]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "packed"), UPB_TABVALUE_PTR_INIT(&fields[58]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "lazy"), UPB_TABVALUE_PTR_INIT(&fields[28]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "ctype"), UPB_TABVALUE_PTR_INIT(&fields[3]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[6]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[77]), NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL}, + {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "weak_dependency"), UPB_TABVALUE_PTR_INIT(&fields[80]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[34]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "service"), UPB_TABVALUE_PTR_INIT(&fields[63]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "source_code_info"), UPB_TABVALUE_PTR_INIT(&fields[64]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "dependency"), UPB_TABVALUE_PTR_INIT(&fields[5]), NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "message_type"), UPB_TABVALUE_PTR_INIT(&fields[32]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "package"), UPB_TABVALUE_PTR_INIT(&fields[57]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[53]), &strentries[82]}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL}, + {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "public_dependency"), UPB_TABVALUE_PTR_INIT(&fields[61]), &strentries[81]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "file"), UPB_TABVALUE_PTR_INIT(&fields[17]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "cc_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[2]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "java_multiple_files"), UPB_TABVALUE_PTR_INIT(&fields[24]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\025", "\000", "\000", "\000", "java_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[23]), &strentries[102]}, + {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "java_generate_equals_and_hash"), UPB_TABVALUE_PTR_INIT(&fields[22]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "go_package"), UPB_TABVALUE_PTR_INIT(&fields[18]), NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "java_package"), UPB_TABVALUE_PTR_INIT(&fields[26]), NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "optimize_for"), UPB_TABVALUE_PTR_INIT(&fields[48]), NULL}, + {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "py_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[62]), NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "java_outer_classname"), UPB_TABVALUE_PTR_INIT(&fields[25]), NULL}, + {UPB_TABKEY_STR("\027", "\000", "\000", "\000", "message_set_wire_format"), UPB_TABVALUE_PTR_INIT(&fields[31]), &strentries[106]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL}, + {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "no_standard_descriptor_accessor"), UPB_TABVALUE_PTR_INIT(&fields[45]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[39]), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "input_type"), UPB_TABVALUE_PTR_INIT(&fields[20]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "output_type"), UPB_TABVALUE_PTR_INIT(&fields[56]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[55]), NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[54]), &strentries[122]}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "method"), UPB_TABVALUE_PTR_INIT(&fields[33]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[35]), &strentries[121]}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[72]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "location"), UPB_TABVALUE_PTR_INIT(&fields[30]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "span"), UPB_TABVALUE_PTR_INIT(&fields[65]), &strentries[139]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "trailing_comments"), UPB_TABVALUE_PTR_INIT(&fields[68]), NULL}, + {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "leading_comments"), UPB_TABVALUE_PTR_INIT(&fields[29]), &strentries[137]}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "path"), UPB_TABVALUE_PTR_INIT(&fields[59]), NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "double_value"), UPB_TABVALUE_PTR_INIT(&fields[7]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[36]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "negative_int_value"), UPB_TABVALUE_PTR_INIT(&fields[43]), NULL}, + {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "aggregate_value"), UPB_TABVALUE_PTR_INIT(&fields[0]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\022", "\000", "\000", "\000", "positive_int_value"), UPB_TABVALUE_PTR_INIT(&fields[60]), NULL}, + {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "identifier_value"), UPB_TABVALUE_PTR_INIT(&fields[19]), NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "string_value"), UPB_TABVALUE_PTR_INIT(&fields[67]), &strentries[154]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "is_extension"), UPB_TABVALUE_PTR_INIT(&fields[21]), NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "name_part"), UPB_TABVALUE_PTR_INIT(&fields[42]), NULL}, + {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REQUIRED"), UPB_TABVALUE_INT_INIT(2), &strentries[162]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_REPEATED"), UPB_TABVALUE_INT_INIT(3), NULL}, + {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "LABEL_OPTIONAL"), UPB_TABVALUE_INT_INIT(1), NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED64"), UPB_TABVALUE_INT_INIT(6), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_STRING"), UPB_TABVALUE_INT_INIT(9), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_FLOAT"), UPB_TABVALUE_INT_INIT(2), &strentries[193]}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_DOUBLE"), UPB_TABVALUE_INT_INIT(1), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT32"), UPB_TABVALUE_INT_INIT(5), NULL}, + {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED32"), UPB_TABVALUE_INT_INIT(15), NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_FIXED32"), UPB_TABVALUE_INT_INIT(7), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "TYPE_MESSAGE"), UPB_TABVALUE_INT_INIT(11), &strentries[194]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_INT64"), UPB_TABVALUE_INT_INIT(3), &strentries[191]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_ENUM"), UPB_TABVALUE_INT_INIT(14), NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT32"), UPB_TABVALUE_INT_INIT(13), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_UINT64"), UPB_TABVALUE_INT_INIT(4), &strentries[190]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "TYPE_SFIXED64"), UPB_TABVALUE_INT_INIT(16), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_BYTES"), UPB_TABVALUE_INT_INIT(12), NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT64"), UPB_TABVALUE_INT_INIT(18), NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "TYPE_BOOL"), UPB_TABVALUE_INT_INIT(8), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "TYPE_GROUP"), UPB_TABVALUE_INT_INIT(10), NULL}, + {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "TYPE_SINT32"), UPB_TABVALUE_INT_INIT(17), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "CORD"), UPB_TABVALUE_INT_INIT(1), NULL}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "STRING"), UPB_TABVALUE_INT_INIT(0), &strentries[197]}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "STRING_PIECE"), UPB_TABVALUE_INT_INIT(2), NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "CODE_SIZE"), UPB_TABVALUE_INT_INIT(2), NULL}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "SPEED"), UPB_TABVALUE_INT_INIT(1), &strentries[203]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "LITE_RUNTIME"), UPB_TABVALUE_INT_INIT(3), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\047", "\000", "\000", "\000", "google.protobuf.SourceCodeInfo.Location"), UPB_TABVALUE_PTR_INIT(&msgs[17]), NULL}, + {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.UninterpretedOption"), UPB_TABVALUE_PTR_INIT(&msgs[18]), NULL}, + {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.FileDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[8]), NULL}, + {UPB_TABKEY_STR("\045", "\000", "\000", "\000", "google.protobuf.MethodDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[12]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\040", "\000", "\000", "\000", "google.protobuf.EnumValueOptions"), UPB_TABVALUE_PTR_INIT(&msgs[5]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "google.protobuf.DescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[0]), &strentries[228]}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.SourceCodeInfo"), UPB_TABVALUE_PTR_INIT(&msgs[16]), NULL}, + {UPB_TABKEY_STR("\051", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto.Type"), UPB_TABVALUE_PTR_INIT(&enums[1]), NULL}, + {UPB_TABKEY_STR("\056", "\000", "\000", "\000", "google.protobuf.DescriptorProto.ExtensionRange"), UPB_TABVALUE_PTR_INIT(&msgs[1]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\050", "\000", "\000", "\000", "google.protobuf.EnumValueDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[4]), NULL}, + {UPB_TABKEY_STR("\034", "\000", "\000", "\000", "google.protobuf.FieldOptions"), UPB_TABVALUE_PTR_INIT(&msgs[7]), NULL}, + {UPB_TABKEY_STR("\033", "\000", "\000", "\000", "google.protobuf.FileOptions"), UPB_TABVALUE_PTR_INIT(&msgs[10]), NULL}, + {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.EnumDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[2]), &strentries[233]}, + {UPB_TABKEY_STR("\052", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto.Label"), UPB_TABVALUE_PTR_INIT(&enums[0]), NULL}, + {UPB_TABKEY_STR("\046", "\000", "\000", "\000", "google.protobuf.ServiceDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[14]), NULL}, + {UPB_TABKEY_STR("\042", "\000", "\000", "\000", "google.protobuf.FieldOptions.CType"), UPB_TABVALUE_PTR_INIT(&enums[2]), &strentries[229]}, + {UPB_TABKEY_STR("\041", "\000", "\000", "\000", "google.protobuf.FileDescriptorSet"), UPB_TABVALUE_PTR_INIT(&msgs[9]), &strentries[235]}, + {UPB_TABKEY_STR("\033", "\000", "\000", "\000", "google.protobuf.EnumOptions"), UPB_TABVALUE_PTR_INIT(&msgs[3]), NULL}, + {UPB_TABKEY_STR("\044", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[6]), NULL}, + {UPB_TABKEY_STR("\050", "\000", "\000", "\000", "google.protobuf.FileOptions.OptimizeMode"), UPB_TABVALUE_PTR_INIT(&enums[3]), &strentries[221]}, + {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.ServiceOptions"), UPB_TABVALUE_PTR_INIT(&msgs[15]), NULL}, + {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.MessageOptions"), UPB_TABVALUE_PTR_INIT(&msgs[11]), NULL}, + {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "google.protobuf.MethodOptions"), UPB_TABVALUE_PTR_INIT(&msgs[13]), &strentries[226]}, + {UPB_TABKEY_STR("\054", "\000", "\000", "\000", "google.protobuf.UninterpretedOption.NamePart"), UPB_TABVALUE_PTR_INIT(&msgs[19]), NULL}, +}; + +static const upb_tabent intentries[14] = { + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[77]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[72]), NULL}, +}; + +static const upb_tabval arrays[232] = { + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[38]), + UPB_TABVALUE_PTR_INIT(&fields[16]), + UPB_TABVALUE_PTR_INIT(&fields[44]), + UPB_TABVALUE_PTR_INIT(&fields[9]), + UPB_TABVALUE_PTR_INIT(&fields[15]), + UPB_TABVALUE_PTR_INIT(&fields[14]), + UPB_TABVALUE_PTR_INIT(&fields[49]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[66]), + UPB_TABVALUE_PTR_INIT(&fields[8]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[40]), + UPB_TABVALUE_PTR_INIT(&fields[78]), + UPB_TABVALUE_PTR_INIT(&fields[50]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[1]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[37]), + UPB_TABVALUE_PTR_INIT(&fields[47]), + UPB_TABVALUE_PTR_INIT(&fields[52]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[41]), + UPB_TABVALUE_PTR_INIT(&fields[12]), + UPB_TABVALUE_PTR_INIT(&fields[46]), + UPB_TABVALUE_PTR_INIT(&fields[27]), + UPB_TABVALUE_PTR_INIT(&fields[69]), + UPB_TABVALUE_PTR_INIT(&fields[70]), + UPB_TABVALUE_PTR_INIT(&fields[4]), + UPB_TABVALUE_PTR_INIT(&fields[51]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[3]), + UPB_TABVALUE_PTR_INIT(&fields[58]), + UPB_TABVALUE_PTR_INIT(&fields[6]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[28]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[11]), + UPB_TABVALUE_PTR_INIT(&fields[79]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[34]), + UPB_TABVALUE_PTR_INIT(&fields[57]), + UPB_TABVALUE_PTR_INIT(&fields[5]), + UPB_TABVALUE_PTR_INIT(&fields[32]), + UPB_TABVALUE_PTR_INIT(&fields[10]), + UPB_TABVALUE_PTR_INIT(&fields[63]), + UPB_TABVALUE_PTR_INIT(&fields[13]), + UPB_TABVALUE_PTR_INIT(&fields[53]), + UPB_TABVALUE_PTR_INIT(&fields[64]), + UPB_TABVALUE_PTR_INIT(&fields[61]), + UPB_TABVALUE_PTR_INIT(&fields[80]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[17]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[26]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[25]), + UPB_TABVALUE_PTR_INIT(&fields[48]), + UPB_TABVALUE_PTR_INIT(&fields[24]), + UPB_TABVALUE_PTR_INIT(&fields[18]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[2]), + UPB_TABVALUE_PTR_INIT(&fields[23]), + UPB_TABVALUE_PTR_INIT(&fields[62]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[22]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[31]), + UPB_TABVALUE_PTR_INIT(&fields[45]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[39]), + UPB_TABVALUE_PTR_INIT(&fields[20]), + UPB_TABVALUE_PTR_INIT(&fields[56]), + UPB_TABVALUE_PTR_INIT(&fields[55]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[35]), + UPB_TABVALUE_PTR_INIT(&fields[33]), + UPB_TABVALUE_PTR_INIT(&fields[54]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[30]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[59]), + UPB_TABVALUE_PTR_INIT(&fields[65]), + UPB_TABVALUE_PTR_INIT(&fields[29]), + UPB_TABVALUE_PTR_INIT(&fields[68]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[36]), + UPB_TABVALUE_PTR_INIT(&fields[19]), + UPB_TABVALUE_PTR_INIT(&fields[60]), + UPB_TABVALUE_PTR_INIT(&fields[43]), + UPB_TABVALUE_PTR_INIT(&fields[7]), + UPB_TABVALUE_PTR_INIT(&fields[67]), + UPB_TABVALUE_PTR_INIT(&fields[0]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[42]), + UPB_TABVALUE_PTR_INIT(&fields[21]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT("LABEL_OPTIONAL"), + UPB_TABVALUE_PTR_INIT("LABEL_REQUIRED"), + UPB_TABVALUE_PTR_INIT("LABEL_REPEATED"), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT("TYPE_DOUBLE"), + UPB_TABVALUE_PTR_INIT("TYPE_FLOAT"), + UPB_TABVALUE_PTR_INIT("TYPE_INT64"), + UPB_TABVALUE_PTR_INIT("TYPE_UINT64"), + UPB_TABVALUE_PTR_INIT("TYPE_INT32"), + UPB_TABVALUE_PTR_INIT("TYPE_FIXED64"), + UPB_TABVALUE_PTR_INIT("TYPE_FIXED32"), + UPB_TABVALUE_PTR_INIT("TYPE_BOOL"), + UPB_TABVALUE_PTR_INIT("TYPE_STRING"), + UPB_TABVALUE_PTR_INIT("TYPE_GROUP"), + UPB_TABVALUE_PTR_INIT("TYPE_MESSAGE"), + UPB_TABVALUE_PTR_INIT("TYPE_BYTES"), + UPB_TABVALUE_PTR_INIT("TYPE_UINT32"), + UPB_TABVALUE_PTR_INIT("TYPE_ENUM"), + UPB_TABVALUE_PTR_INIT("TYPE_SFIXED32"), + UPB_TABVALUE_PTR_INIT("TYPE_SFIXED64"), + UPB_TABVALUE_PTR_INIT("TYPE_SINT32"), + UPB_TABVALUE_PTR_INIT("TYPE_SINT64"), + UPB_TABVALUE_PTR_INIT("STRING"), + UPB_TABVALUE_PTR_INIT("CORD"), + UPB_TABVALUE_PTR_INIT("STRING_PIECE"), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT("SPEED"), + UPB_TABVALUE_PTR_INIT("CODE_SIZE"), + UPB_TABVALUE_PTR_INIT("LITE_RUNTIME"), +}; + +static const upb_symtab symtab = UPB_SYMTAB_INIT(UPB_STRTABLE_INIT(24, 31, UPB_CTYPE_PTR, 5, &strentries[204]), &reftables[210], &reftables[211]); + +const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner) { + upb_symtab_ref(&symtab, owner); + return &symtab; +} + +#ifdef UPB_DEBUG_REFS +static upb_inttable reftables[212] = { + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), + UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), +}; +#endif + +/* +** XXX: The routines in this file that consume a string do not currently +** support having the string span buffers. In the future, as upb_sink and +** its buffering/sharing functionality evolve there should be an easy and +** idiomatic way of correctly handling this case. For now, we accept this +** limitation since we currently only parse descriptors from single strings. +*/ + + +#include +#include +#include + +/* upb_deflist is an internal-only dynamic array for storing a growing list of + * upb_defs. */ +typedef struct { + upb_def **defs; + size_t len; + size_t size; + bool owned; +} upb_deflist; + +/* We keep a stack of all the messages scopes we are currently in, as well as + * the top-level file scope. This is necessary to correctly qualify the + * definitions that are contained inside. "name" tracks the name of the + * message or package (a bare name -- not qualified by any enclosing scopes). */ +typedef struct { + char *name; + /* Index of the first def that is under this scope. For msgdefs, the + * msgdef itself is at start-1. */ + int start; +} upb_descreader_frame; + +/* The maximum number of nested declarations that are allowed, ie. + * message Foo { + * message Bar { + * message Baz { + * } + * } + * } + * + * This is a resource limit that affects how big our runtime stack can grow. + * TODO: make this a runtime-settable property of the Reader instance. */ +#define UPB_MAX_MESSAGE_NESTING 64 + +struct upb_descreader { + upb_sink sink; + upb_deflist defs; + upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING]; + int stack_len; + + uint32_t number; + char *name; + bool saw_number; + bool saw_name; + + char *default_string; + + upb_fielddef *f; +}; + +static char *upb_strndup(const char *buf, size_t n) { + char *ret = malloc(n + 1); + if (!ret) return NULL; + memcpy(ret, buf, n); + ret[n] = '\0'; + return ret; +} + +/* Returns a newly allocated string that joins input strings together, for + * example: + * join("Foo.Bar", "Baz") -> "Foo.Bar.Baz" + * join("", "Baz") -> "Baz" + * Caller owns a ref on the returned string. */ +static char *upb_join(const char *base, const char *name) { + if (!base || strlen(base) == 0) { + return upb_strdup(name); + } else { + char *ret = malloc(strlen(base) + strlen(name) + 2); + ret[0] = '\0'; + strcat(ret, base); + strcat(ret, "."); + strcat(ret, name); + return ret; + } +} + + +/* upb_deflist ****************************************************************/ + +void upb_deflist_init(upb_deflist *l) { + l->size = 0; + l->defs = NULL; + l->len = 0; + l->owned = true; +} + +void upb_deflist_uninit(upb_deflist *l) { + size_t i; + if (l->owned) + for(i = 0; i < l->len; i++) + upb_def_unref(l->defs[i], l); + free(l->defs); +} + +bool upb_deflist_push(upb_deflist *l, upb_def *d) { + if(++l->len >= l->size) { + size_t new_size = UPB_MAX(l->size, 4); + new_size *= 2; + l->defs = realloc(l->defs, new_size * sizeof(void *)); + if (!l->defs) return false; + l->size = new_size; + } + l->defs[l->len - 1] = d; + return true; +} + +void upb_deflist_donaterefs(upb_deflist *l, void *owner) { + size_t i; + assert(l->owned); + for (i = 0; i < l->len; i++) + upb_def_donateref(l->defs[i], l, owner); + l->owned = false; +} + +static upb_def *upb_deflist_last(upb_deflist *l) { + return l->defs[l->len-1]; +} + +/* Qualify the defname for all defs starting with offset "start" with "str". */ +static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) { + uint32_t i; + for (i = start; i < l->len; i++) { + upb_def *def = l->defs[i]; + char *name = upb_join(str, upb_def_fullname(def)); + upb_def_setfullname(def, name, NULL); + free(name); + } +} + + +/* upb_descreader ************************************************************/ + +static upb_msgdef *upb_descreader_top(upb_descreader *r) { + int index; + assert(r->stack_len > 1); + index = r->stack[r->stack_len-1].start - 1; + assert(index >= 0); + return upb_downcast_msgdef_mutable(r->defs.defs[index]); +} + +static upb_def *upb_descreader_last(upb_descreader *r) { + return upb_deflist_last(&r->defs); +} + +/* Start/end handlers for FileDescriptorProto and DescriptorProto (the two + * entities that have names and can contain sub-definitions. */ +void upb_descreader_startcontainer(upb_descreader *r) { + upb_descreader_frame *f = &r->stack[r->stack_len++]; + f->start = r->defs.len; + f->name = NULL; +} + +void upb_descreader_endcontainer(upb_descreader *r) { + upb_descreader_frame *f = &r->stack[--r->stack_len]; + upb_deflist_qualify(&r->defs, f->name, f->start); + free(f->name); + f->name = NULL; +} + +void upb_descreader_setscopename(upb_descreader *r, char *str) { + upb_descreader_frame *f = &r->stack[r->stack_len-1]; + free(f->name); + f->name = str; +} + +/* Handlers for google.protobuf.FileDescriptorProto. */ +static bool file_startmsg(void *r, const void *hd) { + UPB_UNUSED(hd); + upb_descreader_startcontainer(r); + return true; +} + +static bool file_endmsg(void *closure, const void *hd, upb_status *status) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + UPB_UNUSED(status); + upb_descreader_endcontainer(r); + return true; +} + +static size_t file_onpackage(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + UPB_UNUSED(handle); + /* XXX: see comment at the top of the file. */ + upb_descreader_setscopename(r, upb_strndup(buf, n)); + return n; +} + +/* Handlers for google.protobuf.EnumValueDescriptorProto. */ +static bool enumval_startmsg(void *closure, const void *hd) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + r->saw_number = false; + r->saw_name = false; + return true; +} + +static size_t enumval_onname(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + UPB_UNUSED(handle); + /* XXX: see comment at the top of the file. */ + free(r->name); + r->name = upb_strndup(buf, n); + r->saw_name = true; + return n; +} + +static bool enumval_onnumber(void *closure, const void *hd, int32_t val) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + r->number = val; + r->saw_number = true; + return true; +} + +static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) { + upb_descreader *r = closure; + upb_enumdef *e; + UPB_UNUSED(hd); + + if(!r->saw_number || !r->saw_name) { + upb_status_seterrmsg(status, "Enum value missing name or number."); + return false; + } + e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); + upb_enumdef_addval(e, r->name, r->number, status); + free(r->name); + r->name = NULL; + return true; +} + + +/* Handlers for google.protobuf.EnumDescriptorProto. */ +static bool enum_startmsg(void *closure, const void *hd) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + upb_deflist_push(&r->defs, + upb_enumdef_upcast_mutable(upb_enumdef_new(&r->defs))); + return true; +} + +static bool enum_endmsg(void *closure, const void *hd, upb_status *status) { + upb_descreader *r = closure; + upb_enumdef *e; + UPB_UNUSED(hd); + + e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); + if (upb_def_fullname(upb_descreader_last(r)) == NULL) { + upb_status_seterrmsg(status, "Enum had no name."); + return false; + } + if (upb_enumdef_numvals(e) == 0) { + upb_status_seterrmsg(status, "Enum had no values."); + return false; + } + return true; +} + +static size_t enum_onname(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + char *fullname = upb_strndup(buf, n); + UPB_UNUSED(hd); + UPB_UNUSED(handle); + /* XXX: see comment at the top of the file. */ + upb_def_setfullname(upb_descreader_last(r), fullname, NULL); + free(fullname); + return n; +} + +/* Handlers for google.protobuf.FieldDescriptorProto */ +static bool field_startmsg(void *closure, const void *hd) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + r->f = upb_fielddef_new(&r->defs); + free(r->default_string); + r->default_string = NULL; + + /* fielddefs default to packed, but descriptors default to non-packed. */ + upb_fielddef_setpacked(r->f, false); + return true; +} + +/* Converts the default value in string "str" into "d". Passes a ref on str. + * Returns true on success. */ +static bool parse_default(char *str, upb_fielddef *f) { + bool success = true; + char *end; + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: { + long val = strtol(str, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultint32(f, val); + break; + } + case UPB_TYPE_INT64: { + /* XXX: Need to write our own strtoll, since it's not available in c89. */ + long long val = strtol(str, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultint64(f, val); + break; + } + case UPB_TYPE_UINT32: { + unsigned long val = strtoul(str, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultuint32(f, val); + break; + } + case UPB_TYPE_UINT64: { + /* XXX: Need to write our own strtoull, since it's not available in c89. */ + unsigned long long val = strtoul(str, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultuint64(f, val); + break; + } + case UPB_TYPE_DOUBLE: { + double val = strtod(str, &end); + if (errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultdouble(f, val); + break; + } + case UPB_TYPE_FLOAT: { + /* XXX: Need to write our own strtof, since it's not available in c89. */ + float val = strtod(str, &end); + if (errno == ERANGE || *end) + success = false; + else + upb_fielddef_setdefaultfloat(f, val); + break; + } + case UPB_TYPE_BOOL: { + if (strcmp(str, "false") == 0) + upb_fielddef_setdefaultbool(f, false); + else if (strcmp(str, "true") == 0) + upb_fielddef_setdefaultbool(f, true); + else + success = false; + break; + } + default: abort(); + } + return success; +} + +static bool field_endmsg(void *closure, const void *hd, upb_status *status) { + upb_descreader *r = closure; + upb_fielddef *f = r->f; + UPB_UNUSED(hd); + + /* TODO: verify that all required fields were present. */ + assert(upb_fielddef_number(f) != 0); + assert(upb_fielddef_name(f) != NULL); + assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f)); + + if (r->default_string) { + if (upb_fielddef_issubmsg(f)) { + upb_status_seterrmsg(status, "Submessages cannot have defaults."); + return false; + } + if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) { + upb_fielddef_setdefaultcstr(f, r->default_string, NULL); + } else { + if (r->default_string && !parse_default(r->default_string, f)) { + /* We don't worry too much about giving a great error message since the + * compiler should have ensured this was correct. */ + upb_status_seterrmsg(status, "Error converting default value."); + return false; + } + } + } + return true; +} + +static bool field_onlazy(void *closure, const void *hd, bool val) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + + upb_fielddef_setlazy(r->f, val); + return true; +} + +static bool field_onpacked(void *closure, const void *hd, bool val) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + + upb_fielddef_setpacked(r->f, val); + return true; +} + +static bool field_ontype(void *closure, const void *hd, int32_t val) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + + upb_fielddef_setdescriptortype(r->f, val); + return true; +} + +static bool field_onlabel(void *closure, const void *hd, int32_t val) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + + upb_fielddef_setlabel(r->f, val); + return true; +} + +static bool field_onnumber(void *closure, const void *hd, int32_t val) { + upb_descreader *r = closure; + bool ok = upb_fielddef_setnumber(r->f, val, NULL); + UPB_UNUSED(hd); + + UPB_ASSERT_VAR(ok, ok); + return true; +} + +static size_t field_onname(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + char *name = upb_strndup(buf, n); + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + /* XXX: see comment at the top of the file. */ + upb_fielddef_setname(r->f, name, NULL); + free(name); + return n; +} + +static size_t field_ontypename(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + char *name = upb_strndup(buf, n); + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + /* XXX: see comment at the top of the file. */ + upb_fielddef_setsubdefname(r->f, name, NULL); + free(name); + return n; +} + +static size_t field_onextendee(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + char *name = upb_strndup(buf, n); + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + /* XXX: see comment at the top of the file. */ + upb_fielddef_setcontainingtypename(r->f, name, NULL); + free(name); + return n; +} + +static size_t field_ondefaultval(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + /* Have to convert from string to the correct type, but we might not know the + * type yet, so we save it as a string until the end of the field. + * XXX: see comment at the top of the file. */ + free(r->default_string); + r->default_string = upb_strndup(buf, n); + return n; +} + +/* Handlers for google.protobuf.DescriptorProto (representing a message). */ +static bool msg_startmsg(void *closure, const void *hd) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + + upb_deflist_push(&r->defs, + upb_msgdef_upcast_mutable(upb_msgdef_new(&r->defs))); + upb_descreader_startcontainer(r); + return true; +} + +static bool msg_endmsg(void *closure, const void *hd, upb_status *status) { + upb_descreader *r = closure; + upb_msgdef *m = upb_descreader_top(r); + UPB_UNUSED(hd); + + if(!upb_def_fullname(upb_msgdef_upcast_mutable(m))) { + upb_status_seterrmsg(status, "Encountered message with no name."); + return false; + } + upb_descreader_endcontainer(r); + return true; +} + +static size_t msg_onname(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + upb_msgdef *m = upb_descreader_top(r); + /* XXX: see comment at the top of the file. */ + char *name = upb_strndup(buf, n); + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + upb_def_setfullname(upb_msgdef_upcast_mutable(m), name, NULL); + upb_descreader_setscopename(r, name); /* Passes ownership of name. */ + return n; +} + +static bool msg_onendfield(void *closure, const void *hd) { + upb_descreader *r = closure; + upb_msgdef *m = upb_descreader_top(r); + UPB_UNUSED(hd); + + upb_msgdef_addfield(m, r->f, &r->defs, NULL); + r->f = NULL; + return true; +} + +static bool pushextension(void *closure, const void *hd) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + + assert(upb_fielddef_containingtypename(r->f)); + upb_fielddef_setisextension(r->f, true); + upb_deflist_push(&r->defs, upb_fielddef_upcast_mutable(r->f)); + r->f = NULL; + return true; +} + +#define D(name) upbdefs_google_protobuf_ ## name(s) + +static void reghandlers(const void *closure, upb_handlers *h) { + const upb_symtab *s = closure; + const upb_msgdef *m = upb_handlers_msgdef(h); + + if (m == D(DescriptorProto)) { + upb_handlers_setstartmsg(h, &msg_startmsg, NULL); + upb_handlers_setendmsg(h, &msg_endmsg, NULL); + upb_handlers_setstring(h, D(DescriptorProto_name), &msg_onname, NULL); + upb_handlers_setendsubmsg(h, D(DescriptorProto_field), &msg_onendfield, + NULL); + upb_handlers_setendsubmsg(h, D(DescriptorProto_extension), &pushextension, + NULL); + } else if (m == D(FileDescriptorProto)) { + upb_handlers_setstartmsg(h, &file_startmsg, NULL); + upb_handlers_setendmsg(h, &file_endmsg, NULL); + upb_handlers_setstring(h, D(FileDescriptorProto_package), &file_onpackage, + NULL); + upb_handlers_setendsubmsg(h, D(FileDescriptorProto_extension), &pushextension, + NULL); + } else if (m == D(EnumValueDescriptorProto)) { + upb_handlers_setstartmsg(h, &enumval_startmsg, NULL); + upb_handlers_setendmsg(h, &enumval_endmsg, NULL); + upb_handlers_setstring(h, D(EnumValueDescriptorProto_name), &enumval_onname, NULL); + upb_handlers_setint32(h, D(EnumValueDescriptorProto_number), &enumval_onnumber, + NULL); + } else if (m == D(EnumDescriptorProto)) { + upb_handlers_setstartmsg(h, &enum_startmsg, NULL); + upb_handlers_setendmsg(h, &enum_endmsg, NULL); + upb_handlers_setstring(h, D(EnumDescriptorProto_name), &enum_onname, NULL); + } else if (m == D(FieldDescriptorProto)) { + upb_handlers_setstartmsg(h, &field_startmsg, NULL); + upb_handlers_setendmsg(h, &field_endmsg, NULL); + upb_handlers_setint32(h, D(FieldDescriptorProto_type), &field_ontype, + NULL); + upb_handlers_setint32(h, D(FieldDescriptorProto_label), &field_onlabel, + NULL); + upb_handlers_setint32(h, D(FieldDescriptorProto_number), &field_onnumber, + NULL); + upb_handlers_setstring(h, D(FieldDescriptorProto_name), &field_onname, + NULL); + upb_handlers_setstring(h, D(FieldDescriptorProto_type_name), + &field_ontypename, NULL); + upb_handlers_setstring(h, D(FieldDescriptorProto_extendee), + &field_onextendee, NULL); + upb_handlers_setstring(h, D(FieldDescriptorProto_default_value), + &field_ondefaultval, NULL); + } else if (m == D(FieldOptions)) { + upb_handlers_setbool(h, D(FieldOptions_lazy), &field_onlazy, NULL); + upb_handlers_setbool(h, D(FieldOptions_packed), &field_onpacked, NULL); + } +} + +#undef D + +void descreader_cleanup(void *_r) { + upb_descreader *r = _r; + free(r->name); + upb_deflist_uninit(&r->defs); + free(r->default_string); + while (r->stack_len > 0) { + upb_descreader_frame *f = &r->stack[--r->stack_len]; + free(f->name); + } +} + + +/* Public API ****************************************************************/ + +upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) { + upb_descreader *r = upb_env_malloc(e, sizeof(upb_descreader)); + if (!r || !upb_env_addcleanup(e, descreader_cleanup, r)) { + return NULL; + } + + upb_deflist_init(&r->defs); + upb_sink_reset(upb_descreader_input(r), h, r); + r->stack_len = 0; + r->name = NULL; + r->default_string = NULL; + + return r; +} + +upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) { + *n = r->defs.len; + upb_deflist_donaterefs(&r->defs, owner); + return r->defs.defs; +} + +upb_sink *upb_descreader_input(upb_descreader *r) { + return &r->sink; +} + +const upb_handlers *upb_descreader_newhandlers(const void *owner) { + const upb_symtab *s = upbdefs_google_protobuf_descriptor(&s); + const upb_handlers *h = upb_handlers_newfrozen( + upbdefs_google_protobuf_FileDescriptorSet(s), owner, reghandlers, s); + upb_symtab_unref(s, &s); + return h; +} +/* +** protobuf decoder bytecode compiler +** +** Code to compile a upb::Handlers into bytecode for decoding a protobuf +** according to that specific schema and destination handlers. +** +** Compiling to bytecode is always the first step. If we are using the +** interpreted decoder we leave it as bytecode and interpret that. If we are +** using a JIT decoder we use a code generator to turn the bytecode into native +** code, LLVM IR, etc. +** +** Bytecode definition is in decoder.int.h. +*/ + +#include + +#ifdef UPB_DUMP_BYTECODE +#include +#endif + +#define MAXLABEL 5 +#define EMPTYLABEL -1 + +/* mgroup *********************************************************************/ + +static void freegroup(upb_refcounted *r) { + mgroup *g = (mgroup*)r; + upb_inttable_uninit(&g->methods); +#ifdef UPB_USE_JIT_X64 + upb_pbdecoder_freejit(g); +#endif + free(g->bytecode); + free(g); +} + +static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const mgroup *g = (const mgroup*)r; + upb_inttable_iter i; + upb_inttable_begin(&i, &g->methods); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); + visit(r, upb_pbdecodermethod_upcast(method), closure); + } +} + +mgroup *newgroup(const void *owner) { + mgroup *g = malloc(sizeof(*g)); + static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup}; + upb_refcounted_init(mgroup_upcast_mutable(g), &vtbl, owner); + upb_inttable_init(&g->methods, UPB_CTYPE_PTR); + g->bytecode = NULL; + g->bytecode_end = NULL; + return g; +} + + +/* upb_pbdecodermethod ********************************************************/ + +static void freemethod(upb_refcounted *r) { + upb_pbdecodermethod *method = (upb_pbdecodermethod*)r; + + if (method->dest_handlers_) { + upb_handlers_unref(method->dest_handlers_, method); + } + + upb_inttable_uninit(&method->dispatch); + free(method); +} + +static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const upb_pbdecodermethod *m = (const upb_pbdecodermethod*)r; + visit(r, m->group, closure); +} + +static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers, + mgroup *group) { + static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod}; + upb_pbdecodermethod *ret = malloc(sizeof(*ret)); + upb_refcounted_init(upb_pbdecodermethod_upcast_mutable(ret), &vtbl, &ret); + upb_byteshandler_init(&ret->input_handler_); + + /* The method references the group and vice-versa, in a circular reference. */ + upb_ref2(ret, group); + upb_ref2(group, ret); + upb_inttable_insertptr(&group->methods, dest_handlers, upb_value_ptr(ret)); + upb_pbdecodermethod_unref(ret, &ret); + + ret->group = mgroup_upcast_mutable(group); + ret->dest_handlers_ = dest_handlers; + ret->is_native_ = false; /* If we JIT, it will update this later. */ + upb_inttable_init(&ret->dispatch, UPB_CTYPE_UINT64); + + if (ret->dest_handlers_) { + upb_handlers_ref(ret->dest_handlers_, ret); + } + return ret; +} + +const upb_handlers *upb_pbdecodermethod_desthandlers( + const upb_pbdecodermethod *m) { + return m->dest_handlers_; +} + +const upb_byteshandler *upb_pbdecodermethod_inputhandler( + const upb_pbdecodermethod *m) { + return &m->input_handler_; +} + +bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m) { + return m->is_native_; +} + +const upb_pbdecodermethod *upb_pbdecodermethod_new( + const upb_pbdecodermethodopts *opts, const void *owner) { + const upb_pbdecodermethod *ret; + upb_pbcodecache cache; + + upb_pbcodecache_init(&cache); + ret = upb_pbcodecache_getdecodermethod(&cache, opts); + upb_pbdecodermethod_ref(ret, owner); + upb_pbcodecache_uninit(&cache); + return ret; +} + + +/* bytecode compiler **********************************************************/ + +/* Data used only at compilation time. */ +typedef struct { + mgroup *group; + + uint32_t *pc; + int fwd_labels[MAXLABEL]; + int back_labels[MAXLABEL]; + + /* For fields marked "lazy", parse them lazily or eagerly? */ + bool lazy; +} compiler; + +static compiler *newcompiler(mgroup *group, bool lazy) { + compiler *ret = malloc(sizeof(*ret)); + int i; + + ret->group = group; + ret->lazy = lazy; + for (i = 0; i < MAXLABEL; i++) { + ret->fwd_labels[i] = EMPTYLABEL; + ret->back_labels[i] = EMPTYLABEL; + } + return ret; +} + +static void freecompiler(compiler *c) { + free(c); +} + +const size_t ptr_words = sizeof(void*) / sizeof(uint32_t); + +/* How many words an instruction is. */ +static int instruction_len(uint32_t instr) { + switch (getop(instr)) { + case OP_SETDISPATCH: return 1 + ptr_words; + case OP_TAGN: return 3; + case OP_SETBIGGROUPNUM: return 2; + default: return 1; + } +} + +bool op_has_longofs(int32_t instruction) { + switch (getop(instruction)) { + case OP_CALL: + case OP_BRANCH: + case OP_CHECKDELIM: + return true; + /* The "tag" instructions only have 8 bytes available for the jump target, + * but that is ok because these opcodes only require short jumps. */ + case OP_TAG1: + case OP_TAG2: + case OP_TAGN: + return false; + default: + assert(false); + return false; + } +} + +static int32_t getofs(uint32_t instruction) { + if (op_has_longofs(instruction)) { + return (int32_t)instruction >> 8; + } else { + return (int8_t)(instruction >> 8); + } +} + +static void setofs(uint32_t *instruction, int32_t ofs) { + if (op_has_longofs(*instruction)) { + *instruction = getop(*instruction) | ofs << 8; + } else { + *instruction = (*instruction & ~0xff00) | ((ofs & 0xff) << 8); + } + assert(getofs(*instruction) == ofs); /* Would fail in cases of overflow. */ +} + +static uint32_t pcofs(compiler *c) { return c->pc - c->group->bytecode; } + +/* Defines a local label at the current PC location. All previous forward + * references are updated to point to this location. The location is noted + * for any future backward references. */ +static void label(compiler *c, unsigned int label) { + int val; + uint32_t *codep; + + assert(label < MAXLABEL); + val = c->fwd_labels[label]; + codep = (val == EMPTYLABEL) ? NULL : c->group->bytecode + val; + while (codep) { + int ofs = getofs(*codep); + setofs(codep, c->pc - codep - instruction_len(*codep)); + codep = ofs ? codep + ofs : NULL; + } + c->fwd_labels[label] = EMPTYLABEL; + c->back_labels[label] = pcofs(c); +} + +/* Creates a reference to a numbered label; either a forward reference + * (positive arg) or backward reference (negative arg). For forward references + * the value returned now is actually a "next" pointer into a linked list of all + * instructions that use this label and will be patched later when the label is + * defined with label(). + * + * The returned value is the offset that should be written into the instruction. + */ +static int32_t labelref(compiler *c, int label) { + assert(label < MAXLABEL); + if (label == LABEL_DISPATCH) { + /* No resolving required. */ + return 0; + } else if (label < 0) { + /* Backward local label. Relative to the next instruction. */ + uint32_t from = (c->pc + 1) - c->group->bytecode; + return c->back_labels[-label] - from; + } else { + /* Forward local label: prepend to (possibly-empty) linked list. */ + int *lptr = &c->fwd_labels[label]; + int32_t ret = (*lptr == EMPTYLABEL) ? 0 : *lptr - pcofs(c); + *lptr = pcofs(c); + return ret; + } +} + +static void put32(compiler *c, uint32_t v) { + mgroup *g = c->group; + if (c->pc == g->bytecode_end) { + int ofs = pcofs(c); + size_t oldsize = g->bytecode_end - g->bytecode; + size_t newsize = UPB_MAX(oldsize * 2, 64); + /* TODO(haberman): handle OOM. */ + g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t)); + g->bytecode_end = g->bytecode + newsize; + c->pc = g->bytecode + ofs; + } + *c->pc++ = v; +} + +static void putop(compiler *c, opcode op, ...) { + va_list ap; + va_start(ap, op); + + switch (op) { + case OP_SETDISPATCH: { + uintptr_t ptr = (uintptr_t)va_arg(ap, void*); + put32(c, OP_SETDISPATCH); + put32(c, ptr); + if (sizeof(uintptr_t) > sizeof(uint32_t)) + put32(c, (uint64_t)ptr >> 32); + break; + } + case OP_STARTMSG: + case OP_ENDMSG: + case OP_PUSHLENDELIM: + case OP_POP: + case OP_SETDELIM: + case OP_HALT: + case OP_RET: + case OP_DISPATCH: + put32(c, op); + break; + case OP_PARSE_DOUBLE: + case OP_PARSE_FLOAT: + case OP_PARSE_INT64: + case OP_PARSE_UINT64: + case OP_PARSE_INT32: + case OP_PARSE_FIXED64: + case OP_PARSE_FIXED32: + case OP_PARSE_BOOL: + case OP_PARSE_UINT32: + case OP_PARSE_SFIXED32: + case OP_PARSE_SFIXED64: + case OP_PARSE_SINT32: + case OP_PARSE_SINT64: + case OP_STARTSEQ: + case OP_ENDSEQ: + case OP_STARTSUBMSG: + case OP_ENDSUBMSG: + case OP_STARTSTR: + case OP_STRING: + case OP_ENDSTR: + case OP_PUSHTAGDELIM: + put32(c, op | va_arg(ap, upb_selector_t) << 8); + break; + case OP_SETBIGGROUPNUM: + put32(c, op); + put32(c, va_arg(ap, int)); + break; + case OP_CALL: { + const upb_pbdecodermethod *method = va_arg(ap, upb_pbdecodermethod *); + put32(c, op | (method->code_base.ofs - (pcofs(c) + 1)) << 8); + break; + } + case OP_CHECKDELIM: + case OP_BRANCH: { + uint32_t instruction = op; + int label = va_arg(ap, int); + setofs(&instruction, labelref(c, label)); + put32(c, instruction); + break; + } + case OP_TAG1: + case OP_TAG2: { + int label = va_arg(ap, int); + uint64_t tag = va_arg(ap, uint64_t); + uint32_t instruction = op | (tag << 16); + assert(tag <= 0xffff); + setofs(&instruction, labelref(c, label)); + put32(c, instruction); + break; + } + case OP_TAGN: { + int label = va_arg(ap, int); + uint64_t tag = va_arg(ap, uint64_t); + uint32_t instruction = op | (upb_value_size(tag) << 16); + setofs(&instruction, labelref(c, label)); + put32(c, instruction); + put32(c, tag); + put32(c, tag >> 32); + break; + } + } + + va_end(ap); +} + +#if defined(UPB_USE_JIT_X64) || defined(UPB_DUMP_BYTECODE) + +const char *upb_pbdecoder_getopname(unsigned int op) { +#define QUOTE(x) #x +#define EXPAND_AND_QUOTE(x) QUOTE(x) +#define OPNAME(x) OP_##x +#define OP(x) case OPNAME(x): return EXPAND_AND_QUOTE(OPNAME(x)); +#define T(x) OP(PARSE_##x) + /* Keep in sync with list in decoder.int.h. */ + switch ((opcode)op) { + T(DOUBLE) T(FLOAT) T(INT64) T(UINT64) T(INT32) T(FIXED64) T(FIXED32) + T(BOOL) T(UINT32) T(SFIXED32) T(SFIXED64) T(SINT32) T(SINT64) + OP(STARTMSG) OP(ENDMSG) OP(STARTSEQ) OP(ENDSEQ) OP(STARTSUBMSG) + OP(ENDSUBMSG) OP(STARTSTR) OP(STRING) OP(ENDSTR) OP(CALL) OP(RET) + OP(PUSHLENDELIM) OP(PUSHTAGDELIM) OP(SETDELIM) OP(CHECKDELIM) + OP(BRANCH) OP(TAG1) OP(TAG2) OP(TAGN) OP(SETDISPATCH) OP(POP) + OP(SETBIGGROUPNUM) OP(DISPATCH) OP(HALT) + } + return ""; +#undef OP +#undef T +} + +#endif + +#ifdef UPB_DUMP_BYTECODE + +static void dumpbc(uint32_t *p, uint32_t *end, FILE *f) { + + uint32_t *begin = p; + + while (p < end) { + fprintf(f, "%p %8tx", p, p - begin); + uint32_t instr = *p++; + uint8_t op = getop(instr); + fprintf(f, " %s", upb_pbdecoder_getopname(op)); + switch ((opcode)op) { + case OP_SETDISPATCH: { + const upb_inttable *dispatch; + memcpy(&dispatch, p, sizeof(void*)); + p += ptr_words; + const upb_pbdecodermethod *method = + (void *)((char *)dispatch - + offsetof(upb_pbdecodermethod, dispatch)); + fprintf(f, " %s", upb_msgdef_fullname( + upb_handlers_msgdef(method->dest_handlers_))); + break; + } + case OP_DISPATCH: + case OP_STARTMSG: + case OP_ENDMSG: + case OP_PUSHLENDELIM: + case OP_POP: + case OP_SETDELIM: + case OP_HALT: + case OP_RET: + break; + case OP_PARSE_DOUBLE: + case OP_PARSE_FLOAT: + case OP_PARSE_INT64: + case OP_PARSE_UINT64: + case OP_PARSE_INT32: + case OP_PARSE_FIXED64: + case OP_PARSE_FIXED32: + case OP_PARSE_BOOL: + case OP_PARSE_UINT32: + case OP_PARSE_SFIXED32: + case OP_PARSE_SFIXED64: + case OP_PARSE_SINT32: + case OP_PARSE_SINT64: + case OP_STARTSEQ: + case OP_ENDSEQ: + case OP_STARTSUBMSG: + case OP_ENDSUBMSG: + case OP_STARTSTR: + case OP_STRING: + case OP_ENDSTR: + case OP_PUSHTAGDELIM: + fprintf(f, " %d", instr >> 8); + break; + case OP_SETBIGGROUPNUM: + fprintf(f, " %d", *p++); + break; + case OP_CHECKDELIM: + case OP_CALL: + case OP_BRANCH: + fprintf(f, " =>0x%tx", p + getofs(instr) - begin); + break; + case OP_TAG1: + case OP_TAG2: { + fprintf(f, " tag:0x%x", instr >> 16); + if (getofs(instr)) { + fprintf(f, " =>0x%tx", p + getofs(instr) - begin); + } + break; + } + case OP_TAGN: { + uint64_t tag = *p++; + tag |= (uint64_t)*p++ << 32; + fprintf(f, " tag:0x%llx", (long long)tag); + fprintf(f, " n:%d", instr >> 16); + if (getofs(instr)) { + fprintf(f, " =>0x%tx", p + getofs(instr) - begin); + } + break; + } + } + fputs("\n", f); + } +} + +#endif + +static uint64_t get_encoded_tag(const upb_fielddef *f, int wire_type) { + uint32_t tag = (upb_fielddef_number(f) << 3) | wire_type; + uint64_t encoded_tag = upb_vencode32(tag); + /* No tag should be greater than 5 bytes. */ + assert(encoded_tag <= 0xffffffffff); + return encoded_tag; +} + +static void putchecktag(compiler *c, const upb_fielddef *f, + int wire_type, int dest) { + uint64_t tag = get_encoded_tag(f, wire_type); + switch (upb_value_size(tag)) { + case 1: + putop(c, OP_TAG1, dest, tag); + break; + case 2: + putop(c, OP_TAG2, dest, tag); + break; + default: + putop(c, OP_TAGN, dest, tag); + break; + } +} + +static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { + upb_selector_t selector; + bool ok = upb_handlers_getselector(f, type, &selector); + UPB_ASSERT_VAR(ok, ok); + return selector; +} + +/* Takes an existing, primary dispatch table entry and repacks it with a + * different alternate wire type. Called when we are inserting a secondary + * dispatch table entry for an alternate wire type. */ +static uint64_t repack(uint64_t dispatch, int new_wt2) { + uint64_t ofs; + uint8_t wt1; + uint8_t old_wt2; + upb_pbdecoder_unpackdispatch(dispatch, &ofs, &wt1, &old_wt2); + assert(old_wt2 == NO_WIRE_TYPE); /* wt2 should not be set yet. */ + return upb_pbdecoder_packdispatch(ofs, wt1, new_wt2); +} + +/* Marks the current bytecode position as the dispatch target for this message, + * field, and wire type. */ +static void dispatchtarget(compiler *c, upb_pbdecodermethod *method, + const upb_fielddef *f, int wire_type) { + /* Offset is relative to msg base. */ + uint64_t ofs = pcofs(c) - method->code_base.ofs; + uint32_t fn = upb_fielddef_number(f); + upb_inttable *d = &method->dispatch; + upb_value v; + if (upb_inttable_remove(d, fn, &v)) { + /* TODO: prioritize based on packed setting in .proto file. */ + uint64_t repacked = repack(upb_value_getuint64(v), wire_type); + upb_inttable_insert(d, fn, upb_value_uint64(repacked)); + upb_inttable_insert(d, fn + UPB_MAX_FIELDNUMBER, upb_value_uint64(ofs)); + } else { + uint64_t val = upb_pbdecoder_packdispatch(ofs, wire_type, NO_WIRE_TYPE); + upb_inttable_insert(d, fn, upb_value_uint64(val)); + } +} + +static void putpush(compiler *c, const upb_fielddef *f) { + if (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) { + putop(c, OP_PUSHLENDELIM); + } else { + uint32_t fn = upb_fielddef_number(f); + if (fn >= 1 << 24) { + putop(c, OP_PUSHTAGDELIM, 0); + putop(c, OP_SETBIGGROUPNUM, fn); + } else { + putop(c, OP_PUSHTAGDELIM, fn); + } + } +} + +static upb_pbdecodermethod *find_submethod(const compiler *c, + const upb_pbdecodermethod *method, + const upb_fielddef *f) { + const upb_handlers *sub = + upb_handlers_getsubhandlers(method->dest_handlers_, f); + upb_value v; + return upb_inttable_lookupptr(&c->group->methods, sub, &v) + ? upb_value_getptr(v) + : NULL; +} + +static void putsel(compiler *c, opcode op, upb_selector_t sel, + const upb_handlers *h) { + if (upb_handlers_gethandler(h, sel)) { + putop(c, op, sel); + } +} + +/* Puts an opcode to call a callback, but only if a callback actually exists for + * this field and handler type. */ +static void maybeput(compiler *c, opcode op, const upb_handlers *h, + const upb_fielddef *f, upb_handlertype_t type) { + putsel(c, op, getsel(f, type), h); +} + +static bool haslazyhandlers(const upb_handlers *h, const upb_fielddef *f) { + if (!upb_fielddef_lazy(f)) + return false; + + return upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STARTSTR)) || + upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_STRING)) || + upb_handlers_gethandler(h, getsel(f, UPB_HANDLER_ENDSTR)); +} + + +/* bytecode compiler code generation ******************************************/ + +/* Symbolic names for our local labels. */ +#define LABEL_LOOPSTART 1 /* Top of a repeated field loop. */ +#define LABEL_LOOPBREAK 2 /* To jump out of a repeated loop */ +#define LABEL_FIELD 3 /* Jump backward to find the most recent field. */ +#define LABEL_ENDMSG 4 /* To reach the OP_ENDMSG instr for this msg. */ + +/* Generates bytecode to parse a single non-lazy message field. */ +static void generate_msgfield(compiler *c, const upb_fielddef *f, + upb_pbdecodermethod *method) { + const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); + const upb_pbdecodermethod *sub_m = find_submethod(c, method, f); + int wire_type; + + if (!sub_m) { + /* Don't emit any code for this field at all; it will be parsed as an + * unknown field. */ + return; + } + + label(c, LABEL_FIELD); + + wire_type = + (upb_fielddef_descriptortype(f) == UPB_DESCRIPTOR_TYPE_MESSAGE) + ? UPB_WIRE_TYPE_DELIMITED + : UPB_WIRE_TYPE_START_GROUP; + + if (upb_fielddef_isseq(f)) { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, wire_type, LABEL_DISPATCH); + dispatchtarget(c, method, f, wire_type); + putop(c, OP_PUSHTAGDELIM, 0); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); + label(c, LABEL_LOOPSTART); + putpush(c, f); + putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); + putop(c, OP_CALL, sub_m); + putop(c, OP_POP); + maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG); + if (wire_type == UPB_WIRE_TYPE_DELIMITED) { + putop(c, OP_SETDELIM); + } + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putchecktag(c, f, wire_type, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + label(c, LABEL_LOOPBREAK); + putop(c, OP_POP); + maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); + } else { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, wire_type, LABEL_DISPATCH); + dispatchtarget(c, method, f, wire_type); + putpush(c, f); + putop(c, OP_STARTSUBMSG, getsel(f, UPB_HANDLER_STARTSUBMSG)); + putop(c, OP_CALL, sub_m); + putop(c, OP_POP); + maybeput(c, OP_ENDSUBMSG, h, f, UPB_HANDLER_ENDSUBMSG); + if (wire_type == UPB_WIRE_TYPE_DELIMITED) { + putop(c, OP_SETDELIM); + } + } +} + +/* Generates bytecode to parse a single string or lazy submessage field. */ +static void generate_delimfield(compiler *c, const upb_fielddef *f, + upb_pbdecodermethod *method) { + const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); + + label(c, LABEL_FIELD); + if (upb_fielddef_isseq(f)) { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); + dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); + putop(c, OP_PUSHTAGDELIM, 0); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); + label(c, LABEL_LOOPSTART); + putop(c, OP_PUSHLENDELIM); + putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); + /* Need to emit even if no handler to skip past the string. */ + putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); + putop(c, OP_POP); + maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR); + putop(c, OP_SETDELIM); + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + label(c, LABEL_LOOPBREAK); + putop(c, OP_POP); + maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); + } else { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); + dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); + putop(c, OP_PUSHLENDELIM); + putop(c, OP_STARTSTR, getsel(f, UPB_HANDLER_STARTSTR)); + putop(c, OP_STRING, getsel(f, UPB_HANDLER_STRING)); + putop(c, OP_POP); + maybeput(c, OP_ENDSTR, h, f, UPB_HANDLER_ENDSTR); + putop(c, OP_SETDELIM); + } +} + +/* Generates bytecode to parse a single primitive field. */ +static void generate_primitivefield(compiler *c, const upb_fielddef *f, + upb_pbdecodermethod *method) { + const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); + upb_descriptortype_t descriptor_type = upb_fielddef_descriptortype(f); + opcode parse_type; + upb_selector_t sel; + int wire_type; + + label(c, LABEL_FIELD); + + /* From a decoding perspective, ENUM is the same as INT32. */ + if (descriptor_type == UPB_DESCRIPTOR_TYPE_ENUM) + descriptor_type = UPB_DESCRIPTOR_TYPE_INT32; + + parse_type = (opcode)descriptor_type; + + /* TODO(haberman): generate packed or non-packed first depending on "packed" + * setting in the fielddef. This will favor (in speed) whichever was + * specified. */ + + assert((int)parse_type >= 0 && parse_type <= OP_MAX); + sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); + wire_type = upb_pb_native_wire_types[upb_fielddef_descriptortype(f)]; + if (upb_fielddef_isseq(f)) { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, UPB_WIRE_TYPE_DELIMITED, LABEL_DISPATCH); + dispatchtarget(c, method, f, UPB_WIRE_TYPE_DELIMITED); + putop(c, OP_PUSHLENDELIM); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Packed */ + label(c, LABEL_LOOPSTART); + putop(c, parse_type, sel); + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + dispatchtarget(c, method, f, wire_type); + putop(c, OP_PUSHTAGDELIM, 0); + putop(c, OP_STARTSEQ, getsel(f, UPB_HANDLER_STARTSEQ)); /* Non-packed */ + label(c, LABEL_LOOPSTART); + putop(c, parse_type, sel); + putop(c, OP_CHECKDELIM, LABEL_LOOPBREAK); + putchecktag(c, f, wire_type, LABEL_LOOPBREAK); + putop(c, OP_BRANCH, -LABEL_LOOPSTART); + label(c, LABEL_LOOPBREAK); + putop(c, OP_POP); /* Packed and non-packed join. */ + maybeput(c, OP_ENDSEQ, h, f, UPB_HANDLER_ENDSEQ); + putop(c, OP_SETDELIM); /* Could remove for non-packed by dup ENDSEQ. */ + } else { + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + putchecktag(c, f, wire_type, LABEL_DISPATCH); + dispatchtarget(c, method, f, wire_type); + putop(c, parse_type, sel); + } +} + +/* Adds bytecode for parsing the given message to the given decoderplan, + * while adding all dispatch targets to this message's dispatch table. */ +static void compile_method(compiler *c, upb_pbdecodermethod *method) { + const upb_handlers *h; + const upb_msgdef *md; + uint32_t* start_pc; + upb_msg_field_iter i; + upb_value val; + + assert(method); + + /* Clear all entries in the dispatch table. */ + upb_inttable_uninit(&method->dispatch); + upb_inttable_init(&method->dispatch, UPB_CTYPE_UINT64); + + h = upb_pbdecodermethod_desthandlers(method); + md = upb_handlers_msgdef(h); + + method->code_base.ofs = pcofs(c); + putop(c, OP_SETDISPATCH, &method->dispatch); + putsel(c, OP_STARTMSG, UPB_STARTMSG_SELECTOR, h); + label(c, LABEL_FIELD); + start_pc = c->pc; + for(upb_msg_field_begin(&i, md); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + const upb_fielddef *f = upb_msg_iter_field(&i); + upb_fieldtype_t type = upb_fielddef_type(f); + + if (type == UPB_TYPE_MESSAGE && !(haslazyhandlers(h, f) && c->lazy)) { + generate_msgfield(c, f, method); + } else if (type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES || + type == UPB_TYPE_MESSAGE) { + generate_delimfield(c, f, method); + } else { + generate_primitivefield(c, f, method); + } + } + + /* If there were no fields, or if no handlers were defined, we need to + * generate a non-empty loop body so that we can at least dispatch for unknown + * fields and check for the end of the message. */ + if (c->pc == start_pc) { + /* Check for end-of-message. */ + putop(c, OP_CHECKDELIM, LABEL_ENDMSG); + /* Unconditionally dispatch. */ + putop(c, OP_DISPATCH, 0); + } + + /* For now we just loop back to the last field of the message (or if none, + * the DISPATCH opcode for the message). */ + putop(c, OP_BRANCH, -LABEL_FIELD); + + /* Insert both a label and a dispatch table entry for this end-of-msg. */ + label(c, LABEL_ENDMSG); + val = upb_value_uint64(pcofs(c) - method->code_base.ofs); + upb_inttable_insert(&method->dispatch, DISPATCH_ENDMSG, val); + + putsel(c, OP_ENDMSG, UPB_ENDMSG_SELECTOR, h); + putop(c, OP_RET); + + upb_inttable_compact(&method->dispatch); +} + +/* Populate "methods" with new upb_pbdecodermethod objects reachable from "h". + * Returns the method for these handlers. + * + * Generates a new method for every destination handlers reachable from "h". */ +static void find_methods(compiler *c, const upb_handlers *h) { + upb_value v; + upb_msg_field_iter i; + const upb_msgdef *md; + + if (upb_inttable_lookupptr(&c->group->methods, h, &v)) + return; + newmethod(h, c->group); + + /* Find submethods. */ + md = upb_handlers_msgdef(h); + for(upb_msg_field_begin(&i, md); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + const upb_fielddef *f = upb_msg_iter_field(&i); + const upb_handlers *sub_h; + if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE && + (sub_h = upb_handlers_getsubhandlers(h, f)) != NULL) { + /* We only generate a decoder method for submessages with handlers. + * Others will be parsed as unknown fields. */ + find_methods(c, sub_h); + } + } +} + +/* (Re-)compile bytecode for all messages in "msgs." + * Overwrites any existing bytecode in "c". */ +static void compile_methods(compiler *c) { + upb_inttable_iter i; + + /* Start over at the beginning of the bytecode. */ + c->pc = c->group->bytecode; + + upb_inttable_begin(&i, &c->group->methods); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *method = upb_value_getptr(upb_inttable_iter_value(&i)); + compile_method(c, method); + } +} + +static void set_bytecode_handlers(mgroup *g) { + upb_inttable_iter i; + upb_inttable_begin(&i, &g->methods); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + upb_pbdecodermethod *m = upb_value_getptr(upb_inttable_iter_value(&i)); + upb_byteshandler *h = &m->input_handler_; + + m->code_base.ptr = g->bytecode + m->code_base.ofs; + + upb_byteshandler_setstartstr(h, upb_pbdecoder_startbc, m->code_base.ptr); + upb_byteshandler_setstring(h, upb_pbdecoder_decode, g); + upb_byteshandler_setendstr(h, upb_pbdecoder_end, m); + } +} + + +/* JIT setup. *****************************************************************/ + +#ifdef UPB_USE_JIT_X64 + +static void sethandlers(mgroup *g, bool allowjit) { + g->jit_code = NULL; + if (allowjit) { + /* Compile byte-code into machine code, create handlers. */ + upb_pbdecoder_jit(g); + } else { + set_bytecode_handlers(g); + } +} + +#else /* UPB_USE_JIT_X64 */ + +static void sethandlers(mgroup *g, bool allowjit) { + /* No JIT compiled in; use bytecode handlers unconditionally. */ + UPB_UNUSED(allowjit); + set_bytecode_handlers(g); +} + +#endif /* UPB_USE_JIT_X64 */ + + +/* TODO(haberman): allow this to be constructed for an arbitrary set of dest + * handlers and other mgroups (but verify we have a transitive closure). */ +const mgroup *mgroup_new(const upb_handlers *dest, bool allowjit, bool lazy, + const void *owner) { + mgroup *g; + compiler *c; + + UPB_UNUSED(allowjit); + assert(upb_handlers_isfrozen(dest)); + + g = newgroup(owner); + c = newcompiler(g, lazy); + find_methods(c, dest); + + /* We compile in two passes: + * 1. all messages are assigned relative offsets from the beginning of the + * bytecode (saved in method->code_base). + * 2. forwards OP_CALL instructions can be correctly linked since message + * offsets have been previously assigned. + * + * Could avoid the second pass by linking OP_CALL instructions somehow. */ + compile_methods(c); + compile_methods(c); + g->bytecode_end = c->pc; + freecompiler(c); + +#ifdef UPB_DUMP_BYTECODE + { + FILE *f = fopen("/tmp/upb-bytecode", "wb"); + assert(f); + dumpbc(g->bytecode, g->bytecode_end, stderr); + dumpbc(g->bytecode, g->bytecode_end, f); + fclose(f); + } +#endif + + sethandlers(g, allowjit); + return g; +} + + +/* upb_pbcodecache ************************************************************/ + +void upb_pbcodecache_init(upb_pbcodecache *c) { + upb_inttable_init(&c->groups, UPB_CTYPE_CONSTPTR); + c->allow_jit_ = true; +} + +void upb_pbcodecache_uninit(upb_pbcodecache *c) { + upb_inttable_iter i; + upb_inttable_begin(&i, &c->groups); + for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + const mgroup *group = upb_value_getconstptr(upb_inttable_iter_value(&i)); + mgroup_unref(group, c); + } + upb_inttable_uninit(&c->groups); +} + +bool upb_pbcodecache_allowjit(const upb_pbcodecache *c) { + return c->allow_jit_; +} + +bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow) { + if (upb_inttable_count(&c->groups) > 0) + return false; + c->allow_jit_ = allow; + return true; +} + +const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod( + upb_pbcodecache *c, const upb_pbdecodermethodopts *opts) { + upb_value v; + bool ok; + + /* Right now we build a new DecoderMethod every time. + * TODO(haberman): properly cache methods by their true key. */ + const mgroup *g = mgroup_new(opts->handlers, c->allow_jit_, opts->lazy, c); + upb_inttable_push(&c->groups, upb_value_constptr(g)); + + ok = upb_inttable_lookupptr(&g->methods, opts->handlers, &v); + UPB_ASSERT_VAR(ok, ok); + return upb_value_getptr(v); +} + + +/* upb_pbdecodermethodopts ****************************************************/ + +void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts, + const upb_handlers *h) { + opts->handlers = h; + opts->lazy = false; +} + +void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy) { + opts->lazy = lazy; +} +/* +** upb::Decoder (Bytecode Decoder VM) +** +** Bytecode must previously have been generated using the bytecode compiler in +** compile_decoder.c. This decoder then walks through the bytecode op-by-op to +** parse the input. +** +** Decoding is fully resumable; we just keep a pointer to the current bytecode +** instruction and resume from there. A fair amount of the logic here is to +** handle the fact that values can span buffer seams and we have to be able to +** be capable of suspending/resuming from any byte in the stream. This +** sometimes requires keeping a few trailing bytes from the last buffer around +** in the "residual" buffer. +*/ + +#include +#include + +#ifdef UPB_DUMP_BYTECODE +#include +#endif + +#define CHECK_SUSPEND(x) if (!(x)) return upb_pbdecoder_suspend(d); + +/* Error messages that are shared between the bytecode and JIT decoders. */ +const char *kPbDecoderStackOverflow = "Nesting too deep."; +const char *kPbDecoderSubmessageTooLong = + "Submessage end extends past enclosing submessage."; + +/* Error messages shared within this file. */ +static const char *kUnterminatedVarint = "Unterminated varint."; + +/* upb_pbdecoder **************************************************************/ + +static opcode halt = OP_HALT; + +/* Whether an op consumes any of the input buffer. */ +static bool consumes_input(opcode op) { + switch (op) { + case OP_SETDISPATCH: + case OP_STARTMSG: + case OP_ENDMSG: + case OP_STARTSEQ: + case OP_ENDSEQ: + case OP_STARTSUBMSG: + case OP_ENDSUBMSG: + case OP_STARTSTR: + case OP_ENDSTR: + case OP_PUSHTAGDELIM: + case OP_POP: + case OP_SETDELIM: + case OP_SETBIGGROUPNUM: + case OP_CHECKDELIM: + case OP_CALL: + case OP_RET: + case OP_BRANCH: + return false; + default: + return true; + } +} + +static size_t stacksize(upb_pbdecoder *d, size_t entries) { + UPB_UNUSED(d); + return entries * sizeof(upb_pbdecoder_frame); +} + +static size_t callstacksize(upb_pbdecoder *d, size_t entries) { + UPB_UNUSED(d); + +#ifdef UPB_USE_JIT_X64 + if (d->method_->is_native_) { + /* Each native stack frame needs two pointers, plus we need a few frames for + * the enter/exit trampolines. */ + size_t ret = entries * sizeof(void*) * 2; + ret += sizeof(void*) * 10; + return ret; + } +#endif + + return entries * sizeof(uint32_t*); +} + + +static bool in_residual_buf(const upb_pbdecoder *d, const char *p); + +/* It's unfortunate that we have to micro-manage the compiler with + * UPB_FORCEINLINE and UPB_NOINLINE, especially since this tuning is necessarily + * specific to one hardware configuration. But empirically on a Core i7, + * performance increases 30-50% with these annotations. Every instance where + * these appear, gcc 4.2.1 made the wrong decision and degraded performance in + * benchmarks. */ + +static void seterr(upb_pbdecoder *d, const char *msg) { + upb_status status = UPB_STATUS_INIT; + upb_status_seterrmsg(&status, msg); + upb_env_reporterror(d->env, &status); +} + +void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg) { + seterr(d, msg); +} + + +/* Buffering ******************************************************************/ + +/* We operate on one buffer at a time, which is either the user's buffer passed + * to our "decode" callback or some residual bytes from the previous buffer. */ + +/* How many bytes can be safely read from d->ptr without reading past end-of-buf + * or past the current delimited end. */ +static size_t curbufleft(const upb_pbdecoder *d) { + assert(d->data_end >= d->ptr); + return d->data_end - d->ptr; +} + +/* How many bytes are available before end-of-buffer. */ +static size_t bufleft(const upb_pbdecoder *d) { + return d->end - d->ptr; +} + +/* Overall stream offset of d->ptr. */ +uint64_t offset(const upb_pbdecoder *d) { + return d->bufstart_ofs + (d->ptr - d->buf); +} + +/* How many bytes are available before the end of this delimited region. */ +size_t delim_remaining(const upb_pbdecoder *d) { + return d->top->end_ofs - offset(d); +} + +/* Advances d->ptr. */ +static void advance(upb_pbdecoder *d, size_t len) { + assert(curbufleft(d) >= len); + d->ptr += len; +} + +static bool in_buf(const char *p, const char *buf, const char *end) { + return p >= buf && p <= end; +} + +static bool in_residual_buf(const upb_pbdecoder *d, const char *p) { + return in_buf(p, d->residual, d->residual_end); +} + +/* Calculates the delim_end value, which is affected by both the current buffer + * and the parsing stack, so must be called whenever either is updated. */ +static void set_delim_end(upb_pbdecoder *d) { + size_t delim_ofs = d->top->end_ofs - d->bufstart_ofs; + if (delim_ofs <= (size_t)(d->end - d->buf)) { + d->delim_end = d->buf + delim_ofs; + d->data_end = d->delim_end; + } else { + d->data_end = d->end; + d->delim_end = NULL; + } +} + +static void switchtobuf(upb_pbdecoder *d, const char *buf, const char *end) { + d->ptr = buf; + d->buf = buf; + d->end = end; + set_delim_end(d); +} + +static void advancetobuf(upb_pbdecoder *d, const char *buf, size_t len) { + assert(curbufleft(d) == 0); + d->bufstart_ofs += (d->end - d->buf); + switchtobuf(d, buf, buf + len); +} + +static void checkpoint(upb_pbdecoder *d) { + /* The assertion here is in the interests of efficiency, not correctness. + * We are trying to ensure that we don't checkpoint() more often than + * necessary. */ + assert(d->checkpoint != d->ptr); + d->checkpoint = d->ptr; +} + +/* Skips "bytes" bytes in the stream, which may be more than available. If we + * skip more bytes than are available, we return a long read count to the caller + * indicating how many bytes can be skipped over before passing actual data + * again. Skipped bytes can pass a NULL buffer and the decoder guarantees they + * won't actually be read. + */ +static int32_t skip(upb_pbdecoder *d, size_t bytes) { + assert(!in_residual_buf(d, d->ptr) || d->size_param == 0); + assert(d->skip == 0); + if (bytes > delim_remaining(d)) { + seterr(d, "Skipped value extended beyond enclosing submessage."); + return upb_pbdecoder_suspend(d); + } else if (bufleft(d) > bytes) { + /* Skipped data is all in current buffer, and more is still available. */ + advance(d, bytes); + d->skip = 0; + return DECODE_OK; + } else { + /* Skipped data extends beyond currently available buffers. */ + d->pc = d->last; + d->skip = bytes - curbufleft(d); + d->bufstart_ofs += (d->end - d->buf); + d->residual_end = d->residual; + switchtobuf(d, d->residual, d->residual_end); + return d->size_param + d->skip; + } +} + + +/* Resumes the decoder from an initial state or from a previous suspend. */ +int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, + size_t size, const upb_bufhandle *handle) { + UPB_UNUSED(p); /* Useless; just for the benefit of the JIT. */ + + d->buf_param = buf; + d->size_param = size; + d->handle = handle; + + if (d->residual_end > d->residual) { + /* We have residual bytes from the last buffer. */ + assert(d->ptr == d->residual); + } else { + switchtobuf(d, buf, buf + size); + } + + d->checkpoint = d->ptr; + + if (d->skip) { + size_t skip_bytes = d->skip; + d->skip = 0; + CHECK_RETURN(skip(d, skip_bytes)); + d->checkpoint = d->ptr; + } + + if (!buf) { + /* NULL buf is ok if its entire span is covered by the "skip" above, but + * by this point we know that "skip" doesn't cover the buffer. */ + seterr(d, "Passed NULL buffer over non-skippable region."); + return upb_pbdecoder_suspend(d); + } + + if (d->top->groupnum < 0) { + CHECK_RETURN(upb_pbdecoder_skipunknown(d, -1, 0)); + d->checkpoint = d->ptr; + } + + return DECODE_OK; +} + +/* Suspends the decoder at the last checkpoint, without saving any residual + * bytes. If there are any unconsumed bytes, returns a short byte count. */ +size_t upb_pbdecoder_suspend(upb_pbdecoder *d) { + d->pc = d->last; + if (d->checkpoint == d->residual) { + /* Checkpoint was in residual buf; no user bytes were consumed. */ + d->ptr = d->residual; + return 0; + } else { + size_t consumed; + assert(!in_residual_buf(d, d->checkpoint)); + assert(d->buf == d->buf_param); + + consumed = d->checkpoint - d->buf; + d->bufstart_ofs += consumed; + d->residual_end = d->residual; + switchtobuf(d, d->residual, d->residual_end); + return consumed; + } +} + +/* Suspends the decoder at the last checkpoint, and saves any unconsumed + * bytes in our residual buffer. This is necessary if we need more user + * bytes to form a complete value, which might not be contiguous in the + * user's buffers. Always consumes all user bytes. */ +static size_t suspend_save(upb_pbdecoder *d) { + /* We hit end-of-buffer before we could parse a full value. + * Save any unconsumed bytes (if any) to the residual buffer. */ + d->pc = d->last; + + if (d->checkpoint == d->residual) { + /* Checkpoint was in residual buf; append user byte(s) to residual buf. */ + assert((d->residual_end - d->residual) + d->size_param <= + sizeof(d->residual)); + if (!in_residual_buf(d, d->ptr)) { + d->bufstart_ofs -= (d->residual_end - d->residual); + } + memcpy(d->residual_end, d->buf_param, d->size_param); + d->residual_end += d->size_param; + } else { + /* Checkpoint was in user buf; old residual bytes not needed. */ + size_t save; + assert(!in_residual_buf(d, d->checkpoint)); + + d->ptr = d->checkpoint; + save = curbufleft(d); + assert(save <= sizeof(d->residual)); + memcpy(d->residual, d->ptr, save); + d->residual_end = d->residual + save; + d->bufstart_ofs = offset(d); + } + + switchtobuf(d, d->residual, d->residual_end); + return d->size_param; +} + +/* Copies the next "bytes" bytes into "buf" and advances the stream. + * Requires that this many bytes are available in the current buffer. */ +UPB_FORCEINLINE static void consumebytes(upb_pbdecoder *d, void *buf, + size_t bytes) { + assert(bytes <= curbufleft(d)); + memcpy(buf, d->ptr, bytes); + advance(d, bytes); +} + +/* Slow path for getting the next "bytes" bytes, regardless of whether they are + * available in the current buffer or not. Returns a status code as described + * in decoder.int.h. */ +UPB_NOINLINE static int32_t getbytes_slow(upb_pbdecoder *d, void *buf, + size_t bytes) { + const size_t avail = curbufleft(d); + consumebytes(d, buf, avail); + bytes -= avail; + assert(bytes > 0); + if (in_residual_buf(d, d->ptr)) { + advancetobuf(d, d->buf_param, d->size_param); + } + if (curbufleft(d) >= bytes) { + consumebytes(d, (char *)buf + avail, bytes); + return DECODE_OK; + } else if (d->data_end == d->delim_end) { + seterr(d, "Submessage ended in the middle of a value or group"); + return upb_pbdecoder_suspend(d); + } else { + return suspend_save(d); + } +} + +/* Gets the next "bytes" bytes, regardless of whether they are available in the + * current buffer or not. Returns a status code as described in decoder.int.h. + */ +UPB_FORCEINLINE static int32_t getbytes(upb_pbdecoder *d, void *buf, + size_t bytes) { + if (curbufleft(d) >= bytes) { + /* Buffer has enough data to satisfy. */ + consumebytes(d, buf, bytes); + return DECODE_OK; + } else { + return getbytes_slow(d, buf, bytes); + } +} + +UPB_NOINLINE static size_t peekbytes_slow(upb_pbdecoder *d, void *buf, + size_t bytes) { + size_t ret = curbufleft(d); + memcpy(buf, d->ptr, ret); + if (in_residual_buf(d, d->ptr)) { + size_t copy = UPB_MIN(bytes - ret, d->size_param); + memcpy((char *)buf + ret, d->buf_param, copy); + ret += copy; + } + return ret; +} + +UPB_FORCEINLINE static size_t peekbytes(upb_pbdecoder *d, void *buf, + size_t bytes) { + if (curbufleft(d) >= bytes) { + memcpy(buf, d->ptr, bytes); + return bytes; + } else { + return peekbytes_slow(d, buf, bytes); + } +} + + +/* Decoding of wire types *****************************************************/ + +/* Slow path for decoding a varint from the current buffer position. + * Returns a status code as described in decoder.int.h. */ +UPB_NOINLINE int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, + uint64_t *u64) { + uint8_t byte = 0x80; + int bitpos; + *u64 = 0; + for(bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) { + int32_t ret = getbytes(d, &byte, 1); + if (ret >= 0) return ret; + *u64 |= (uint64_t)(byte & 0x7F) << bitpos; + } + if(bitpos == 70 && (byte & 0x80)) { + seterr(d, kUnterminatedVarint); + return upb_pbdecoder_suspend(d); + } + return DECODE_OK; +} + +/* Decodes a varint from the current buffer position. + * Returns a status code as described in decoder.int.h. */ +UPB_FORCEINLINE static int32_t decode_varint(upb_pbdecoder *d, uint64_t *u64) { + if (curbufleft(d) > 0 && !(*d->ptr & 0x80)) { + *u64 = *d->ptr; + advance(d, 1); + return DECODE_OK; + } else if (curbufleft(d) >= 10) { + /* Fast case. */ + upb_decoderet r = upb_vdecode_fast(d->ptr); + if (r.p == NULL) { + seterr(d, kUnterminatedVarint); + return upb_pbdecoder_suspend(d); + } + advance(d, r.p - d->ptr); + *u64 = r.val; + return DECODE_OK; + } else { + /* Slow case -- varint spans buffer seam. */ + return upb_pbdecoder_decode_varint_slow(d, u64); + } +} + +/* Decodes a 32-bit varint from the current buffer position. + * Returns a status code as described in decoder.int.h. */ +UPB_FORCEINLINE static int32_t decode_v32(upb_pbdecoder *d, uint32_t *u32) { + uint64_t u64; + int32_t ret = decode_varint(d, &u64); + if (ret >= 0) return ret; + if (u64 > UINT32_MAX) { + seterr(d, "Unterminated 32-bit varint"); + /* TODO(haberman) guarantee that this function return is >= 0 somehow, + * so we know this path will always be treated as error by our caller. + * Right now the size_t -> int32_t can overflow and produce negative values. + */ + *u32 = 0; + return upb_pbdecoder_suspend(d); + } + *u32 = u64; + return DECODE_OK; +} + +/* Decodes a fixed32 from the current buffer position. + * Returns a status code as described in decoder.int.h. + * TODO: proper byte swapping for big-endian machines. */ +UPB_FORCEINLINE static int32_t decode_fixed32(upb_pbdecoder *d, uint32_t *u32) { + return getbytes(d, u32, 4); +} + +/* Decodes a fixed64 from the current buffer position. + * Returns a status code as described in decoder.int.h. + * TODO: proper byte swapping for big-endian machines. */ +UPB_FORCEINLINE static int32_t decode_fixed64(upb_pbdecoder *d, uint64_t *u64) { + return getbytes(d, u64, 8); +} + +/* Non-static versions of the above functions. + * These are called by the JIT for fallback paths. */ +int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32) { + return decode_fixed32(d, u32); +} + +int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64) { + return decode_fixed64(d, u64); +} + +static double as_double(uint64_t n) { double d; memcpy(&d, &n, 8); return d; } +static float as_float(uint32_t n) { float f; memcpy(&f, &n, 4); return f; } + +/* Pushes a frame onto the decoder stack. */ +static bool decoder_push(upb_pbdecoder *d, uint64_t end) { + upb_pbdecoder_frame *fr = d->top; + + if (end > fr->end_ofs) { + seterr(d, kPbDecoderSubmessageTooLong); + return false; + } else if (fr == d->limit) { + seterr(d, kPbDecoderStackOverflow); + return false; + } + + fr++; + fr->end_ofs = end; + fr->dispatch = NULL; + fr->groupnum = 0; + d->top = fr; + return true; +} + +static bool pushtagdelim(upb_pbdecoder *d, uint32_t arg) { + /* While we expect to see an "end" tag (either ENDGROUP or a non-sequence + * field number) prior to hitting any enclosing submessage end, pushing our + * existing delim end prevents us from continuing to parse values from a + * corrupt proto that doesn't give us an END tag in time. */ + if (!decoder_push(d, d->top->end_ofs)) + return false; + d->top->groupnum = arg; + return true; +} + +/* Pops a frame from the decoder stack. */ +static void decoder_pop(upb_pbdecoder *d) { d->top--; } + +UPB_NOINLINE int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, + uint64_t expected) { + uint64_t data = 0; + size_t bytes = upb_value_size(expected); + size_t read = peekbytes(d, &data, bytes); + if (read == bytes && data == expected) { + /* Advance past matched bytes. */ + int32_t ok = getbytes(d, &data, read); + UPB_ASSERT_VAR(ok, ok < 0); + return DECODE_OK; + } else if (read < bytes && memcmp(&data, &expected, read) == 0) { + return suspend_save(d); + } else { + return DECODE_MISMATCH; + } +} + +int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum, + uint8_t wire_type) { + if (fieldnum >= 0) + goto have_tag; + + while (true) { + uint32_t tag; + CHECK_RETURN(decode_v32(d, &tag)); + wire_type = tag & 0x7; + fieldnum = tag >> 3; + +have_tag: + if (fieldnum == 0) { + seterr(d, "Saw invalid field number (0)"); + return upb_pbdecoder_suspend(d); + } + + /* TODO: deliver to unknown field callback. */ + switch (wire_type) { + case UPB_WIRE_TYPE_32BIT: + CHECK_RETURN(skip(d, 4)); + break; + case UPB_WIRE_TYPE_64BIT: + CHECK_RETURN(skip(d, 8)); + break; + case UPB_WIRE_TYPE_VARINT: { + uint64_t u64; + CHECK_RETURN(decode_varint(d, &u64)); + break; + } + case UPB_WIRE_TYPE_DELIMITED: { + uint32_t len; + CHECK_RETURN(decode_v32(d, &len)); + CHECK_RETURN(skip(d, len)); + break; + } + case UPB_WIRE_TYPE_START_GROUP: + CHECK_SUSPEND(pushtagdelim(d, -fieldnum)); + break; + case UPB_WIRE_TYPE_END_GROUP: + if (fieldnum == -d->top->groupnum) { + decoder_pop(d); + } else if (fieldnum == d->top->groupnum) { + return DECODE_ENDGROUP; + } else { + seterr(d, "Unmatched ENDGROUP tag."); + return upb_pbdecoder_suspend(d); + } + break; + default: + seterr(d, "Invalid wire type"); + return upb_pbdecoder_suspend(d); + } + + if (d->top->groupnum >= 0) { + return DECODE_OK; + } + + /* Unknown group -- continue looping over unknown fields. */ + checkpoint(d); + } +} + +static void goto_endmsg(upb_pbdecoder *d) { + upb_value v; + bool found = upb_inttable_lookup32(d->top->dispatch, DISPATCH_ENDMSG, &v); + UPB_ASSERT_VAR(found, found); + d->pc = d->top->base + upb_value_getuint64(v); +} + +/* Parses a tag and jumps to the corresponding bytecode instruction for this + * field. + * + * If the tag is unknown (or the wire type doesn't match), parses the field as + * unknown. If the tag is a valid ENDGROUP tag, jumps to the bytecode + * instruction for the end of message. */ +static int32_t dispatch(upb_pbdecoder *d) { + upb_inttable *dispatch = d->top->dispatch; + uint32_t tag; + uint8_t wire_type; + uint32_t fieldnum; + upb_value val; + int32_t retval; + + /* Decode tag. */ + CHECK_RETURN(decode_v32(d, &tag)); + wire_type = tag & 0x7; + fieldnum = tag >> 3; + + /* Lookup tag. Because of packed/non-packed compatibility, we have to + * check the wire type against two possibilities. */ + if (fieldnum != DISPATCH_ENDMSG && + upb_inttable_lookup32(dispatch, fieldnum, &val)) { + uint64_t v = upb_value_getuint64(val); + if (wire_type == (v & 0xff)) { + d->pc = d->top->base + (v >> 16); + return DECODE_OK; + } else if (wire_type == ((v >> 8) & 0xff)) { + bool found = + upb_inttable_lookup(dispatch, fieldnum + UPB_MAX_FIELDNUMBER, &val); + UPB_ASSERT_VAR(found, found); + d->pc = d->top->base + upb_value_getuint64(val); + return DECODE_OK; + } + } + + /* We have some unknown fields (or ENDGROUP) to parse. The DISPATCH or TAG + * bytecode that triggered this is preceded by a CHECKDELIM bytecode which + * we need to back up to, so that when we're done skipping unknown data we + * can re-check the delimited end. */ + d->last--; /* Necessary if we get suspended */ + d->pc = d->last; + assert(getop(*d->last) == OP_CHECKDELIM); + + /* Unknown field or ENDGROUP. */ + retval = upb_pbdecoder_skipunknown(d, fieldnum, wire_type); + + CHECK_RETURN(retval); + + if (retval == DECODE_ENDGROUP) { + goto_endmsg(d); + return DECODE_OK; + } + + return DECODE_OK; +} + +/* Callers know that the stack is more than one deep because the opcodes that + * call this only occur after PUSH operations. */ +upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) { + assert(d->top != d->stack); + return d->top - 1; +} + + +/* The main decoding loop *****************************************************/ + +/* The main decoder VM function. Uses traditional bytecode dispatch loop with a + * switch() statement. */ +size_t run_decoder_vm(upb_pbdecoder *d, const mgroup *group, + const upb_bufhandle* handle) { + +#define VMCASE(op, code) \ + case op: { code; if (consumes_input(op)) checkpoint(d); break; } +#define PRIMITIVE_OP(type, wt, name, convfunc, ctype) \ + VMCASE(OP_PARSE_ ## type, { \ + ctype val; \ + CHECK_RETURN(decode_ ## wt(d, &val)); \ + upb_sink_put ## name(&d->top->sink, arg, (convfunc)(val)); \ + }) + + while(1) { + int32_t instruction; + opcode op; + uint32_t arg; + int32_t longofs; + + d->last = d->pc; + instruction = *d->pc++; + op = getop(instruction); + arg = instruction >> 8; + longofs = arg; + assert(d->ptr != d->residual_end); + UPB_UNUSED(group); +#ifdef UPB_DUMP_BYTECODE + fprintf(stderr, "s_ofs=%d buf_ofs=%d data_rem=%d buf_rem=%d delim_rem=%d " + "%x %s (%d)\n", + (int)offset(d), + (int)(d->ptr - d->buf), + (int)(d->data_end - d->ptr), + (int)(d->end - d->ptr), + (int)((d->top->end_ofs - d->bufstart_ofs) - (d->ptr - d->buf)), + (int)(d->pc - 1 - group->bytecode), + upb_pbdecoder_getopname(op), + arg); +#endif + switch (op) { + /* Technically, we are losing data if we see a 32-bit varint that is not + * properly sign-extended. We could detect this and error about the data + * loss, but proto2 does not do this, so we pass. */ + PRIMITIVE_OP(INT32, varint, int32, int32_t, uint64_t) + PRIMITIVE_OP(INT64, varint, int64, int64_t, uint64_t) + PRIMITIVE_OP(UINT32, varint, uint32, uint32_t, uint64_t) + PRIMITIVE_OP(UINT64, varint, uint64, uint64_t, uint64_t) + PRIMITIVE_OP(FIXED32, fixed32, uint32, uint32_t, uint32_t) + PRIMITIVE_OP(FIXED64, fixed64, uint64, uint64_t, uint64_t) + PRIMITIVE_OP(SFIXED32, fixed32, int32, int32_t, uint32_t) + PRIMITIVE_OP(SFIXED64, fixed64, int64, int64_t, uint64_t) + PRIMITIVE_OP(BOOL, varint, bool, bool, uint64_t) + PRIMITIVE_OP(DOUBLE, fixed64, double, as_double, uint64_t) + PRIMITIVE_OP(FLOAT, fixed32, float, as_float, uint32_t) + PRIMITIVE_OP(SINT32, varint, int32, upb_zzdec_32, uint64_t) + PRIMITIVE_OP(SINT64, varint, int64, upb_zzdec_64, uint64_t) + + VMCASE(OP_SETDISPATCH, + d->top->base = d->pc - 1; + memcpy(&d->top->dispatch, d->pc, sizeof(void*)); + d->pc += sizeof(void*) / sizeof(uint32_t); + ) + VMCASE(OP_STARTMSG, + CHECK_SUSPEND(upb_sink_startmsg(&d->top->sink)); + ) + VMCASE(OP_ENDMSG, + CHECK_SUSPEND(upb_sink_endmsg(&d->top->sink, d->status)); + ) + VMCASE(OP_STARTSEQ, + upb_pbdecoder_frame *outer = outer_frame(d); + CHECK_SUSPEND(upb_sink_startseq(&outer->sink, arg, &d->top->sink)); + ) + VMCASE(OP_ENDSEQ, + CHECK_SUSPEND(upb_sink_endseq(&d->top->sink, arg)); + ) + VMCASE(OP_STARTSUBMSG, + upb_pbdecoder_frame *outer = outer_frame(d); + CHECK_SUSPEND(upb_sink_startsubmsg(&outer->sink, arg, &d->top->sink)); + ) + VMCASE(OP_ENDSUBMSG, + CHECK_SUSPEND(upb_sink_endsubmsg(&d->top->sink, arg)); + ) + VMCASE(OP_STARTSTR, + uint32_t len = delim_remaining(d); + upb_pbdecoder_frame *outer = outer_frame(d); + CHECK_SUSPEND(upb_sink_startstr(&outer->sink, arg, len, &d->top->sink)); + if (len == 0) { + d->pc++; /* Skip OP_STRING. */ + } + ) + VMCASE(OP_STRING, + uint32_t len = curbufleft(d); + size_t n = upb_sink_putstring(&d->top->sink, arg, d->ptr, len, handle); + if (n > len) { + if (n > delim_remaining(d)) { + seterr(d, "Tried to skip past end of string."); + return upb_pbdecoder_suspend(d); + } else { + int32_t ret = skip(d, n); + /* This shouldn't return DECODE_OK, because n > len. */ + assert(ret >= 0); + return ret; + } + } + advance(d, n); + if (n < len || d->delim_end == NULL) { + /* We aren't finished with this string yet. */ + d->pc--; /* Repeat OP_STRING. */ + if (n > 0) checkpoint(d); + return upb_pbdecoder_suspend(d); + } + ) + VMCASE(OP_ENDSTR, + CHECK_SUSPEND(upb_sink_endstr(&d->top->sink, arg)); + ) + VMCASE(OP_PUSHTAGDELIM, + CHECK_SUSPEND(pushtagdelim(d, arg)); + ) + VMCASE(OP_SETBIGGROUPNUM, + d->top->groupnum = *d->pc++; + ) + VMCASE(OP_POP, + assert(d->top > d->stack); + decoder_pop(d); + ) + VMCASE(OP_PUSHLENDELIM, + uint32_t len; + CHECK_RETURN(decode_v32(d, &len)); + CHECK_SUSPEND(decoder_push(d, offset(d) + len)); + set_delim_end(d); + ) + VMCASE(OP_SETDELIM, + set_delim_end(d); + ) + VMCASE(OP_CHECKDELIM, + /* We are guaranteed of this assert because we never allow ourselves to + * consume bytes beyond data_end, which covers delim_end when non-NULL. + */ + assert(!(d->delim_end && d->ptr > d->delim_end)); + if (d->ptr == d->delim_end) + d->pc += longofs; + ) + VMCASE(OP_CALL, + d->callstack[d->call_len++] = d->pc; + d->pc += longofs; + ) + VMCASE(OP_RET, + assert(d->call_len > 0); + d->pc = d->callstack[--d->call_len]; + ) + VMCASE(OP_BRANCH, + d->pc += longofs; + ) + VMCASE(OP_TAG1, + uint8_t expected; + CHECK_SUSPEND(curbufleft(d) > 0); + expected = (arg >> 8) & 0xff; + if (*d->ptr == expected) { + advance(d, 1); + } else { + int8_t shortofs; + badtag: + shortofs = arg; + if (shortofs == LABEL_DISPATCH) { + CHECK_RETURN(dispatch(d)); + } else { + d->pc += shortofs; + break; /* Avoid checkpoint(). */ + } + } + ) + VMCASE(OP_TAG2, + uint16_t expected; + CHECK_SUSPEND(curbufleft(d) > 0); + expected = (arg >> 8) & 0xffff; + if (curbufleft(d) >= 2) { + uint16_t actual; + memcpy(&actual, d->ptr, 2); + if (expected == actual) { + advance(d, 2); + } else { + goto badtag; + } + } else { + int32_t result = upb_pbdecoder_checktag_slow(d, expected); + if (result == DECODE_MISMATCH) goto badtag; + if (result >= 0) return result; + } + ) + VMCASE(OP_TAGN, { + uint64_t expected; + int32_t result; + memcpy(&expected, d->pc, 8); + d->pc += 2; + result = upb_pbdecoder_checktag_slow(d, expected); + if (result == DECODE_MISMATCH) goto badtag; + if (result >= 0) return result; + }) + VMCASE(OP_DISPATCH, { + CHECK_RETURN(dispatch(d)); + }) + VMCASE(OP_HALT, { + return d->size_param; + }) + } + } +} + + +/* BytesHandler handlers ******************************************************/ + +void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { + upb_pbdecoder *d = closure; + UPB_UNUSED(size_hint); + d->top->end_ofs = UINT64_MAX; + d->bufstart_ofs = 0; + d->call_len = 1; + d->callstack[0] = &halt; + d->pc = pc; + d->skip = 0; + return d; +} + +void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) { + upb_pbdecoder *d = closure; + UPB_UNUSED(hd); + UPB_UNUSED(size_hint); + d->top->end_ofs = UINT64_MAX; + d->bufstart_ofs = 0; + d->call_len = 0; + d->skip = 0; + return d; +} + +bool upb_pbdecoder_end(void *closure, const void *handler_data) { + upb_pbdecoder *d = closure; + const upb_pbdecodermethod *method = handler_data; + uint64_t end; + char dummy; + + if (d->residual_end > d->residual) { + seterr(d, "Unexpected EOF: decoder still has buffered unparsed data"); + return false; + } + + if (d->skip) { + seterr(d, "Unexpected EOF inside skipped data"); + return false; + } + + if (d->top->end_ofs != UINT64_MAX) { + seterr(d, "Unexpected EOF inside delimited string"); + return false; + } + + /* The user's end() call indicates that the message ends here. */ + end = offset(d); + d->top->end_ofs = end; + +#ifdef UPB_USE_JIT_X64 + if (method->is_native_) { + const mgroup *group = (const mgroup*)method->group; + if (d->top != d->stack) + d->stack->end_ofs = 0; + group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL); + } else +#endif + { + const uint32_t *p = d->pc; + d->stack->end_ofs = end; + /* Check the previous bytecode, but guard against beginning. */ + if (p != method->code_base.ptr) p--; + if (getop(*p) == OP_CHECKDELIM) { + /* Rewind from OP_TAG* to OP_CHECKDELIM. */ + assert(getop(*d->pc) == OP_TAG1 || + getop(*d->pc) == OP_TAG2 || + getop(*d->pc) == OP_TAGN || + getop(*d->pc) == OP_DISPATCH); + d->pc = p; + } + upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL); + } + + if (d->call_len != 0) { + seterr(d, "Unexpected EOF inside submessage or group"); + return false; + } + + return true; +} + +size_t upb_pbdecoder_decode(void *decoder, const void *group, const char *buf, + size_t size, const upb_bufhandle *handle) { + int32_t result = upb_pbdecoder_resume(decoder, NULL, buf, size, handle); + + if (result == DECODE_ENDGROUP) goto_endmsg(decoder); + CHECK_RETURN(result); + + return run_decoder_vm(decoder, group, handle); +} + + +/* Public API *****************************************************************/ + +void upb_pbdecoder_reset(upb_pbdecoder *d) { + d->top = d->stack; + d->top->groupnum = 0; + d->ptr = d->residual; + d->buf = d->residual; + d->end = d->residual; + d->residual_end = d->residual; +} + +upb_pbdecoder *upb_pbdecoder_create(upb_env *e, const upb_pbdecodermethod *m, + upb_sink *sink) { + const size_t default_max_nesting = 64; +#ifndef NDEBUG + size_t size_before = upb_env_bytesallocated(e); +#endif + + upb_pbdecoder *d = upb_env_malloc(e, sizeof(upb_pbdecoder)); + if (!d) return NULL; + + d->method_ = m; + d->callstack = upb_env_malloc(e, callstacksize(d, default_max_nesting)); + d->stack = upb_env_malloc(e, stacksize(d, default_max_nesting)); + if (!d->stack || !d->callstack) { + return NULL; + } + + d->env = e; + d->limit = d->stack + default_max_nesting - 1; + d->stack_size = default_max_nesting; + + upb_pbdecoder_reset(d); + upb_bytessink_reset(&d->input_, &m->input_handler_, d); + + assert(sink); + if (d->method_->dest_handlers_) { + if (sink->handlers != d->method_->dest_handlers_) + return NULL; + } + upb_sink_reset(&d->top->sink, sink->handlers, sink->closure); + + /* If this fails, increase the value in decoder.h. */ + assert(upb_env_bytesallocated(e) - size_before <= UPB_PB_DECODER_SIZE); + return d; +} + +uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d) { + return offset(d); +} + +const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) { + return d->method_; +} + +upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d) { + return &d->input_; +} + +size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d) { + return d->stack_size; +} + +bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max) { + assert(d->top >= d->stack); + + if (max < (size_t)(d->top - d->stack)) { + /* Can't set a limit smaller than what we are currently at. */ + return false; + } + + if (max > d->stack_size) { + /* Need to reallocate stack and callstack to accommodate. */ + size_t old_size = stacksize(d, d->stack_size); + size_t new_size = stacksize(d, max); + void *p = upb_env_realloc(d->env, d->stack, old_size, new_size); + if (!p) { + return false; + } + d->stack = p; + + old_size = callstacksize(d, d->stack_size); + new_size = callstacksize(d, max); + p = upb_env_realloc(d->env, d->callstack, old_size, new_size); + if (!p) { + return false; + } + d->callstack = p; + + d->stack_size = max; + } + + d->limit = d->stack + max - 1; + return true; +} +/* +** upb::Encoder +** +** Since we are implementing pure handlers (ie. without any out-of-band access +** to pre-computed lengths), we have to buffer all submessages before we can +** emit even their first byte. +** +** Not knowing the size of submessages also means we can't write a perfect +** zero-copy implementation, even with buffering. Lengths are stored as +** varints, which means that we don't know how many bytes to reserve for the +** length until we know what the length is. +** +** This leaves us with three main choices: +** +** 1. buffer all submessage data in a temporary buffer, then copy it exactly +** once into the output buffer. +** +** 2. attempt to buffer data directly into the output buffer, estimating how +** many bytes each length will take. When our guesses are wrong, use +** memmove() to grow or shrink the allotted space. +** +** 3. buffer directly into the output buffer, allocating a max length +** ahead-of-time for each submessage length. If we overallocated, we waste +** space, but no memcpy() or memmove() is required. This approach requires +** defining a maximum size for submessages and rejecting submessages that +** exceed that size. +** +** (2) and (3) have the potential to have better performance, but they are more +** complicated and subtle to implement: +** +** (3) requires making an arbitrary choice of the maximum message size; it +** wastes space when submessages are shorter than this and fails +** completely when they are longer. This makes it more finicky and +** requires configuration based on the input. It also makes it impossible +** to perfectly match the output of reference encoders that always use the +** optimal amount of space for each length. +** +** (2) requires guessing the the size upfront, and if multiple lengths are +** guessed wrong the minimum required number of memmove() operations may +** be complicated to compute correctly. Implemented properly, it may have +** a useful amortized or average cost, but more investigation is required +** to determine this and what the optimal algorithm is to achieve it. +** +** (1) makes you always pay for exactly one copy, but its implementation is +** the simplest and its performance is predictable. +** +** So for now, we implement (1) only. If we wish to optimize later, we should +** be able to do it without affecting users. +** +** The strategy is to buffer the segments of data that do *not* depend on +** unknown lengths in one buffer, and keep a separate buffer of segment pointers +** and lengths. When the top-level submessage ends, we can go beginning to end, +** alternating the writing of lengths with memcpy() of the rest of the data. +** At the top level though, no buffering is required. +*/ + + +#include + +/* The output buffer is divided into segments; a segment is a string of data + * that is "ready to go" -- it does not need any varint lengths inserted into + * the middle. The seams between segments are where varints will be inserted + * once they are known. + * + * We also use the concept of a "run", which is a range of encoded bytes that + * occur at a single submessage level. Every segment contains one or more runs. + * + * A segment can span messages. Consider: + * + * .--Submessage lengths---------. + * | | | + * | V V + * V | |--------------- | |----------------- + * Submessages: | |----------------------------------------------- + * Top-level msg: ------------------------------------------------------------ + * + * Segments: ----- ------------------- ----------------- + * Runs: *---- *--------------*--- *---------------- + * (* marks the start) + * + * Note that the top-level menssage is not in any segment because it does not + * have any length preceding it. + * + * A segment is only interrupted when another length needs to be inserted. So + * observe how the second segment spans both the inner submessage and part of + * the next enclosing message. */ +typedef struct { + uint32_t msglen; /* The length to varint-encode before this segment. */ + uint32_t seglen; /* Length of the segment. */ +} upb_pb_encoder_segment; + +struct upb_pb_encoder { + upb_env *env; + + /* Our input and output. */ + upb_sink input_; + upb_bytessink *output_; + + /* The "subclosure" -- used as the inner closure as part of the bytessink + * protocol. */ + void *subc; + + /* The output buffer and limit, and our current write position. "buf" + * initially points to "initbuf", but is dynamically allocated if we need to + * grow beyond the initial size. */ + char *buf, *ptr, *limit; + + /* The beginning of the current run, or undefined if we are at the top + * level. */ + char *runbegin; + + /* The list of segments we are accumulating. */ + upb_pb_encoder_segment *segbuf, *segptr, *seglimit; + + /* The stack of enclosing submessages. Each entry in the stack points to the + * segment where this submessage's length is being accumulated. */ + int *stack, *top, *stacklimit; + + /* Depth of startmsg/endmsg calls. */ + int depth; +}; + +/* low-level buffering ********************************************************/ + +/* Low-level functions for interacting with the output buffer. */ + +/* TODO(haberman): handle pushback */ +static void putbuf(upb_pb_encoder *e, const char *buf, size_t len) { + size_t n = upb_bytessink_putbuf(e->output_, e->subc, buf, len, NULL); + UPB_ASSERT_VAR(n, n == len); +} + +static upb_pb_encoder_segment *top(upb_pb_encoder *e) { + return &e->segbuf[*e->top]; +} + +/* Call to ensure that at least "bytes" bytes are available for writing at + * e->ptr. Returns false if the bytes could not be allocated. */ +static bool reserve(upb_pb_encoder *e, size_t bytes) { + if ((size_t)(e->limit - e->ptr) < bytes) { + /* Grow buffer. */ + char *new_buf; + size_t needed = bytes + (e->ptr - e->buf); + size_t old_size = e->limit - e->buf; + + size_t new_size = old_size; + + while (new_size < needed) { + new_size *= 2; + } + + new_buf = upb_env_realloc(e->env, e->buf, old_size, new_size); + + if (new_buf == NULL) { + return false; + } + + e->ptr = new_buf + (e->ptr - e->buf); + e->runbegin = new_buf + (e->runbegin - e->buf); + e->limit = new_buf + new_size; + e->buf = new_buf; + } + + return true; +} + +/* Call when "bytes" bytes have been writte at e->ptr. The caller *must* have + * previously called reserve() with at least this many bytes. */ +static void encoder_advance(upb_pb_encoder *e, size_t bytes) { + assert((size_t)(e->limit - e->ptr) >= bytes); + e->ptr += bytes; +} + +/* Call when all of the bytes for a handler have been written. Flushes the + * bytes if possible and necessary, returning false if this failed. */ +static bool commit(upb_pb_encoder *e) { + if (!e->top) { + /* We aren't inside a delimited region. Flush our accumulated bytes to + * the output. + * + * TODO(haberman): in the future we may want to delay flushing for + * efficiency reasons. */ + putbuf(e, e->buf, e->ptr - e->buf); + e->ptr = e->buf; + } + + return true; +} + +/* Writes the given bytes to the buffer, handling reserve/advance. */ +static bool encode_bytes(upb_pb_encoder *e, const void *data, size_t len) { + if (!reserve(e, len)) { + return false; + } + + memcpy(e->ptr, data, len); + encoder_advance(e, len); + return true; +} + +/* Finish the current run by adding the run totals to the segment and message + * length. */ +static void accumulate(upb_pb_encoder *e) { + size_t run_len; + assert(e->ptr >= e->runbegin); + run_len = e->ptr - e->runbegin; + e->segptr->seglen += run_len; + top(e)->msglen += run_len; + e->runbegin = e->ptr; +} + +/* Call to indicate the start of delimited region for which the full length is + * not yet known. All data will be buffered until the length is known. + * Delimited regions may be nested; their lengths will all be tracked properly. */ +static bool start_delim(upb_pb_encoder *e) { + if (e->top) { + /* We are already buffering, advance to the next segment and push it on the + * stack. */ + accumulate(e); + + if (++e->top == e->stacklimit) { + /* TODO(haberman): grow stack? */ + return false; + } + + if (++e->segptr == e->seglimit) { + /* Grow segment buffer. */ + size_t old_size = + (e->seglimit - e->segbuf) * sizeof(upb_pb_encoder_segment); + size_t new_size = old_size * 2; + upb_pb_encoder_segment *new_buf = + upb_env_realloc(e->env, e->segbuf, old_size, new_size); + + if (new_buf == NULL) { + return false; + } + + e->segptr = new_buf + (e->segptr - e->segbuf); + e->seglimit = new_buf + (new_size / sizeof(upb_pb_encoder_segment)); + e->segbuf = new_buf; + } + } else { + /* We were previously at the top level, start buffering. */ + e->segptr = e->segbuf; + e->top = e->stack; + e->runbegin = e->ptr; + } + + *e->top = e->segptr - e->segbuf; + e->segptr->seglen = 0; + e->segptr->msglen = 0; + + return true; +} + +/* Call to indicate the end of a delimited region. We now know the length of + * the delimited region. If we are not nested inside any other delimited + * regions, we can now emit all of the buffered data we accumulated. */ +static bool end_delim(upb_pb_encoder *e) { + size_t msglen; + accumulate(e); + msglen = top(e)->msglen; + + if (e->top == e->stack) { + /* All lengths are now available, emit all buffered data. */ + char buf[UPB_PB_VARINT_MAX_LEN]; + upb_pb_encoder_segment *s; + const char *ptr = e->buf; + for (s = e->segbuf; s <= e->segptr; s++) { + size_t lenbytes = upb_vencode64(s->msglen, buf); + putbuf(e, buf, lenbytes); + putbuf(e, ptr, s->seglen); + ptr += s->seglen; + } + + e->ptr = e->buf; + e->top = NULL; + } else { + /* Need to keep buffering; propagate length info into enclosing + * submessages. */ + --e->top; + top(e)->msglen += msglen + upb_varint_size(msglen); + } + + return true; +} + + +/* tag_t **********************************************************************/ + +/* A precomputed (pre-encoded) tag and length. */ + +typedef struct { + uint8_t bytes; + char tag[7]; +} tag_t; + +/* Allocates a new tag for this field, and sets it in these handlerattr. */ +static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt, + upb_handlerattr *attr) { + uint32_t n = upb_fielddef_number(f); + + tag_t *tag = malloc(sizeof(tag_t)); + tag->bytes = upb_vencode64((n << 3) | wt, tag->tag); + + upb_handlerattr_init(attr); + upb_handlerattr_sethandlerdata(attr, tag); + upb_handlers_addcleanup(h, tag, free); +} + +static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) { + return encode_bytes(e, tag->tag, tag->bytes); +} + + +/* encoding of wire types *****************************************************/ + +static bool encode_fixed64(upb_pb_encoder *e, uint64_t val) { + /* TODO(haberman): byte-swap for big endian. */ + return encode_bytes(e, &val, sizeof(uint64_t)); +} + +static bool encode_fixed32(upb_pb_encoder *e, uint32_t val) { + /* TODO(haberman): byte-swap for big endian. */ + return encode_bytes(e, &val, sizeof(uint32_t)); +} + +static bool encode_varint(upb_pb_encoder *e, uint64_t val) { + if (!reserve(e, UPB_PB_VARINT_MAX_LEN)) { + return false; + } + + encoder_advance(e, upb_vencode64(val, e->ptr)); + return true; +} + +static uint64_t dbl2uint64(double d) { + uint64_t ret; + memcpy(&ret, &d, sizeof(uint64_t)); + return ret; +} + +static uint32_t flt2uint32(float d) { + uint32_t ret; + memcpy(&ret, &d, sizeof(uint32_t)); + return ret; +} + + +/* encoding of proto types ****************************************************/ + +static bool startmsg(void *c, const void *hd) { + upb_pb_encoder *e = c; + UPB_UNUSED(hd); + if (e->depth++ == 0) { + upb_bytessink_start(e->output_, 0, &e->subc); + } + return true; +} + +static bool endmsg(void *c, const void *hd, upb_status *status) { + upb_pb_encoder *e = c; + UPB_UNUSED(hd); + UPB_UNUSED(status); + if (--e->depth == 0) { + upb_bytessink_end(e->output_); + } + return true; +} + +static void *encode_startdelimfield(void *c, const void *hd) { + bool ok = encode_tag(c, hd) && commit(c) && start_delim(c); + return ok ? c : UPB_BREAK; +} + +static bool encode_enddelimfield(void *c, const void *hd) { + UPB_UNUSED(hd); + return end_delim(c); +} + +static void *encode_startgroup(void *c, const void *hd) { + return (encode_tag(c, hd) && commit(c)) ? c : UPB_BREAK; +} + +static bool encode_endgroup(void *c, const void *hd) { + return encode_tag(c, hd) && commit(c); +} + +static void *encode_startstr(void *c, const void *hd, size_t size_hint) { + UPB_UNUSED(size_hint); + return encode_startdelimfield(c, hd); +} + +static size_t encode_strbuf(void *c, const void *hd, const char *buf, + size_t len, const upb_bufhandle *h) { + UPB_UNUSED(hd); + UPB_UNUSED(h); + return encode_bytes(c, buf, len) ? len : 0; +} + +#define T(type, ctype, convert, encode) \ + static bool encode_scalar_##type(void *e, const void *hd, ctype val) { \ + return encode_tag(e, hd) && encode(e, (convert)(val)) && commit(e); \ + } \ + static bool encode_packed_##type(void *e, const void *hd, ctype val) { \ + UPB_UNUSED(hd); \ + return encode(e, (convert)(val)); \ + } + +T(double, double, dbl2uint64, encode_fixed64) +T(float, float, flt2uint32, encode_fixed32) +T(int64, int64_t, uint64_t, encode_varint) +T(int32, int32_t, uint32_t, encode_varint) +T(fixed64, uint64_t, uint64_t, encode_fixed64) +T(fixed32, uint32_t, uint32_t, encode_fixed32) +T(bool, bool, bool, encode_varint) +T(uint32, uint32_t, uint32_t, encode_varint) +T(uint64, uint64_t, uint64_t, encode_varint) +T(enum, int32_t, uint32_t, encode_varint) +T(sfixed32, int32_t, uint32_t, encode_fixed32) +T(sfixed64, int64_t, uint64_t, encode_fixed64) +T(sint32, int32_t, upb_zzenc_32, encode_varint) +T(sint64, int64_t, upb_zzenc_64, encode_varint) + +#undef T + + +/* code to build the handlers *************************************************/ + +static void newhandlers_callback(const void *closure, upb_handlers *h) { + const upb_msgdef *m; + upb_msg_field_iter i; + + UPB_UNUSED(closure); + + upb_handlers_setstartmsg(h, startmsg, NULL); + upb_handlers_setendmsg(h, endmsg, NULL); + + m = upb_handlers_msgdef(h); + for(upb_msg_field_begin(&i, m); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + const upb_fielddef *f = upb_msg_iter_field(&i); + bool packed = upb_fielddef_isseq(f) && upb_fielddef_isprimitive(f) && + upb_fielddef_packed(f); + upb_handlerattr attr; + upb_wiretype_t wt = + packed ? UPB_WIRE_TYPE_DELIMITED + : upb_pb_native_wire_types[upb_fielddef_descriptortype(f)]; + + /* Pre-encode the tag for this field. */ + new_tag(h, f, wt, &attr); + + if (packed) { + upb_handlers_setstartseq(h, f, encode_startdelimfield, &attr); + upb_handlers_setendseq(h, f, encode_enddelimfield, &attr); + } + +#define T(upper, lower, upbtype) \ + case UPB_DESCRIPTOR_TYPE_##upper: \ + if (packed) { \ + upb_handlers_set##upbtype(h, f, encode_packed_##lower, &attr); \ + } else { \ + upb_handlers_set##upbtype(h, f, encode_scalar_##lower, &attr); \ + } \ + break; + + switch (upb_fielddef_descriptortype(f)) { + T(DOUBLE, double, double); + T(FLOAT, float, float); + T(INT64, int64, int64); + T(INT32, int32, int32); + T(FIXED64, fixed64, uint64); + T(FIXED32, fixed32, uint32); + T(BOOL, bool, bool); + T(UINT32, uint32, uint32); + T(UINT64, uint64, uint64); + T(ENUM, enum, int32); + T(SFIXED32, sfixed32, int32); + T(SFIXED64, sfixed64, int64); + T(SINT32, sint32, int32); + T(SINT64, sint64, int64); + case UPB_DESCRIPTOR_TYPE_STRING: + case UPB_DESCRIPTOR_TYPE_BYTES: + upb_handlers_setstartstr(h, f, encode_startstr, &attr); + upb_handlers_setendstr(h, f, encode_enddelimfield, &attr); + upb_handlers_setstring(h, f, encode_strbuf, &attr); + break; + case UPB_DESCRIPTOR_TYPE_MESSAGE: + upb_handlers_setstartsubmsg(h, f, encode_startdelimfield, &attr); + upb_handlers_setendsubmsg(h, f, encode_enddelimfield, &attr); + break; + case UPB_DESCRIPTOR_TYPE_GROUP: { + /* Endgroup takes a different tag (wire_type = END_GROUP). */ + upb_handlerattr attr2; + new_tag(h, f, UPB_WIRE_TYPE_END_GROUP, &attr2); + + upb_handlers_setstartsubmsg(h, f, encode_startgroup, &attr); + upb_handlers_setendsubmsg(h, f, encode_endgroup, &attr2); + + upb_handlerattr_uninit(&attr2); + break; + } + } + +#undef T + + upb_handlerattr_uninit(&attr); + } +} + +void upb_pb_encoder_reset(upb_pb_encoder *e) { + e->segptr = NULL; + e->top = NULL; + e->depth = 0; +} + + +/* public API *****************************************************************/ + +const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m, + const void *owner) { + return upb_handlers_newfrozen(m, owner, newhandlers_callback, NULL); +} + +upb_pb_encoder *upb_pb_encoder_create(upb_env *env, const upb_handlers *h, + upb_bytessink *output) { + const size_t initial_bufsize = 256; + const size_t initial_segbufsize = 16; + /* TODO(haberman): make this configurable. */ + const size_t stack_size = 64; +#ifndef NDEBUG + const size_t size_before = upb_env_bytesallocated(env); +#endif + + upb_pb_encoder *e = upb_env_malloc(env, sizeof(upb_pb_encoder)); + if (!e) return NULL; + + e->buf = upb_env_malloc(env, initial_bufsize); + e->segbuf = upb_env_malloc(env, initial_segbufsize * sizeof(*e->segbuf)); + e->stack = upb_env_malloc(env, stack_size * sizeof(*e->stack)); + + if (!e->buf || !e->segbuf || !e->stack) { + return NULL; + } + + e->limit = e->buf + initial_bufsize; + e->seglimit = e->segbuf + initial_segbufsize; + e->stacklimit = e->stack + stack_size; + + upb_pb_encoder_reset(e); + upb_sink_reset(&e->input_, h, e); + + e->env = env; + e->output_ = output; + e->subc = output->closure; + e->ptr = e->buf; + + /* If this fails, increase the value in encoder.h. */ + assert(upb_env_bytesallocated(env) - size_before <= UPB_PB_ENCODER_SIZE); + return e; +} + +upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; } + + +#include +#include +#include + +upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, + void *owner, upb_status *status) { + /* Create handlers. */ + const upb_pbdecodermethod *decoder_m; + const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h); + upb_env env; + upb_pbdecodermethodopts opts; + upb_pbdecoder *decoder; + upb_descreader *reader; + bool ok; + upb_def **ret = NULL; + upb_def **defs; + + upb_pbdecodermethodopts_init(&opts, reader_h); + decoder_m = upb_pbdecodermethod_new(&opts, &decoder_m); + + upb_env_init(&env); + upb_env_reporterrorsto(&env, status); + + reader = upb_descreader_create(&env, reader_h); + decoder = upb_pbdecoder_create(&env, decoder_m, upb_descreader_input(reader)); + + /* Push input data. */ + ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(decoder)); + + if (!ok) goto cleanup; + defs = upb_descreader_getdefs(reader, owner, n); + ret = malloc(sizeof(upb_def*) * (*n)); + memcpy(ret, defs, sizeof(upb_def*) * (*n)); + +cleanup: + upb_env_uninit(&env); + upb_handlers_unref(reader_h, &reader_h); + upb_pbdecodermethod_unref(decoder_m, &decoder_m); + return ret; +} + +bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len, + upb_status *status) { + int n; + bool success; + upb_def **defs = upb_load_defs_from_descriptor(str, len, &n, &defs, status); + if (!defs) return false; + success = upb_symtab_add(s, defs, n, &defs, status); + free(defs); + return success; +} + +char *upb_readfile(const char *filename, size_t *len) { + long size; + char *buf; + FILE *f = fopen(filename, "rb"); + if(!f) return NULL; + if(fseek(f, 0, SEEK_END) != 0) goto error; + size = ftell(f); + if(size < 0) goto error; + if(fseek(f, 0, SEEK_SET) != 0) goto error; + buf = malloc(size + 1); + if(size && fread(buf, size, 1, f) != 1) goto error; + fclose(f); + if (len) *len = size; + return buf; + +error: + fclose(f); + return NULL; +} + +bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname, + upb_status *status) { + size_t len; + bool success; + char *data = upb_readfile(fname, &len); + if (!data) { + if (status) upb_status_seterrf(status, "Couldn't read file: %s", fname); + return false; + } + success = upb_load_descriptor_into_symtab(symtab, data, len, status); + free(data); + return success; +} +/* + * upb::pb::TextPrinter + * + * OPT: This is not optimized at all. It uses printf() which parses the format + * string every time, and it allocates memory for every put. + */ + + +#include +#include +#include +#include +#include +#include +#include + + +struct upb_textprinter { + upb_sink input_; + upb_bytessink *output_; + int indent_depth_; + bool single_line_; + void *subc; +}; + +#define CHECK(x) if ((x) < 0) goto err; + +static const char *shortname(const char *longname) { + const char *last = strrchr(longname, '.'); + return last ? last + 1 : longname; +} + +static int indent(upb_textprinter *p) { + int i; + if (!p->single_line_) + for (i = 0; i < p->indent_depth_; i++) + upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL); + return 0; +} + +static int endfield(upb_textprinter *p) { + const char ch = (p->single_line_ ? ' ' : '\n'); + upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL); + return 0; +} + +static int putescaped(upb_textprinter *p, const char *buf, size_t len, + bool preserve_utf8) { + /* Based on CEscapeInternal() from Google's protobuf release. */ + char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); + const char *end = buf + len; + + /* I think hex is prettier and more useful, but proto2 uses octal; should + * investigate whether it can parse hex also. */ + const bool use_hex = false; + bool last_hex_escape = false; /* true if last output char was \xNN */ + + for (; buf < end; buf++) { + bool is_hex_escape; + + if (dstend - dst < 4) { + upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); + dst = dstbuf; + } + + is_hex_escape = false; + switch (*buf) { + case '\n': *(dst++) = '\\'; *(dst++) = 'n'; break; + case '\r': *(dst++) = '\\'; *(dst++) = 'r'; break; + case '\t': *(dst++) = '\\'; *(dst++) = 't'; break; + case '\"': *(dst++) = '\\'; *(dst++) = '\"'; break; + case '\'': *(dst++) = '\\'; *(dst++) = '\''; break; + case '\\': *(dst++) = '\\'; *(dst++) = '\\'; break; + default: + /* Note that if we emit \xNN and the buf character after that is a hex + * digit then that digit must be escaped too to prevent it being + * interpreted as part of the character code by C. */ + if ((!preserve_utf8 || (uint8_t)*buf < 0x80) && + (!isprint(*buf) || (last_hex_escape && isxdigit(*buf)))) { + sprintf(dst, (use_hex ? "\\x%02x" : "\\%03o"), (uint8_t)*buf); + is_hex_escape = use_hex; + dst += 4; + } else { + *(dst++) = *buf; break; + } + } + last_hex_escape = is_hex_escape; + } + /* Flush remaining data. */ + upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); + return 0; +} + +bool putf(upb_textprinter *p, const char *fmt, ...) { + va_list args; + va_list args_copy; + char *str; + int written; + int len; + bool ok; + + va_start(args, fmt); + + /* Run once to get the length of the string. */ + _upb_va_copy(args_copy, args); + len = _upb_vsnprintf(NULL, 0, fmt, args_copy); + va_end(args_copy); + + /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */ + str = malloc(len + 1); + if (!str) return false; + written = vsprintf(str, fmt, args); + va_end(args); + UPB_ASSERT_VAR(written, written == len); + + ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL); + free(str); + return ok; +} + + +/* handlers *******************************************************************/ + +static bool textprinter_startmsg(void *c, const void *hd) { + upb_textprinter *p = c; + UPB_UNUSED(hd); + if (p->indent_depth_ == 0) { + upb_bytessink_start(p->output_, 0, &p->subc); + } + return true; +} + +static bool textprinter_endmsg(void *c, const void *hd, upb_status *s) { + upb_textprinter *p = c; + UPB_UNUSED(hd); + UPB_UNUSED(s); + if (p->indent_depth_ == 0) { + upb_bytessink_end(p->output_); + } + return true; +} + +#define TYPE(name, ctype, fmt) \ + static bool textprinter_put ## name(void *closure, const void *handler_data, \ + ctype val) { \ + upb_textprinter *p = closure; \ + const upb_fielddef *f = handler_data; \ + CHECK(indent(p)); \ + putf(p, "%s: " fmt, upb_fielddef_name(f), val); \ + CHECK(endfield(p)); \ + return true; \ + err: \ + return false; \ +} + +static bool textprinter_putbool(void *closure, const void *handler_data, + bool val) { + upb_textprinter *p = closure; + const upb_fielddef *f = handler_data; + CHECK(indent(p)); + putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false"); + CHECK(endfield(p)); + return true; +err: + return false; +} + +#define STRINGIFY_HELPER(x) #x +#define STRINGIFY_MACROVAL(x) STRINGIFY_HELPER(x) + +TYPE(int32, int32_t, "%" PRId32) +TYPE(int64, int64_t, "%" PRId64) +TYPE(uint32, uint32_t, "%" PRIu32) +TYPE(uint64, uint64_t, "%" PRIu64) +TYPE(float, float, "%." STRINGIFY_MACROVAL(FLT_DIG) "g") +TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") + +#undef TYPE + +/* Output a symbolic value from the enum if found, else just print as int32. */ +static bool textprinter_putenum(void *closure, const void *handler_data, + int32_t val) { + upb_textprinter *p = closure; + const upb_fielddef *f = handler_data; + const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f)); + const char *label = upb_enumdef_iton(enum_def, val); + if (label) { + indent(p); + putf(p, "%s: %s", upb_fielddef_name(f), label); + endfield(p); + } else { + if (!textprinter_putint32(closure, handler_data, val)) + return false; + } + return true; +} + +static void *textprinter_startstr(void *closure, const void *handler_data, + size_t size_hint) { + upb_textprinter *p = closure; + const upb_fielddef *f = handler_data; + UPB_UNUSED(size_hint); + indent(p); + putf(p, "%s: \"", upb_fielddef_name(f)); + return p; +} + +static bool textprinter_endstr(void *closure, const void *handler_data) { + upb_textprinter *p = closure; + UPB_UNUSED(handler_data); + putf(p, "\""); + endfield(p); + return true; +} + +static size_t textprinter_putstr(void *closure, const void *hd, const char *buf, + size_t len, const upb_bufhandle *handle) { + upb_textprinter *p = closure; + const upb_fielddef *f = hd; + UPB_UNUSED(handle); + CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING)); + return len; +err: + return 0; +} + +static void *textprinter_startsubmsg(void *closure, const void *handler_data) { + upb_textprinter *p = closure; + const char *name = handler_data; + CHECK(indent(p)); + putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n'); + p->indent_depth_++; + return p; +err: + return UPB_BREAK; +} + +static bool textprinter_endsubmsg(void *closure, const void *handler_data) { + upb_textprinter *p = closure; + UPB_UNUSED(handler_data); + p->indent_depth_--; + CHECK(indent(p)); + upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL); + CHECK(endfield(p)); + return true; +err: + return false; +} + +static void onmreg(const void *c, upb_handlers *h) { + const upb_msgdef *m = upb_handlers_msgdef(h); + upb_msg_field_iter i; + UPB_UNUSED(c); + + upb_handlers_setstartmsg(h, textprinter_startmsg, NULL); + upb_handlers_setendmsg(h, textprinter_endmsg, NULL); + + for(upb_msg_field_begin(&i, m); + !upb_msg_field_done(&i); + upb_msg_field_next(&i)) { + upb_fielddef *f = upb_msg_iter_field(&i); + upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; + upb_handlerattr_sethandlerdata(&attr, f); + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + upb_handlers_setint32(h, f, textprinter_putint32, &attr); + break; + case UPB_TYPE_INT64: + upb_handlers_setint64(h, f, textprinter_putint64, &attr); + break; + case UPB_TYPE_UINT32: + upb_handlers_setuint32(h, f, textprinter_putuint32, &attr); + break; + case UPB_TYPE_UINT64: + upb_handlers_setuint64(h, f, textprinter_putuint64, &attr); + break; + case UPB_TYPE_FLOAT: + upb_handlers_setfloat(h, f, textprinter_putfloat, &attr); + break; + case UPB_TYPE_DOUBLE: + upb_handlers_setdouble(h, f, textprinter_putdouble, &attr); + break; + case UPB_TYPE_BOOL: + upb_handlers_setbool(h, f, textprinter_putbool, &attr); + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + upb_handlers_setstartstr(h, f, textprinter_startstr, &attr); + upb_handlers_setstring(h, f, textprinter_putstr, &attr); + upb_handlers_setendstr(h, f, textprinter_endstr, &attr); + break; + case UPB_TYPE_MESSAGE: { + const char *name = + upb_fielddef_istagdelim(f) + ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f))) + : upb_fielddef_name(f); + upb_handlerattr_sethandlerdata(&attr, name); + upb_handlers_setstartsubmsg(h, f, textprinter_startsubmsg, &attr); + upb_handlers_setendsubmsg(h, f, textprinter_endsubmsg, &attr); + break; + } + case UPB_TYPE_ENUM: + upb_handlers_setint32(h, f, textprinter_putenum, &attr); + break; + } + } +} + +static void textprinter_reset(upb_textprinter *p, bool single_line) { + p->single_line_ = single_line; + p->indent_depth_ = 0; +} + + +/* Public API *****************************************************************/ + +upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h, + upb_bytessink *output) { + upb_textprinter *p = upb_env_malloc(env, sizeof(upb_textprinter)); + if (!p) return NULL; + + p->output_ = output; + upb_sink_reset(&p->input_, h, p); + textprinter_reset(p, false); + + return p; +} + +const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, + const void *owner) { + return upb_handlers_newfrozen(m, owner, &onmreg, NULL); +} + +upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; } + +void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) { + p->single_line_ = single_line; +} + + +/* Index is descriptor type. */ +const uint8_t upb_pb_native_wire_types[] = { + UPB_WIRE_TYPE_END_GROUP, /* ENDGROUP */ + UPB_WIRE_TYPE_64BIT, /* DOUBLE */ + UPB_WIRE_TYPE_32BIT, /* FLOAT */ + UPB_WIRE_TYPE_VARINT, /* INT64 */ + UPB_WIRE_TYPE_VARINT, /* UINT64 */ + UPB_WIRE_TYPE_VARINT, /* INT32 */ + UPB_WIRE_TYPE_64BIT, /* FIXED64 */ + UPB_WIRE_TYPE_32BIT, /* FIXED32 */ + UPB_WIRE_TYPE_VARINT, /* BOOL */ + UPB_WIRE_TYPE_DELIMITED, /* STRING */ + UPB_WIRE_TYPE_START_GROUP, /* GROUP */ + UPB_WIRE_TYPE_DELIMITED, /* MESSAGE */ + UPB_WIRE_TYPE_DELIMITED, /* BYTES */ + UPB_WIRE_TYPE_VARINT, /* UINT32 */ + UPB_WIRE_TYPE_VARINT, /* ENUM */ + UPB_WIRE_TYPE_32BIT, /* SFIXED32 */ + UPB_WIRE_TYPE_64BIT, /* SFIXED64 */ + UPB_WIRE_TYPE_VARINT, /* SINT32 */ + UPB_WIRE_TYPE_VARINT, /* SINT64 */ +}; + +/* A basic branch-based decoder, uses 32-bit values to get good performance + * on 32-bit architectures (but performs well on 64-bits also). + * This scheme comes from the original Google Protobuf implementation + * (proto2). */ +upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r) { + upb_decoderet err = {NULL, 0}; + const char *p = r.p; + uint32_t low = (uint32_t)r.val; + uint32_t high = 0; + uint32_t b; + b = *(p++); low |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done; + b = *(p++); low |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done; + b = *(p++); low |= (b & 0x7fU) << 28; + high = (b & 0x7fU) >> 4; if (!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7fU) << 3; if (!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7fU) << 10; if (!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7fU) << 17; if (!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7fU) << 24; if (!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7fU) << 31; if (!(b & 0x80)) goto done; + return err; + +done: + r.val = ((uint64_t)high << 32) | low; + r.p = p; + return r; +} + +/* Like the previous, but uses 64-bit values. */ +upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r) { + const char *p = r.p; + uint64_t val = r.val; + uint64_t b; + upb_decoderet err = {NULL, 0}; + b = *(p++); val |= (b & 0x7fU) << 14; if (!(b & 0x80)) goto done; + b = *(p++); val |= (b & 0x7fU) << 21; if (!(b & 0x80)) goto done; + b = *(p++); val |= (b & 0x7fU) << 28; if (!(b & 0x80)) goto done; + b = *(p++); val |= (b & 0x7fU) << 35; if (!(b & 0x80)) goto done; + b = *(p++); val |= (b & 0x7fU) << 42; if (!(b & 0x80)) goto done; + b = *(p++); val |= (b & 0x7fU) << 49; if (!(b & 0x80)) goto done; + b = *(p++); val |= (b & 0x7fU) << 56; if (!(b & 0x80)) goto done; + b = *(p++); val |= (b & 0x7fU) << 63; if (!(b & 0x80)) goto done; + return err; + +done: + r.val = val; + r.p = p; + return r; +} + +/* Given an encoded varint v, returns an integer with a single bit set that + * indicates the end of the varint. Subtracting one from this value will + * yield a mask that leaves only bits that are part of the varint. Returns + * 0 if the varint is unterminated. */ +static uint64_t upb_get_vstopbit(uint64_t v) { + uint64_t cbits = v | 0x7f7f7f7f7f7f7f7fULL; + return ~cbits & (cbits+1); +} + +/* A branchless decoder. Credit to Pascal Massimino for the bit-twiddling. */ +upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r) { + uint64_t b; + uint64_t stop_bit; + upb_decoderet my_r; + memcpy(&b, r.p, sizeof(b)); + stop_bit = upb_get_vstopbit(b); + b = (b & 0x7f7f7f7f7f7f7f7fULL) & (stop_bit - 1); + b += b & 0x007f007f007f007fULL; + b += 3 * (b & 0x0000ffff0000ffffULL); + b += 15 * (b & 0x00000000ffffffffULL); + if (stop_bit == 0) { + /* Error: unterminated varint. */ + upb_decoderet err_r = {(void*)0, 0}; + return err_r; + } + my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8), + r.val | (b << 7)); + return my_r; +} + +/* A branchless decoder. Credit to Daniel Wright for the bit-twiddling. */ +upb_decoderet upb_vdecode_max8_wright(upb_decoderet r) { + uint64_t b; + uint64_t stop_bit; + upb_decoderet my_r; + memcpy(&b, r.p, sizeof(b)); + stop_bit = upb_get_vstopbit(b); + b &= (stop_bit - 1); + b = ((b & 0x7f007f007f007f00ULL) >> 1) | (b & 0x007f007f007f007fULL); + b = ((b & 0xffff0000ffff0000ULL) >> 2) | (b & 0x0000ffff0000ffffULL); + b = ((b & 0xffffffff00000000ULL) >> 4) | (b & 0x00000000ffffffffULL); + if (stop_bit == 0) { + /* Error: unterminated varint. */ + upb_decoderet err_r = {(void*)0, 0}; + return err_r; + } + my_r = upb_decoderet_make(r.p + ((__builtin_ctzll(stop_bit) + 1) / 8), + r.val | (b << 14)); + return my_r; +} + +#line 1 "upb/json/parser.rl" +/* +** upb::json::Parser (upb_json_parser) +** +** A parser that uses the Ragel State Machine Compiler to generate +** the finite automata. +** +** Ragel only natively handles regular languages, but we can manually +** program it a bit to handle context-free languages like JSON, by using +** the "fcall" and "fret" constructs. +** +** This parser can handle the basics, but needs several things to be fleshed +** out: +** +** - handling of unicode escape sequences (including high surrogate pairs). +** - properly check and report errors for unknown fields, stack overflow, +** improper array nesting (or lack of nesting). +** - handling of base64 sequences with padding characters. +** - handling of push-back (non-success returns from sink functions). +** - handling of keys/escape-sequences/etc that span input buffers. +*/ + +#include +#include +#include +#include +#include +#include + + +#define UPB_JSON_MAX_DEPTH 64 + +typedef struct { + upb_sink sink; + + /* The current message in which we're parsing, and the field whose value we're + * expecting next. */ + const upb_msgdef *m; + const upb_fielddef *f; + + /* We are in a repeated-field context, ready to emit mapentries as + * submessages. This flag alters the start-of-object (open-brace) behavior to + * begin a sequence of mapentry messages rather than a single submessage. */ + bool is_map; + + /* We are in a map-entry message context. This flag is set when parsing the + * value field of a single map entry and indicates to all value-field parsers + * (subobjects, strings, numbers, and bools) that the map-entry submessage + * should end as soon as the value is parsed. */ + bool is_mapentry; + + /* If |is_map| or |is_mapentry| is true, |mapfield| refers to the parent + * message's map field that we're currently parsing. This differs from |f| + * because |f| is the field in the *current* message (i.e., the map-entry + * message itself), not the parent's field that leads to this map. */ + const upb_fielddef *mapfield; +} upb_jsonparser_frame; + +struct upb_json_parser { + upb_env *env; + upb_byteshandler input_handler_; + upb_bytessink input_; + + /* Stack to track the JSON scopes we are in. */ + upb_jsonparser_frame stack[UPB_JSON_MAX_DEPTH]; + upb_jsonparser_frame *top; + upb_jsonparser_frame *limit; + + upb_status status; + + /* Ragel's internal parsing stack for the parsing state machine. */ + int current_state; + int parser_stack[UPB_JSON_MAX_DEPTH]; + int parser_top; + + /* The handle for the current buffer. */ + const upb_bufhandle *handle; + + /* Accumulate buffer. See details in parser.rl. */ + const char *accumulated; + size_t accumulated_len; + char *accumulate_buf; + size_t accumulate_buf_size; + + /* Multi-part text data. See details in parser.rl. */ + int multipart_state; + upb_selector_t string_selector; + + /* Input capture. See details in parser.rl. */ + const char *capture; + + /* Intermediate result of parsing a unicode escape sequence. */ + uint32_t digit; +}; + +#define PARSER_CHECK_RETURN(x) if (!(x)) return false + +/* Used to signal that a capture has been suspended. */ +static char suspend_capture; + +static upb_selector_t getsel_for_handlertype(upb_json_parser *p, + upb_handlertype_t type) { + upb_selector_t sel; + bool ok = upb_handlers_getselector(p->top->f, type, &sel); + UPB_ASSERT_VAR(ok, ok); + return sel; +} + +static upb_selector_t parser_getsel(upb_json_parser *p) { + return getsel_for_handlertype( + p, upb_handlers_getprimitivehandlertype(p->top->f)); +} + +static bool check_stack(upb_json_parser *p) { + if ((p->top + 1) == p->limit) { + upb_status_seterrmsg(&p->status, "Nesting too deep"); + upb_env_reporterror(p->env, &p->status); + return false; + } + + return true; +} + +/* There are GCC/Clang built-ins for overflow checking which we could start + * using if there was any performance benefit to it. */ + +static bool checked_add(size_t a, size_t b, size_t *c) { + if (SIZE_MAX - a < b) return false; + *c = a + b; + return true; +} + +static size_t saturating_multiply(size_t a, size_t b) { + /* size_t is unsigned, so this is defined behavior even on overflow. */ + size_t ret = a * b; + if (b != 0 && ret / b != a) { + ret = SIZE_MAX; + } + return ret; +} + + +/* Base64 decoding ************************************************************/ + +/* TODO(haberman): make this streaming. */ + +static const signed char b64table[] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 62/*+*/, -1, -1, -1, 63/*/ */, + 52/*0*/, 53/*1*/, 54/*2*/, 55/*3*/, 56/*4*/, 57/*5*/, 58/*6*/, 59/*7*/, + 60/*8*/, 61/*9*/, -1, -1, -1, -1, -1, -1, + -1, 0/*A*/, 1/*B*/, 2/*C*/, 3/*D*/, 4/*E*/, 5/*F*/, 6/*G*/, + 07/*H*/, 8/*I*/, 9/*J*/, 10/*K*/, 11/*L*/, 12/*M*/, 13/*N*/, 14/*O*/, + 15/*P*/, 16/*Q*/, 17/*R*/, 18/*S*/, 19/*T*/, 20/*U*/, 21/*V*/, 22/*W*/, + 23/*X*/, 24/*Y*/, 25/*Z*/, -1, -1, -1, -1, -1, + -1, 26/*a*/, 27/*b*/, 28/*c*/, 29/*d*/, 30/*e*/, 31/*f*/, 32/*g*/, + 33/*h*/, 34/*i*/, 35/*j*/, 36/*k*/, 37/*l*/, 38/*m*/, 39/*n*/, 40/*o*/, + 41/*p*/, 42/*q*/, 43/*r*/, 44/*s*/, 45/*t*/, 46/*u*/, 47/*v*/, 48/*w*/, + 49/*x*/, 50/*y*/, 51/*z*/, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/* Returns the table value sign-extended to 32 bits. Knowing that the upper + * bits will be 1 for unrecognized characters makes it easier to check for + * this error condition later (see below). */ +int32_t b64lookup(unsigned char ch) { return b64table[ch]; } + +/* Returns true if the given character is not a valid base64 character or + * padding. */ +bool nonbase64(unsigned char ch) { return b64lookup(ch) == -1 && ch != '='; } + +static bool base64_push(upb_json_parser *p, upb_selector_t sel, const char *ptr, + size_t len) { + const char *limit = ptr + len; + for (; ptr < limit; ptr += 4) { + uint32_t val; + char output[3]; + + if (limit - ptr < 4) { + upb_status_seterrf(&p->status, + "Base64 input for bytes field not a multiple of 4: %s", + upb_fielddef_name(p->top->f)); + upb_env_reporterror(p->env, &p->status); + return false; + } + + val = b64lookup(ptr[0]) << 18 | + b64lookup(ptr[1]) << 12 | + b64lookup(ptr[2]) << 6 | + b64lookup(ptr[3]); + + /* Test the upper bit; returns true if any of the characters returned -1. */ + if (val & 0x80000000) { + goto otherchar; + } + + output[0] = val >> 16; + output[1] = (val >> 8) & 0xff; + output[2] = val & 0xff; + upb_sink_putstring(&p->top->sink, sel, output, 3, NULL); + } + return true; + +otherchar: + if (nonbase64(ptr[0]) || nonbase64(ptr[1]) || nonbase64(ptr[2]) || + nonbase64(ptr[3]) ) { + upb_status_seterrf(&p->status, + "Non-base64 characters in bytes field: %s", + upb_fielddef_name(p->top->f)); + upb_env_reporterror(p->env, &p->status); + return false; + } if (ptr[2] == '=') { + uint32_t val; + char output; + + /* Last group contains only two input bytes, one output byte. */ + if (ptr[0] == '=' || ptr[1] == '=' || ptr[3] != '=') { + goto badpadding; + } + + val = b64lookup(ptr[0]) << 18 | + b64lookup(ptr[1]) << 12; + + assert(!(val & 0x80000000)); + output = val >> 16; + upb_sink_putstring(&p->top->sink, sel, &output, 1, NULL); + return true; + } else { + uint32_t val; + char output[2]; + + /* Last group contains only three input bytes, two output bytes. */ + if (ptr[0] == '=' || ptr[1] == '=' || ptr[2] == '=') { + goto badpadding; + } + + val = b64lookup(ptr[0]) << 18 | + b64lookup(ptr[1]) << 12 | + b64lookup(ptr[2]) << 6; + + output[0] = val >> 16; + output[1] = (val >> 8) & 0xff; + upb_sink_putstring(&p->top->sink, sel, output, 2, NULL); + return true; + } + +badpadding: + upb_status_seterrf(&p->status, + "Incorrect base64 padding for field: %s (%.*s)", + upb_fielddef_name(p->top->f), + 4, ptr); + upb_env_reporterror(p->env, &p->status); + return false; +} + + +/* Accumulate buffer **********************************************************/ + +/* Functionality for accumulating a buffer. + * + * Some parts of the parser need an entire value as a contiguous string. For + * example, to look up a member name in a hash table, or to turn a string into + * a number, the relevant library routines need the input string to be in + * contiguous memory, even if the value spanned two or more buffers in the + * input. These routines handle that. + * + * In the common case we can just point to the input buffer to get this + * contiguous string and avoid any actual copy. So we optimistically begin + * this way. But there are a few cases where we must instead copy into a + * separate buffer: + * + * 1. The string was not contiguous in the input (it spanned buffers). + * + * 2. The string included escape sequences that need to be interpreted to get + * the true value in a contiguous buffer. */ + +static void assert_accumulate_empty(upb_json_parser *p) { + UPB_UNUSED(p); + assert(p->accumulated == NULL); + assert(p->accumulated_len == 0); +} + +static void accumulate_clear(upb_json_parser *p) { + p->accumulated = NULL; + p->accumulated_len = 0; +} + +/* Used internally by accumulate_append(). */ +static bool accumulate_realloc(upb_json_parser *p, size_t need) { + void *mem; + size_t old_size = p->accumulate_buf_size; + size_t new_size = UPB_MAX(old_size, 128); + while (new_size < need) { + new_size = saturating_multiply(new_size, 2); + } + + mem = upb_env_realloc(p->env, p->accumulate_buf, old_size, new_size); + if (!mem) { + upb_status_seterrmsg(&p->status, "Out of memory allocating buffer."); + upb_env_reporterror(p->env, &p->status); + return false; + } + + p->accumulate_buf = mem; + p->accumulate_buf_size = new_size; + return true; +} + +/* Logically appends the given data to the append buffer. + * If "can_alias" is true, we will try to avoid actually copying, but the buffer + * must be valid until the next accumulate_append() call (if any). */ +static bool accumulate_append(upb_json_parser *p, const char *buf, size_t len, + bool can_alias) { + size_t need; + + if (!p->accumulated && can_alias) { + p->accumulated = buf; + p->accumulated_len = len; + return true; + } + + if (!checked_add(p->accumulated_len, len, &need)) { + upb_status_seterrmsg(&p->status, "Integer overflow."); + upb_env_reporterror(p->env, &p->status); + return false; + } + + if (need > p->accumulate_buf_size && !accumulate_realloc(p, need)) { + return false; + } + + if (p->accumulated != p->accumulate_buf) { + memcpy(p->accumulate_buf, p->accumulated, p->accumulated_len); + p->accumulated = p->accumulate_buf; + } + + memcpy(p->accumulate_buf + p->accumulated_len, buf, len); + p->accumulated_len += len; + return true; +} + +/* Returns a pointer to the data accumulated since the last accumulate_clear() + * call, and writes the length to *len. This with point either to the input + * buffer or a temporary accumulate buffer. */ +static const char *accumulate_getptr(upb_json_parser *p, size_t *len) { + assert(p->accumulated); + *len = p->accumulated_len; + return p->accumulated; +} + + +/* Mult-part text data ********************************************************/ + +/* When we have text data in the input, it can often come in multiple segments. + * For example, there may be some raw string data followed by an escape + * sequence. The two segments are processed with different logic. Also buffer + * seams in the input can cause multiple segments. + * + * As we see segments, there are two main cases for how we want to process them: + * + * 1. we want to push the captured input directly to string handlers. + * + * 2. we need to accumulate all the parts into a contiguous buffer for further + * processing (field name lookup, string->number conversion, etc). */ + +/* This is the set of states for p->multipart_state. */ +enum { + /* We are not currently processing multipart data. */ + MULTIPART_INACTIVE = 0, + + /* We are processing multipart data by accumulating it into a contiguous + * buffer. */ + MULTIPART_ACCUMULATE = 1, + + /* We are processing multipart data by pushing each part directly to the + * current string handlers. */ + MULTIPART_PUSHEAGERLY = 2 +}; + +/* Start a multi-part text value where we accumulate the data for processing at + * the end. */ +static void multipart_startaccum(upb_json_parser *p) { + assert_accumulate_empty(p); + assert(p->multipart_state == MULTIPART_INACTIVE); + p->multipart_state = MULTIPART_ACCUMULATE; +} + +/* Start a multi-part text value where we immediately push text data to a string + * value with the given selector. */ +static void multipart_start(upb_json_parser *p, upb_selector_t sel) { + assert_accumulate_empty(p); + assert(p->multipart_state == MULTIPART_INACTIVE); + p->multipart_state = MULTIPART_PUSHEAGERLY; + p->string_selector = sel; +} + +static bool multipart_text(upb_json_parser *p, const char *buf, size_t len, + bool can_alias) { + switch (p->multipart_state) { + case MULTIPART_INACTIVE: + upb_status_seterrmsg( + &p->status, "Internal error: unexpected state MULTIPART_INACTIVE"); + upb_env_reporterror(p->env, &p->status); + return false; + + case MULTIPART_ACCUMULATE: + if (!accumulate_append(p, buf, len, can_alias)) { + return false; + } + break; + + case MULTIPART_PUSHEAGERLY: { + const upb_bufhandle *handle = can_alias ? p->handle : NULL; + upb_sink_putstring(&p->top->sink, p->string_selector, buf, len, handle); + break; + } + } + + return true; +} + +/* Note: this invalidates the accumulate buffer! Call only after reading its + * contents. */ +static void multipart_end(upb_json_parser *p) { + assert(p->multipart_state != MULTIPART_INACTIVE); + p->multipart_state = MULTIPART_INACTIVE; + accumulate_clear(p); +} + + +/* Input capture **************************************************************/ + +/* Functionality for capturing a region of the input as text. Gracefully + * handles the case where a buffer seam occurs in the middle of the captured + * region. */ + +static void capture_begin(upb_json_parser *p, const char *ptr) { + assert(p->multipart_state != MULTIPART_INACTIVE); + assert(p->capture == NULL); + p->capture = ptr; +} + +static bool capture_end(upb_json_parser *p, const char *ptr) { + assert(p->capture); + if (multipart_text(p, p->capture, ptr - p->capture, true)) { + p->capture = NULL; + return true; + } else { + return false; + } +} + +/* This is called at the end of each input buffer (ie. when we have hit a + * buffer seam). If we are in the middle of capturing the input, this + * processes the unprocessed capture region. */ +static void capture_suspend(upb_json_parser *p, const char **ptr) { + if (!p->capture) return; + + if (multipart_text(p, p->capture, *ptr - p->capture, false)) { + /* We use this as a signal that we were in the middle of capturing, and + * that capturing should resume at the beginning of the next buffer. + * + * We can't use *ptr here, because we have no guarantee that this pointer + * will be valid when we resume (if the underlying memory is freed, then + * using the pointer at all, even to compare to NULL, is likely undefined + * behavior). */ + p->capture = &suspend_capture; + } else { + /* Need to back up the pointer to the beginning of the capture, since + * we were not able to actually preserve it. */ + *ptr = p->capture; + } +} + +static void capture_resume(upb_json_parser *p, const char *ptr) { + if (p->capture) { + assert(p->capture == &suspend_capture); + p->capture = ptr; + } +} + + +/* Callbacks from the parser **************************************************/ + +/* These are the functions called directly from the parser itself. + * We define these in the same order as their declarations in the parser. */ + +static char escape_char(char in) { + switch (in) { + case 'r': return '\r'; + case 't': return '\t'; + case 'n': return '\n'; + case 'f': return '\f'; + case 'b': return '\b'; + case '/': return '/'; + case '"': return '"'; + case '\\': return '\\'; + default: + assert(0); + return 'x'; + } +} + +static bool escape(upb_json_parser *p, const char *ptr) { + char ch = escape_char(*ptr); + return multipart_text(p, &ch, 1, false); +} + +static void start_hex(upb_json_parser *p) { + p->digit = 0; +} + +static void hexdigit(upb_json_parser *p, const char *ptr) { + char ch = *ptr; + + p->digit <<= 4; + + if (ch >= '0' && ch <= '9') { + p->digit += (ch - '0'); + } else if (ch >= 'a' && ch <= 'f') { + p->digit += ((ch - 'a') + 10); + } else { + assert(ch >= 'A' && ch <= 'F'); + p->digit += ((ch - 'A') + 10); + } +} + +static bool end_hex(upb_json_parser *p) { + uint32_t codepoint = p->digit; + + /* emit the codepoint as UTF-8. */ + char utf8[3]; /* support \u0000 -- \uFFFF -- need only three bytes. */ + int length = 0; + if (codepoint <= 0x7F) { + utf8[0] = codepoint; + length = 1; + } else if (codepoint <= 0x07FF) { + utf8[1] = (codepoint & 0x3F) | 0x80; + codepoint >>= 6; + utf8[0] = (codepoint & 0x1F) | 0xC0; + length = 2; + } else /* codepoint <= 0xFFFF */ { + utf8[2] = (codepoint & 0x3F) | 0x80; + codepoint >>= 6; + utf8[1] = (codepoint & 0x3F) | 0x80; + codepoint >>= 6; + utf8[0] = (codepoint & 0x0F) | 0xE0; + length = 3; + } + /* TODO(haberman): Handle high surrogates: if codepoint is a high surrogate + * we have to wait for the next escape to get the full code point). */ + + return multipart_text(p, utf8, length, false); +} + +static void start_text(upb_json_parser *p, const char *ptr) { + capture_begin(p, ptr); +} + +static bool end_text(upb_json_parser *p, const char *ptr) { + return capture_end(p, ptr); +} + +static void start_number(upb_json_parser *p, const char *ptr) { + multipart_startaccum(p); + capture_begin(p, ptr); +} + +static bool parse_number(upb_json_parser *p); + +static bool end_number(upb_json_parser *p, const char *ptr) { + if (!capture_end(p, ptr)) { + return false; + } + + return parse_number(p); +} + +static bool parse_number(upb_json_parser *p) { + size_t len; + const char *buf; + const char *myend; + char *end; + + /* strtol() and friends unfortunately do not support specifying the length of + * the input string, so we need to force a copy into a NULL-terminated buffer. */ + if (!multipart_text(p, "\0", 1, false)) { + return false; + } + + buf = accumulate_getptr(p, &len); + myend = buf + len - 1; /* One for NULL. */ + + /* XXX: We are using strtol to parse integers, but this is wrong as even + * integers can be represented as 1e6 (for example), which strtol can't + * handle correctly. + * + * XXX: Also, we can't handle large integers properly because strto[u]ll + * isn't in C89. + * + * XXX: Also, we don't properly check floats for overflow, since strtof + * isn't in C89. */ + switch (upb_fielddef_type(p->top->f)) { + case UPB_TYPE_ENUM: + case UPB_TYPE_INT32: { + long val = strtol(p->accumulated, &end, 0); + if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || end != myend) + goto err; + else + upb_sink_putint32(&p->top->sink, parser_getsel(p), val); + break; + } + case UPB_TYPE_INT64: { + long long val = strtol(p->accumulated, &end, 0); + if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || end != myend) + goto err; + else + upb_sink_putint64(&p->top->sink, parser_getsel(p), val); + break; + } + case UPB_TYPE_UINT32: { + unsigned long val = strtoul(p->accumulated, &end, 0); + if (val > UINT32_MAX || errno == ERANGE || end != myend) + goto err; + else + upb_sink_putuint32(&p->top->sink, parser_getsel(p), val); + break; + } + case UPB_TYPE_UINT64: { + unsigned long long val = strtoul(p->accumulated, &end, 0); + if (val > UINT64_MAX || errno == ERANGE || end != myend) + goto err; + else + upb_sink_putuint64(&p->top->sink, parser_getsel(p), val); + break; + } + case UPB_TYPE_DOUBLE: { + double val = strtod(p->accumulated, &end); + if (errno == ERANGE || end != myend) + goto err; + else + upb_sink_putdouble(&p->top->sink, parser_getsel(p), val); + break; + } + case UPB_TYPE_FLOAT: { + float val = strtod(p->accumulated, &end); + if (errno == ERANGE || end != myend) + goto err; + else + upb_sink_putfloat(&p->top->sink, parser_getsel(p), val); + break; + } + default: + assert(false); + } + + multipart_end(p); + + return true; + +err: + upb_status_seterrf(&p->status, "error parsing number: %s", buf); + upb_env_reporterror(p->env, &p->status); + multipart_end(p); + return false; +} + +static bool parser_putbool(upb_json_parser *p, bool val) { + bool ok; + + if (upb_fielddef_type(p->top->f) != UPB_TYPE_BOOL) { + upb_status_seterrf(&p->status, + "Boolean value specified for non-bool field: %s", + upb_fielddef_name(p->top->f)); + upb_env_reporterror(p->env, &p->status); + return false; + } + + ok = upb_sink_putbool(&p->top->sink, parser_getsel(p), val); + UPB_ASSERT_VAR(ok, ok); + + return true; +} + +static bool start_stringval(upb_json_parser *p) { + assert(p->top->f); + + if (upb_fielddef_isstring(p->top->f)) { + upb_jsonparser_frame *inner; + upb_selector_t sel; + + if (!check_stack(p)) return false; + + /* Start a new parser frame: parser frames correspond one-to-one with + * handler frames, and string events occur in a sub-frame. */ + inner = p->top + 1; + sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); + upb_sink_startstr(&p->top->sink, sel, 0, &inner->sink); + inner->m = p->top->m; + inner->f = p->top->f; + inner->is_map = false; + inner->is_mapentry = false; + p->top = inner; + + if (upb_fielddef_type(p->top->f) == UPB_TYPE_STRING) { + /* For STRING fields we push data directly to the handlers as it is + * parsed. We don't do this yet for BYTES fields, because our base64 + * decoder is not streaming. + * + * TODO(haberman): make base64 decoding streaming also. */ + multipart_start(p, getsel_for_handlertype(p, UPB_HANDLER_STRING)); + return true; + } else { + multipart_startaccum(p); + return true; + } + } else if (upb_fielddef_type(p->top->f) == UPB_TYPE_ENUM) { + /* No need to push a frame -- symbolic enum names in quotes remain in the + * current parser frame. + * + * Enum string values must accumulate so we can look up the value in a table + * once it is complete. */ + multipart_startaccum(p); + return true; + } else { + upb_status_seterrf(&p->status, + "String specified for non-string/non-enum field: %s", + upb_fielddef_name(p->top->f)); + upb_env_reporterror(p->env, &p->status); + return false; + } +} + +static bool end_stringval(upb_json_parser *p) { + bool ok = true; + + switch (upb_fielddef_type(p->top->f)) { + case UPB_TYPE_BYTES: + if (!base64_push(p, getsel_for_handlertype(p, UPB_HANDLER_STRING), + p->accumulated, p->accumulated_len)) { + return false; + } + /* Fall through. */ + + case UPB_TYPE_STRING: { + upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); + upb_sink_endstr(&p->top->sink, sel); + p->top--; + break; + } + + case UPB_TYPE_ENUM: { + /* Resolve enum symbolic name to integer value. */ + const upb_enumdef *enumdef = + (const upb_enumdef*)upb_fielddef_subdef(p->top->f); + + size_t len; + const char *buf = accumulate_getptr(p, &len); + + int32_t int_val = 0; + ok = upb_enumdef_ntoi(enumdef, buf, len, &int_val); + + if (ok) { + upb_selector_t sel = parser_getsel(p); + upb_sink_putint32(&p->top->sink, sel, int_val); + } else { + upb_status_seterrf(&p->status, "Enum value unknown: '%.*s'", len, buf); + upb_env_reporterror(p->env, &p->status); + } + + break; + } + + default: + assert(false); + upb_status_seterrmsg(&p->status, "Internal error in JSON decoder"); + upb_env_reporterror(p->env, &p->status); + ok = false; + break; + } + + multipart_end(p); + + return ok; +} + +static void start_member(upb_json_parser *p) { + assert(!p->top->f); + multipart_startaccum(p); +} + +/* Helper: invoked during parse_mapentry() to emit the mapentry message's key + * field based on the current contents of the accumulate buffer. */ +static bool parse_mapentry_key(upb_json_parser *p) { + + size_t len; + const char *buf = accumulate_getptr(p, &len); + + /* Emit the key field. We do a bit of ad-hoc parsing here because the + * parser state machine has already decided that this is a string field + * name, and we are reinterpreting it as some arbitrary key type. In + * particular, integer and bool keys are quoted, so we need to parse the + * quoted string contents here. */ + + p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_KEY); + if (p->top->f == NULL) { + upb_status_seterrmsg(&p->status, "mapentry message has no key"); + upb_env_reporterror(p->env, &p->status); + return false; + } + switch (upb_fielddef_type(p->top->f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_INT64: + case UPB_TYPE_UINT32: + case UPB_TYPE_UINT64: + /* Invoke end_number. The accum buffer has the number's text already. */ + if (!parse_number(p)) { + return false; + } + break; + case UPB_TYPE_BOOL: + if (len == 4 && !strncmp(buf, "true", 4)) { + if (!parser_putbool(p, true)) { + return false; + } + } else if (len == 5 && !strncmp(buf, "false", 5)) { + if (!parser_putbool(p, false)) { + return false; + } + } else { + upb_status_seterrmsg(&p->status, + "Map bool key not 'true' or 'false'"); + upb_env_reporterror(p->env, &p->status); + return false; + } + multipart_end(p); + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { + upb_sink subsink; + upb_selector_t sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSTR); + upb_sink_startstr(&p->top->sink, sel, len, &subsink); + sel = getsel_for_handlertype(p, UPB_HANDLER_STRING); + upb_sink_putstring(&subsink, sel, buf, len, NULL); + sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSTR); + upb_sink_endstr(&subsink, sel); + multipart_end(p); + break; + } + default: + upb_status_seterrmsg(&p->status, "Invalid field type for map key"); + upb_env_reporterror(p->env, &p->status); + return false; + } + + return true; +} + +/* Helper: emit one map entry (as a submessage in the map field sequence). This + * is invoked from end_membername(), at the end of the map entry's key string, + * with the map key in the accumulate buffer. It parses the key from that + * buffer, emits the handler calls to start the mapentry submessage (setting up + * its subframe in the process), and sets up state in the subframe so that the + * value parser (invoked next) will emit the mapentry's value field and then + * end the mapentry message. */ + +static bool handle_mapentry(upb_json_parser *p) { + const upb_fielddef *mapfield; + const upb_msgdef *mapentrymsg; + upb_jsonparser_frame *inner; + upb_selector_t sel; + + /* Map entry: p->top->sink is the seq frame, so we need to start a frame + * for the mapentry itself, and then set |f| in that frame so that the map + * value field is parsed, and also set a flag to end the frame after the + * map-entry value is parsed. */ + if (!check_stack(p)) return false; + + mapfield = p->top->mapfield; + mapentrymsg = upb_fielddef_msgsubdef(mapfield); + + inner = p->top + 1; + p->top->f = mapfield; + sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG); + upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink); + inner->m = mapentrymsg; + inner->mapfield = mapfield; + inner->is_map = false; + + /* Don't set this to true *yet* -- we reuse parsing handlers below to push + * the key field value to the sink, and these handlers will pop the frame + * if they see is_mapentry (when invoked by the parser state machine, they + * would have just seen the map-entry value, not key). */ + inner->is_mapentry = false; + p->top = inner; + + /* send STARTMSG in submsg frame. */ + upb_sink_startmsg(&p->top->sink); + + parse_mapentry_key(p); + + /* Set up the value field to receive the map-entry value. */ + p->top->f = upb_msgdef_itof(p->top->m, UPB_MAPENTRY_VALUE); + p->top->is_mapentry = true; /* set up to pop frame after value is parsed. */ + p->top->mapfield = mapfield; + if (p->top->f == NULL) { + upb_status_seterrmsg(&p->status, "mapentry message has no value"); + upb_env_reporterror(p->env, &p->status); + return false; + } + + return true; +} + +static bool end_membername(upb_json_parser *p) { + assert(!p->top->f); + + if (p->top->is_map) { + return handle_mapentry(p); + } else { + size_t len; + const char *buf = accumulate_getptr(p, &len); + const upb_fielddef *f = upb_msgdef_ntof(p->top->m, buf, len); + + if (!f) { + /* TODO(haberman): Ignore unknown fields if requested/configured to do + * so. */ + upb_status_seterrf(&p->status, "No such field: %.*s\n", (int)len, buf); + upb_env_reporterror(p->env, &p->status); + return false; + } + + p->top->f = f; + multipart_end(p); + + return true; + } +} + +static void end_member(upb_json_parser *p) { + /* If we just parsed a map-entry value, end that frame too. */ + if (p->top->is_mapentry) { + upb_status s = UPB_STATUS_INIT; + upb_selector_t sel; + bool ok; + const upb_fielddef *mapfield; + + assert(p->top > p->stack); + /* send ENDMSG on submsg. */ + upb_sink_endmsg(&p->top->sink, &s); + mapfield = p->top->mapfield; + + /* send ENDSUBMSG in repeated-field-of-mapentries frame. */ + p->top--; + ok = upb_handlers_getselector(mapfield, UPB_HANDLER_ENDSUBMSG, &sel); + UPB_ASSERT_VAR(ok, ok); + upb_sink_endsubmsg(&p->top->sink, sel); + } + + p->top->f = NULL; +} + +static bool start_subobject(upb_json_parser *p) { + assert(p->top->f); + + if (upb_fielddef_ismap(p->top->f)) { + upb_jsonparser_frame *inner; + upb_selector_t sel; + + /* Beginning of a map. Start a new parser frame in a repeated-field + * context. */ + if (!check_stack(p)) return false; + + inner = p->top + 1; + sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ); + upb_sink_startseq(&p->top->sink, sel, &inner->sink); + inner->m = upb_fielddef_msgsubdef(p->top->f); + inner->mapfield = p->top->f; + inner->f = NULL; + inner->is_map = true; + inner->is_mapentry = false; + p->top = inner; + + return true; + } else if (upb_fielddef_issubmsg(p->top->f)) { + upb_jsonparser_frame *inner; + upb_selector_t sel; + + /* Beginning of a subobject. Start a new parser frame in the submsg + * context. */ + if (!check_stack(p)) return false; + + inner = p->top + 1; + + sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSUBMSG); + upb_sink_startsubmsg(&p->top->sink, sel, &inner->sink); + inner->m = upb_fielddef_msgsubdef(p->top->f); + inner->f = NULL; + inner->is_map = false; + inner->is_mapentry = false; + p->top = inner; + + return true; + } else { + upb_status_seterrf(&p->status, + "Object specified for non-message/group field: %s", + upb_fielddef_name(p->top->f)); + upb_env_reporterror(p->env, &p->status); + return false; + } +} + +static void end_subobject(upb_json_parser *p) { + if (p->top->is_map) { + upb_selector_t sel; + p->top--; + sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ); + upb_sink_endseq(&p->top->sink, sel); + } else { + upb_selector_t sel; + p->top--; + sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSUBMSG); + upb_sink_endsubmsg(&p->top->sink, sel); + } +} + +static bool start_array(upb_json_parser *p) { + upb_jsonparser_frame *inner; + upb_selector_t sel; + + assert(p->top->f); + + if (!upb_fielddef_isseq(p->top->f)) { + upb_status_seterrf(&p->status, + "Array specified for non-repeated field: %s", + upb_fielddef_name(p->top->f)); + upb_env_reporterror(p->env, &p->status); + return false; + } + + if (!check_stack(p)) return false; + + inner = p->top + 1; + sel = getsel_for_handlertype(p, UPB_HANDLER_STARTSEQ); + upb_sink_startseq(&p->top->sink, sel, &inner->sink); + inner->m = p->top->m; + inner->f = p->top->f; + inner->is_map = false; + inner->is_mapentry = false; + p->top = inner; + + return true; +} + +static void end_array(upb_json_parser *p) { + upb_selector_t sel; + + assert(p->top > p->stack); + + p->top--; + sel = getsel_for_handlertype(p, UPB_HANDLER_ENDSEQ); + upb_sink_endseq(&p->top->sink, sel); +} + +static void start_object(upb_json_parser *p) { + if (!p->top->is_map) { + upb_sink_startmsg(&p->top->sink); + } +} + +static void end_object(upb_json_parser *p) { + if (!p->top->is_map) { + upb_status status; + upb_status_clear(&status); + upb_sink_endmsg(&p->top->sink, &status); + if (!upb_ok(&status)) { + upb_env_reporterror(p->env, &status); + } + } +} + + +#define CHECK_RETURN_TOP(x) if (!(x)) goto error + + +/* The actual parser **********************************************************/ + +/* What follows is the Ragel parser itself. The language is specified in Ragel + * and the actions call our C functions above. + * + * Ragel has an extensive set of functionality, and we use only a small part of + * it. There are many action types but we only use a few: + * + * ">" -- transition into a machine + * "%" -- transition out of a machine + * "@" -- transition into a final state of a machine. + * + * "@" transitions are tricky because a machine can transition into a final + * state repeatedly. But in some cases we know this can't happen, for example + * a string which is delimited by a final '"' can only transition into its + * final state once, when the closing '"' is seen. */ + + +#line 1218 "upb/json/parser.rl" + + + +#line 1130 "upb/json/parser.c" +static const char _json_actions[] = { + 0, 1, 0, 1, 2, 1, 3, 1, + 5, 1, 6, 1, 7, 1, 8, 1, + 10, 1, 12, 1, 13, 1, 14, 1, + 15, 1, 16, 1, 17, 1, 21, 1, + 25, 1, 27, 2, 3, 8, 2, 4, + 5, 2, 6, 2, 2, 6, 8, 2, + 11, 9, 2, 13, 15, 2, 14, 15, + 2, 18, 1, 2, 19, 27, 2, 20, + 9, 2, 22, 27, 2, 23, 27, 2, + 24, 27, 2, 26, 27, 3, 14, 11, + 9 +}; + +static const unsigned char _json_key_offsets[] = { + 0, 0, 4, 9, 14, 15, 19, 24, + 29, 34, 38, 42, 45, 48, 50, 54, + 58, 60, 62, 67, 69, 71, 80, 86, + 92, 98, 104, 106, 115, 116, 116, 116, + 121, 126, 131, 132, 133, 134, 135, 135, + 136, 137, 138, 138, 139, 140, 141, 141, + 146, 151, 152, 156, 161, 166, 171, 175, + 175, 178, 178, 178 +}; + +static const char _json_trans_keys[] = { + 32, 123, 9, 13, 32, 34, 125, 9, + 13, 32, 34, 125, 9, 13, 34, 32, + 58, 9, 13, 32, 93, 125, 9, 13, + 32, 44, 125, 9, 13, 32, 44, 125, + 9, 13, 32, 34, 9, 13, 45, 48, + 49, 57, 48, 49, 57, 46, 69, 101, + 48, 57, 69, 101, 48, 57, 43, 45, + 48, 57, 48, 57, 48, 57, 46, 69, + 101, 48, 57, 34, 92, 34, 92, 34, + 47, 92, 98, 102, 110, 114, 116, 117, + 48, 57, 65, 70, 97, 102, 48, 57, + 65, 70, 97, 102, 48, 57, 65, 70, + 97, 102, 48, 57, 65, 70, 97, 102, + 34, 92, 34, 45, 91, 102, 110, 116, + 123, 48, 57, 34, 32, 93, 125, 9, + 13, 32, 44, 93, 9, 13, 32, 93, + 125, 9, 13, 97, 108, 115, 101, 117, + 108, 108, 114, 117, 101, 32, 34, 125, + 9, 13, 32, 34, 125, 9, 13, 34, + 32, 58, 9, 13, 32, 93, 125, 9, + 13, 32, 44, 125, 9, 13, 32, 44, + 125, 9, 13, 32, 34, 9, 13, 32, + 9, 13, 0 +}; + +static const char _json_single_lengths[] = { + 0, 2, 3, 3, 1, 2, 3, 3, + 3, 2, 2, 1, 3, 0, 2, 2, + 0, 0, 3, 2, 2, 9, 0, 0, + 0, 0, 2, 7, 1, 0, 0, 3, + 3, 3, 1, 1, 1, 1, 0, 1, + 1, 1, 0, 1, 1, 1, 0, 3, + 3, 1, 2, 3, 3, 3, 2, 0, + 1, 0, 0, 0 +}; + +static const char _json_range_lengths[] = { + 0, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 3, 3, + 3, 3, 0, 1, 0, 0, 0, 1, + 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 1, 1, 1, 1, 1, 0, + 1, 0, 0, 0 +}; + +static const short _json_index_offsets[] = { + 0, 0, 4, 9, 14, 16, 20, 25, + 30, 35, 39, 43, 46, 50, 52, 56, + 60, 62, 64, 69, 72, 75, 85, 89, + 93, 97, 101, 104, 113, 115, 116, 117, + 122, 127, 132, 134, 136, 138, 140, 141, + 143, 145, 147, 148, 150, 152, 154, 155, + 160, 165, 167, 171, 176, 181, 186, 190, + 191, 194, 195, 196 +}; + +static const char _json_indicies[] = { + 0, 2, 0, 1, 3, 4, 5, 3, + 1, 6, 7, 8, 6, 1, 9, 1, + 10, 11, 10, 1, 11, 1, 1, 11, + 12, 13, 14, 15, 13, 1, 16, 17, + 8, 16, 1, 17, 7, 17, 1, 18, + 19, 20, 1, 19, 20, 1, 22, 23, + 23, 21, 24, 1, 23, 23, 24, 21, + 25, 25, 26, 1, 26, 1, 26, 21, + 22, 23, 23, 20, 21, 28, 29, 27, + 31, 32, 30, 33, 33, 33, 33, 33, + 33, 33, 33, 34, 1, 35, 35, 35, + 1, 36, 36, 36, 1, 37, 37, 37, + 1, 38, 38, 38, 1, 40, 41, 39, + 42, 43, 44, 45, 46, 47, 48, 43, + 1, 49, 1, 50, 51, 53, 54, 1, + 53, 52, 55, 56, 54, 55, 1, 56, + 1, 1, 56, 52, 57, 1, 58, 1, + 59, 1, 60, 1, 61, 62, 1, 63, + 1, 64, 1, 65, 66, 1, 67, 1, + 68, 1, 69, 70, 71, 72, 70, 1, + 73, 74, 75, 73, 1, 76, 1, 77, + 78, 77, 1, 78, 1, 1, 78, 79, + 80, 81, 82, 80, 1, 83, 84, 75, + 83, 1, 84, 74, 84, 1, 85, 86, + 86, 1, 1, 1, 1, 0 +}; + +static const char _json_trans_targs[] = { + 1, 0, 2, 3, 4, 56, 3, 4, + 56, 5, 5, 6, 7, 8, 9, 56, + 8, 9, 11, 12, 18, 57, 13, 15, + 14, 16, 17, 20, 58, 21, 20, 58, + 21, 19, 22, 23, 24, 25, 26, 20, + 58, 21, 28, 30, 31, 34, 39, 43, + 47, 29, 59, 59, 32, 31, 29, 32, + 33, 35, 36, 37, 38, 59, 40, 41, + 42, 59, 44, 45, 46, 59, 48, 49, + 55, 48, 49, 55, 50, 50, 51, 52, + 53, 54, 55, 53, 54, 59, 56 +}; + +static const char _json_trans_actions[] = { + 0, 0, 0, 21, 77, 53, 0, 47, + 23, 17, 0, 0, 15, 19, 19, 50, + 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 0, 3, 13, 0, 0, 35, + 5, 11, 0, 38, 7, 7, 7, 41, + 44, 9, 62, 56, 25, 0, 0, 0, + 31, 29, 33, 59, 15, 0, 27, 0, + 0, 0, 0, 0, 0, 68, 0, 0, + 0, 71, 0, 0, 0, 65, 21, 77, + 53, 0, 47, 23, 17, 0, 0, 15, + 19, 19, 50, 0, 0, 74, 0 +}; + +static const int json_start = 1; + +static const int json_en_number_machine = 10; +static const int json_en_string_machine = 19; +static const int json_en_value_machine = 27; +static const int json_en_main = 1; + + +#line 1221 "upb/json/parser.rl" + +size_t parse(void *closure, const void *hd, const char *buf, size_t size, + const upb_bufhandle *handle) { + upb_json_parser *parser = closure; + + /* Variables used by Ragel's generated code. */ + int cs = parser->current_state; + int *stack = parser->parser_stack; + int top = parser->parser_top; + + const char *p = buf; + const char *pe = buf + size; + + parser->handle = handle; + + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + capture_resume(parser, buf); + + +#line 1301 "upb/json/parser.c" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _json_trans_keys + _json_key_offsets[cs]; + _trans = _json_index_offsets[cs]; + + _klen = _json_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (unsigned int)(_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _json_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += (unsigned int)((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + _trans = _json_indicies[_trans]; + cs = _json_trans_targs[_trans]; + + if ( _json_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _json_actions + _json_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 1133 "upb/json/parser.rl" + { p--; {cs = stack[--top]; goto _again;} } + break; + case 1: +#line 1134 "upb/json/parser.rl" + { p--; {stack[top++] = cs; cs = 10; goto _again;} } + break; + case 2: +#line 1138 "upb/json/parser.rl" + { start_text(parser, p); } + break; + case 3: +#line 1139 "upb/json/parser.rl" + { CHECK_RETURN_TOP(end_text(parser, p)); } + break; + case 4: +#line 1145 "upb/json/parser.rl" + { start_hex(parser); } + break; + case 5: +#line 1146 "upb/json/parser.rl" + { hexdigit(parser, p); } + break; + case 6: +#line 1147 "upb/json/parser.rl" + { CHECK_RETURN_TOP(end_hex(parser)); } + break; + case 7: +#line 1153 "upb/json/parser.rl" + { CHECK_RETURN_TOP(escape(parser, p)); } + break; + case 8: +#line 1159 "upb/json/parser.rl" + { p--; {cs = stack[--top]; goto _again;} } + break; + case 9: +#line 1162 "upb/json/parser.rl" + { {stack[top++] = cs; cs = 19; goto _again;} } + break; + case 10: +#line 1164 "upb/json/parser.rl" + { p--; {stack[top++] = cs; cs = 27; goto _again;} } + break; + case 11: +#line 1169 "upb/json/parser.rl" + { start_member(parser); } + break; + case 12: +#line 1170 "upb/json/parser.rl" + { CHECK_RETURN_TOP(end_membername(parser)); } + break; + case 13: +#line 1173 "upb/json/parser.rl" + { end_member(parser); } + break; + case 14: +#line 1179 "upb/json/parser.rl" + { start_object(parser); } + break; + case 15: +#line 1182 "upb/json/parser.rl" + { end_object(parser); } + break; + case 16: +#line 1188 "upb/json/parser.rl" + { CHECK_RETURN_TOP(start_array(parser)); } + break; + case 17: +#line 1192 "upb/json/parser.rl" + { end_array(parser); } + break; + case 18: +#line 1197 "upb/json/parser.rl" + { start_number(parser, p); } + break; + case 19: +#line 1198 "upb/json/parser.rl" + { CHECK_RETURN_TOP(end_number(parser, p)); } + break; + case 20: +#line 1200 "upb/json/parser.rl" + { CHECK_RETURN_TOP(start_stringval(parser)); } + break; + case 21: +#line 1201 "upb/json/parser.rl" + { CHECK_RETURN_TOP(end_stringval(parser)); } + break; + case 22: +#line 1203 "upb/json/parser.rl" + { CHECK_RETURN_TOP(parser_putbool(parser, true)); } + break; + case 23: +#line 1205 "upb/json/parser.rl" + { CHECK_RETURN_TOP(parser_putbool(parser, false)); } + break; + case 24: +#line 1207 "upb/json/parser.rl" + { /* null value */ } + break; + case 25: +#line 1209 "upb/json/parser.rl" + { CHECK_RETURN_TOP(start_subobject(parser)); } + break; + case 26: +#line 1210 "upb/json/parser.rl" + { end_subobject(parser); } + break; + case 27: +#line 1215 "upb/json/parser.rl" + { p--; {cs = stack[--top]; goto _again;} } + break; +#line 1487 "upb/json/parser.c" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 1242 "upb/json/parser.rl" + + if (p != pe) { + upb_status_seterrf(&parser->status, "Parse error at %s\n", p); + upb_env_reporterror(parser->env, &parser->status); + } else { + capture_suspend(parser, &p); + } + +error: + /* Save parsing state back to parser. */ + parser->current_state = cs; + parser->parser_top = top; + + return p - buf; +} + +bool end(void *closure, const void *hd) { + UPB_UNUSED(closure); + UPB_UNUSED(hd); + + /* Prevent compile warning on unused static constants. */ + UPB_UNUSED(json_start); + UPB_UNUSED(json_en_number_machine); + UPB_UNUSED(json_en_string_machine); + UPB_UNUSED(json_en_value_machine); + UPB_UNUSED(json_en_main); + return true; +} + +static void json_parser_reset(upb_json_parser *p) { + int cs; + int top; + + p->top = p->stack; + p->top->f = NULL; + p->top->is_map = false; + p->top->is_mapentry = false; + + /* Emit Ragel initialization of the parser. */ + +#line 1541 "upb/json/parser.c" + { + cs = json_start; + top = 0; + } + +#line 1282 "upb/json/parser.rl" + p->current_state = cs; + p->parser_top = top; + accumulate_clear(p); + p->multipart_state = MULTIPART_INACTIVE; + p->capture = NULL; + p->accumulated = NULL; + upb_status_clear(&p->status); +} + + +/* Public API *****************************************************************/ + +upb_json_parser *upb_json_parser_create(upb_env *env, upb_sink *output) { +#ifndef NDEBUG + const size_t size_before = upb_env_bytesallocated(env); +#endif + upb_json_parser *p = upb_env_malloc(env, sizeof(upb_json_parser)); + if (!p) return false; + + p->env = env; + p->limit = p->stack + UPB_JSON_MAX_DEPTH; + p->accumulate_buf = NULL; + p->accumulate_buf_size = 0; + upb_byteshandler_init(&p->input_handler_); + upb_byteshandler_setstring(&p->input_handler_, parse, NULL); + upb_byteshandler_setendstr(&p->input_handler_, end, NULL); + upb_bytessink_reset(&p->input_, &p->input_handler_, p); + + json_parser_reset(p); + upb_sink_reset(&p->top->sink, output->handlers, output->closure); + p->top->m = upb_handlers_msgdef(output->handlers); + + /* If this fails, uncomment and increase the value in parser.h. */ + /* fprintf(stderr, "%zd\n", upb_env_bytesallocated(env) - size_before); */ + assert(upb_env_bytesallocated(env) - size_before <= UPB_JSON_PARSER_SIZE); + return p; +} + +upb_bytessink *upb_json_parser_input(upb_json_parser *p) { + return &p->input_; +} +/* +** This currently uses snprintf() to format primitives, and could be optimized +** further. +*/ + + +#include +#include +#include +#include + +struct upb_json_printer { + upb_sink input_; + /* BytesSink closure. */ + void *subc_; + upb_bytessink *output_; + + /* We track the depth so that we know when to emit startstr/endstr on the + * output. */ + int depth_; + + /* Have we emitted the first element? This state is necessary to emit commas + * without leaving a trailing comma in arrays/maps. We keep this state per + * frame depth. + * + * Why max_depth * 2? UPB_MAX_HANDLER_DEPTH counts depth as nested messages. + * We count frames (contexts in which we separate elements by commas) as both + * repeated fields and messages (maps), and the worst case is a + * message->repeated field->submessage->repeated field->... nesting. */ + bool first_elem_[UPB_MAX_HANDLER_DEPTH * 2]; +}; + +/* StringPiece; a pointer plus a length. */ +typedef struct { + const char *ptr; + size_t len; +} strpc; + +strpc *newstrpc(upb_handlers *h, const upb_fielddef *f) { + strpc *ret = malloc(sizeof(*ret)); + ret->ptr = upb_fielddef_name(f); + ret->len = strlen(ret->ptr); + upb_handlers_addcleanup(h, ret, free); + return ret; +} + +/* ------------ JSON string printing: values, maps, arrays ------------------ */ + +static void print_data( + upb_json_printer *p, const char *buf, unsigned int len) { + /* TODO: Will need to change if we support pushback from the sink. */ + size_t n = upb_bytessink_putbuf(p->output_, p->subc_, buf, len, NULL); + UPB_ASSERT_VAR(n, n == len); +} + +static void print_comma(upb_json_printer *p) { + if (!p->first_elem_[p->depth_]) { + print_data(p, ",", 1); + } + p->first_elem_[p->depth_] = false; +} + +/* Helpers that print properly formatted elements to the JSON output stream. */ + +/* Used for escaping control chars in strings. */ +static const char kControlCharLimit = 0x20; + +UPB_INLINE bool is_json_escaped(char c) { + /* See RFC 4627. */ + unsigned char uc = (unsigned char)c; + return uc < kControlCharLimit || uc == '"' || uc == '\\'; +} + +UPB_INLINE char* json_nice_escape(char c) { + switch (c) { + case '"': return "\\\""; + case '\\': return "\\\\"; + case '\b': return "\\b"; + case '\f': return "\\f"; + case '\n': return "\\n"; + case '\r': return "\\r"; + case '\t': return "\\t"; + default: return NULL; + } +} + +/* Write a properly escaped string chunk. The surrounding quotes are *not* + * printed; this is so that the caller has the option of emitting the string + * content in chunks. */ +static void putstring(upb_json_printer *p, const char *buf, unsigned int len) { + const char* unescaped_run = NULL; + unsigned int i; + for (i = 0; i < len; i++) { + char c = buf[i]; + /* Handle escaping. */ + if (is_json_escaped(c)) { + /* Use a "nice" escape, like \n, if one exists for this character. */ + const char* escape = json_nice_escape(c); + /* If we don't have a specific 'nice' escape code, use a \uXXXX-style + * escape. */ + char escape_buf[8]; + if (!escape) { + unsigned char byte = (unsigned char)c; + _upb_snprintf(escape_buf, sizeof(escape_buf), "\\u%04x", (int)byte); + escape = escape_buf; + } + + /* N.B. that we assume that the input encoding is equal to the output + * encoding (both UTF-8 for now), so for chars >= 0x20 and != \, ", we + * can simply pass the bytes through. */ + + /* If there's a current run of unescaped chars, print that run first. */ + if (unescaped_run) { + print_data(p, unescaped_run, &buf[i] - unescaped_run); + unescaped_run = NULL; + } + /* Then print the escape code. */ + print_data(p, escape, strlen(escape)); + } else { + /* Add to the current unescaped run of characters. */ + if (unescaped_run == NULL) { + unescaped_run = &buf[i]; + } + } + } + + /* If the string ended in a run of unescaped characters, print that last run. */ + if (unescaped_run) { + print_data(p, unescaped_run, &buf[len] - unescaped_run); + } +} + +#define CHKLENGTH(x) if (!(x)) return -1; + +/* Helpers that format floating point values according to our custom formats. + * Right now we use %.8g and %.17g for float/double, respectively, to match + * proto2::util::JsonFormat's defaults. May want to change this later. */ + +static size_t fmt_double(double val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "%.17g", val); + CHKLENGTH(n > 0 && n < length); + return n; +} + +static size_t fmt_float(float val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "%.8g", val); + CHKLENGTH(n > 0 && n < length); + return n; +} + +static size_t fmt_bool(bool val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "%s", (val ? "true" : "false")); + CHKLENGTH(n > 0 && n < length); + return n; +} + +static size_t fmt_int64(long val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "%ld", val); + CHKLENGTH(n > 0 && n < length); + return n; +} + +static size_t fmt_uint64(unsigned long long val, char* buf, size_t length) { + size_t n = _upb_snprintf(buf, length, "%llu", val); + CHKLENGTH(n > 0 && n < length); + return n; +} + +/* Print a map key given a field name. Called by scalar field handlers and by + * startseq for repeated fields. */ +static bool putkey(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + const strpc *key = handler_data; + print_comma(p); + print_data(p, "\"", 1); + putstring(p, key->ptr, key->len); + print_data(p, "\":", 2); + return true; +} + +#define CHKFMT(val) if ((val) == (size_t)-1) return false; +#define CHK(val) if (!(val)) return false; + +#define TYPE_HANDLERS(type, fmt_func) \ + static bool put##type(void *closure, const void *handler_data, type val) { \ + upb_json_printer *p = closure; \ + char data[64]; \ + size_t length = fmt_func(val, data, sizeof(data)); \ + UPB_UNUSED(handler_data); \ + CHKFMT(length); \ + print_data(p, data, length); \ + return true; \ + } \ + static bool scalar_##type(void *closure, const void *handler_data, \ + type val) { \ + CHK(putkey(closure, handler_data)); \ + CHK(put##type(closure, handler_data, val)); \ + return true; \ + } \ + static bool repeated_##type(void *closure, const void *handler_data, \ + type val) { \ + upb_json_printer *p = closure; \ + print_comma(p); \ + CHK(put##type(closure, handler_data, val)); \ + return true; \ + } + +#define TYPE_HANDLERS_MAPKEY(type, fmt_func) \ + static bool putmapkey_##type(void *closure, const void *handler_data, \ + type val) { \ + upb_json_printer *p = closure; \ + print_data(p, "\"", 1); \ + CHK(put##type(closure, handler_data, val)); \ + print_data(p, "\":", 2); \ + return true; \ + } + +TYPE_HANDLERS(double, fmt_double) +TYPE_HANDLERS(float, fmt_float) +TYPE_HANDLERS(bool, fmt_bool) +TYPE_HANDLERS(int32_t, fmt_int64) +TYPE_HANDLERS(uint32_t, fmt_int64) +TYPE_HANDLERS(int64_t, fmt_int64) +TYPE_HANDLERS(uint64_t, fmt_uint64) + +/* double and float are not allowed to be map keys. */ +TYPE_HANDLERS_MAPKEY(bool, fmt_bool) +TYPE_HANDLERS_MAPKEY(int32_t, fmt_int64) +TYPE_HANDLERS_MAPKEY(uint32_t, fmt_int64) +TYPE_HANDLERS_MAPKEY(int64_t, fmt_int64) +TYPE_HANDLERS_MAPKEY(uint64_t, fmt_uint64) + +#undef TYPE_HANDLERS +#undef TYPE_HANDLERS_MAPKEY + +typedef struct { + void *keyname; + const upb_enumdef *enumdef; +} EnumHandlerData; + +static bool scalar_enum(void *closure, const void *handler_data, + int32_t val) { + const EnumHandlerData *hd = handler_data; + upb_json_printer *p = closure; + const char *symbolic_name; + + CHK(putkey(closure, hd->keyname)); + + symbolic_name = upb_enumdef_iton(hd->enumdef, val); + if (symbolic_name) { + print_data(p, "\"", 1); + putstring(p, symbolic_name, strlen(symbolic_name)); + print_data(p, "\"", 1); + } else { + putint32_t(closure, NULL, val); + } + + return true; +} + +static void print_enum_symbolic_name(upb_json_printer *p, + const upb_enumdef *def, + int32_t val) { + const char *symbolic_name = upb_enumdef_iton(def, val); + if (symbolic_name) { + print_data(p, "\"", 1); + putstring(p, symbolic_name, strlen(symbolic_name)); + print_data(p, "\"", 1); + } else { + putint32_t(p, NULL, val); + } +} + +static bool repeated_enum(void *closure, const void *handler_data, + int32_t val) { + const EnumHandlerData *hd = handler_data; + upb_json_printer *p = closure; + print_comma(p); + + print_enum_symbolic_name(p, hd->enumdef, val); + + return true; +} + +static bool mapvalue_enum(void *closure, const void *handler_data, + int32_t val) { + const EnumHandlerData *hd = handler_data; + upb_json_printer *p = closure; + + print_enum_symbolic_name(p, hd->enumdef, val); + + return true; +} + +static void *scalar_startsubmsg(void *closure, const void *handler_data) { + return putkey(closure, handler_data) ? closure : UPB_BREAK; +} + +static void *repeated_startsubmsg(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + print_comma(p); + return closure; +} + +static void start_frame(upb_json_printer *p) { + p->depth_++; + p->first_elem_[p->depth_] = true; + print_data(p, "{", 1); +} + +static void end_frame(upb_json_printer *p) { + print_data(p, "}", 1); + p->depth_--; +} + +static bool printer_startmsg(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + if (p->depth_ == 0) { + upb_bytessink_start(p->output_, 0, &p->subc_); + } + start_frame(p); + return true; +} + +static bool printer_endmsg(void *closure, const void *handler_data, upb_status *s) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + UPB_UNUSED(s); + end_frame(p); + if (p->depth_ == 0) { + upb_bytessink_end(p->output_); + } + return true; +} + +static void *startseq(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + CHK(putkey(closure, handler_data)); + p->depth_++; + p->first_elem_[p->depth_] = true; + print_data(p, "[", 1); + return closure; +} + +static bool endseq(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + print_data(p, "]", 1); + p->depth_--; + return true; +} + +static void *startmap(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + CHK(putkey(closure, handler_data)); + p->depth_++; + p->first_elem_[p->depth_] = true; + print_data(p, "{", 1); + return closure; +} + +static bool endmap(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + print_data(p, "}", 1); + p->depth_--; + return true; +} + +static size_t putstr(void *closure, const void *handler_data, const char *str, + size_t len, const upb_bufhandle *handle) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + UPB_UNUSED(handle); + putstring(p, str, len); + return len; +} + +/* This has to Base64 encode the bytes, because JSON has no "bytes" type. */ +static size_t putbytes(void *closure, const void *handler_data, const char *str, + size_t len, const upb_bufhandle *handle) { + upb_json_printer *p = closure; + + /* This is the regular base64, not the "web-safe" version. */ + static const char base64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /* Base64-encode. */ + char data[16000]; + const char *limit = data + sizeof(data); + const unsigned char *from = (const unsigned char*)str; + char *to = data; + size_t remaining = len; + size_t bytes; + + UPB_UNUSED(handler_data); + UPB_UNUSED(handle); + + while (remaining > 2) { + /* TODO(haberman): handle encoded lengths > sizeof(data) */ + UPB_ASSERT_VAR(limit, (limit - to) >= 4); + + to[0] = base64[from[0] >> 2]; + to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)]; + to[2] = base64[((from[1] & 0xf) << 2) | (from[2] >> 6)]; + to[3] = base64[from[2] & 0x3f]; + + remaining -= 3; + to += 4; + from += 3; + } + + switch (remaining) { + case 2: + to[0] = base64[from[0] >> 2]; + to[1] = base64[((from[0] & 0x3) << 4) | (from[1] >> 4)]; + to[2] = base64[(from[1] & 0xf) << 2]; + to[3] = '='; + to += 4; + from += 2; + break; + case 1: + to[0] = base64[from[0] >> 2]; + to[1] = base64[((from[0] & 0x3) << 4)]; + to[2] = '='; + to[3] = '='; + to += 4; + from += 1; + break; + } + + bytes = to - data; + print_data(p, "\"", 1); + putstring(p, data, bytes); + print_data(p, "\"", 1); + return len; +} + +static void *scalar_startstr(void *closure, const void *handler_data, + size_t size_hint) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + UPB_UNUSED(size_hint); + CHK(putkey(closure, handler_data)); + print_data(p, "\"", 1); + return p; +} + +static size_t scalar_str(void *closure, const void *handler_data, + const char *str, size_t len, + const upb_bufhandle *handle) { + CHK(putstr(closure, handler_data, str, len, handle)); + return len; +} + +static bool scalar_endstr(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + print_data(p, "\"", 1); + return true; +} + +static void *repeated_startstr(void *closure, const void *handler_data, + size_t size_hint) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + UPB_UNUSED(size_hint); + print_comma(p); + print_data(p, "\"", 1); + return p; +} + +static size_t repeated_str(void *closure, const void *handler_data, + const char *str, size_t len, + const upb_bufhandle *handle) { + CHK(putstr(closure, handler_data, str, len, handle)); + return len; +} + +static bool repeated_endstr(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + print_data(p, "\"", 1); + return true; +} + +static void *mapkeyval_startstr(void *closure, const void *handler_data, + size_t size_hint) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + UPB_UNUSED(size_hint); + print_data(p, "\"", 1); + return p; +} + +static size_t mapkey_str(void *closure, const void *handler_data, + const char *str, size_t len, + const upb_bufhandle *handle) { + CHK(putstr(closure, handler_data, str, len, handle)); + return len; +} + +static bool mapkey_endstr(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + print_data(p, "\":", 2); + return true; +} + +static bool mapvalue_endstr(void *closure, const void *handler_data) { + upb_json_printer *p = closure; + UPB_UNUSED(handler_data); + print_data(p, "\"", 1); + return true; +} + +static size_t scalar_bytes(void *closure, const void *handler_data, + const char *str, size_t len, + const upb_bufhandle *handle) { + CHK(putkey(closure, handler_data)); + CHK(putbytes(closure, handler_data, str, len, handle)); + return len; +} + +static size_t repeated_bytes(void *closure, const void *handler_data, + const char *str, size_t len, + const upb_bufhandle *handle) { + upb_json_printer *p = closure; + print_comma(p); + CHK(putbytes(closure, handler_data, str, len, handle)); + return len; +} + +static size_t mapkey_bytes(void *closure, const void *handler_data, + const char *str, size_t len, + const upb_bufhandle *handle) { + upb_json_printer *p = closure; + CHK(putbytes(closure, handler_data, str, len, handle)); + print_data(p, ":", 1); + return len; +} + +static void set_enum_hd(upb_handlers *h, + const upb_fielddef *f, + upb_handlerattr *attr) { + EnumHandlerData *hd = malloc(sizeof(EnumHandlerData)); + hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f); + hd->keyname = newstrpc(h, f); + upb_handlers_addcleanup(h, hd, free); + upb_handlerattr_sethandlerdata(attr, hd); +} + +/* Set up handlers for a mapentry submessage (i.e., an individual key/value pair + * in a map). + * + * TODO: Handle missing key, missing value, out-of-order key/value, or repeated + * key or value cases properly. The right way to do this is to allocate a + * temporary structure at the start of a mapentry submessage, store key and + * value data in it as key and value handlers are called, and then print the + * key/value pair once at the end of the submessage. If we don't do this, we + * should at least detect the case and throw an error. However, so far all of + * our sources that emit mapentry messages do so canonically (with one key + * field, and then one value field), so this is not a pressing concern at the + * moment. */ +void printer_sethandlers_mapentry(const void *closure, upb_handlers *h) { + const upb_msgdef *md = upb_handlers_msgdef(h); + + /* A mapentry message is printed simply as '"key": value'. Rather than + * special-case key and value for every type below, we just handle both + * fields explicitly here. */ + const upb_fielddef* key_field = upb_msgdef_itof(md, UPB_MAPENTRY_KEY); + const upb_fielddef* value_field = upb_msgdef_itof(md, UPB_MAPENTRY_VALUE); + + upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER; + + UPB_UNUSED(closure); + + switch (upb_fielddef_type(key_field)) { + case UPB_TYPE_INT32: + upb_handlers_setint32(h, key_field, putmapkey_int32_t, &empty_attr); + break; + case UPB_TYPE_INT64: + upb_handlers_setint64(h, key_field, putmapkey_int64_t, &empty_attr); + break; + case UPB_TYPE_UINT32: + upb_handlers_setuint32(h, key_field, putmapkey_uint32_t, &empty_attr); + break; + case UPB_TYPE_UINT64: + upb_handlers_setuint64(h, key_field, putmapkey_uint64_t, &empty_attr); + break; + case UPB_TYPE_BOOL: + upb_handlers_setbool(h, key_field, putmapkey_bool, &empty_attr); + break; + case UPB_TYPE_STRING: + upb_handlers_setstartstr(h, key_field, mapkeyval_startstr, &empty_attr); + upb_handlers_setstring(h, key_field, mapkey_str, &empty_attr); + upb_handlers_setendstr(h, key_field, mapkey_endstr, &empty_attr); + break; + case UPB_TYPE_BYTES: + upb_handlers_setstring(h, key_field, mapkey_bytes, &empty_attr); + break; + default: + assert(false); + break; + } + + switch (upb_fielddef_type(value_field)) { + case UPB_TYPE_INT32: + upb_handlers_setint32(h, value_field, putint32_t, &empty_attr); + break; + case UPB_TYPE_INT64: + upb_handlers_setint64(h, value_field, putint64_t, &empty_attr); + break; + case UPB_TYPE_UINT32: + upb_handlers_setuint32(h, value_field, putuint32_t, &empty_attr); + break; + case UPB_TYPE_UINT64: + upb_handlers_setuint64(h, value_field, putuint64_t, &empty_attr); + break; + case UPB_TYPE_BOOL: + upb_handlers_setbool(h, value_field, putbool, &empty_attr); + break; + case UPB_TYPE_FLOAT: + upb_handlers_setfloat(h, value_field, putfloat, &empty_attr); + break; + case UPB_TYPE_DOUBLE: + upb_handlers_setdouble(h, value_field, putdouble, &empty_attr); + break; + case UPB_TYPE_STRING: + upb_handlers_setstartstr(h, value_field, mapkeyval_startstr, &empty_attr); + upb_handlers_setstring(h, value_field, putstr, &empty_attr); + upb_handlers_setendstr(h, value_field, mapvalue_endstr, &empty_attr); + break; + case UPB_TYPE_BYTES: + upb_handlers_setstring(h, value_field, putbytes, &empty_attr); + break; + case UPB_TYPE_ENUM: { + upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER; + set_enum_hd(h, value_field, &enum_attr); + upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr); + upb_handlerattr_uninit(&enum_attr); + break; + } + case UPB_TYPE_MESSAGE: + /* No handler necessary -- the submsg handlers will print the message + * as appropriate. */ + break; + } + + upb_handlerattr_uninit(&empty_attr); +} + +void printer_sethandlers(const void *closure, upb_handlers *h) { + const upb_msgdef *md = upb_handlers_msgdef(h); + bool is_mapentry = upb_msgdef_mapentry(md); + upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER; + upb_msg_field_iter i; + + UPB_UNUSED(closure); + + if (is_mapentry) { + /* mapentry messages are sufficiently different that we handle them + * separately. */ + printer_sethandlers_mapentry(closure, h); + return; + } + + upb_handlers_setstartmsg(h, printer_startmsg, &empty_attr); + upb_handlers_setendmsg(h, printer_endmsg, &empty_attr); + +#define TYPE(type, name, ctype) \ + case type: \ + if (upb_fielddef_isseq(f)) { \ + upb_handlers_set##name(h, f, repeated_##ctype, &empty_attr); \ + } else { \ + upb_handlers_set##name(h, f, scalar_##ctype, &name_attr); \ + } \ + break; + + upb_msg_field_begin(&i, md); + for(; !upb_msg_field_done(&i); upb_msg_field_next(&i)) { + const upb_fielddef *f = upb_msg_iter_field(&i); + + upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER; + upb_handlerattr_sethandlerdata(&name_attr, newstrpc(h, f)); + + if (upb_fielddef_ismap(f)) { + upb_handlers_setstartseq(h, f, startmap, &name_attr); + upb_handlers_setendseq(h, f, endmap, &name_attr); + } else if (upb_fielddef_isseq(f)) { + upb_handlers_setstartseq(h, f, startseq, &name_attr); + upb_handlers_setendseq(h, f, endseq, &empty_attr); + } + + switch (upb_fielddef_type(f)) { + TYPE(UPB_TYPE_FLOAT, float, float); + TYPE(UPB_TYPE_DOUBLE, double, double); + TYPE(UPB_TYPE_BOOL, bool, bool); + TYPE(UPB_TYPE_INT32, int32, int32_t); + TYPE(UPB_TYPE_UINT32, uint32, uint32_t); + TYPE(UPB_TYPE_INT64, int64, int64_t); + TYPE(UPB_TYPE_UINT64, uint64, uint64_t); + case UPB_TYPE_ENUM: { + /* For now, we always emit symbolic names for enums. We may want an + * option later to control this behavior, but we will wait for a real + * need first. */ + upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER; + set_enum_hd(h, f, &enum_attr); + + if (upb_fielddef_isseq(f)) { + upb_handlers_setint32(h, f, repeated_enum, &enum_attr); + } else { + upb_handlers_setint32(h, f, scalar_enum, &enum_attr); + } + + upb_handlerattr_uninit(&enum_attr); + break; + } + case UPB_TYPE_STRING: + if (upb_fielddef_isseq(f)) { + upb_handlers_setstartstr(h, f, repeated_startstr, &empty_attr); + upb_handlers_setstring(h, f, repeated_str, &empty_attr); + upb_handlers_setendstr(h, f, repeated_endstr, &empty_attr); + } else { + upb_handlers_setstartstr(h, f, scalar_startstr, &name_attr); + upb_handlers_setstring(h, f, scalar_str, &empty_attr); + upb_handlers_setendstr(h, f, scalar_endstr, &empty_attr); + } + break; + case UPB_TYPE_BYTES: + /* XXX: this doesn't support strings that span buffers yet. The base64 + * encoder will need to be made resumable for this to work properly. */ + if (upb_fielddef_isseq(f)) { + upb_handlers_setstring(h, f, repeated_bytes, &empty_attr); + } else { + upb_handlers_setstring(h, f, scalar_bytes, &name_attr); + } + break; + case UPB_TYPE_MESSAGE: + if (upb_fielddef_isseq(f)) { + upb_handlers_setstartsubmsg(h, f, repeated_startsubmsg, &name_attr); + } else { + upb_handlers_setstartsubmsg(h, f, scalar_startsubmsg, &name_attr); + } + break; + } + + upb_handlerattr_uninit(&name_attr); + } + + upb_handlerattr_uninit(&empty_attr); +#undef TYPE +} + +static void json_printer_reset(upb_json_printer *p) { + p->depth_ = 0; +} + + +/* Public API *****************************************************************/ + +upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h, + upb_bytessink *output) { +#ifndef NDEBUG + size_t size_before = upb_env_bytesallocated(e); +#endif + + upb_json_printer *p = upb_env_malloc(e, sizeof(upb_json_printer)); + if (!p) return NULL; + + p->output_ = output; + json_printer_reset(p); + upb_sink_reset(&p->input_, h, p); + + /* If this fails, increase the value in printer.h. */ + assert(upb_env_bytesallocated(e) - size_before <= UPB_JSON_PRINTER_SIZE); + return p; +} + +upb_sink *upb_json_printer_input(upb_json_printer *p) { + return &p->input_; +} + +const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md, + const void *owner) { + return upb_handlers_newfrozen(md, owner, printer_sethandlers, NULL); +} diff --git a/php/ext/google/protobuf/upb.h b/php/ext/google/protobuf/upb.h new file mode 100644 index 00000000..078e2a28 --- /dev/null +++ b/php/ext/google/protobuf/upb.h @@ -0,0 +1,8217 @@ +// Amalgamated source file +/* +** Defs are upb's internal representation of the constructs that can appear +** in a .proto file: +** +** - upb::MessageDef (upb_msgdef): describes a "message" construct. +** - upb::FieldDef (upb_fielddef): describes a message field. +** - upb::EnumDef (upb_enumdef): describes an enum. +** - upb::OneofDef (upb_oneofdef): describes a oneof. +** - upb::Def (upb_def): base class of all the others. +** +** TODO: definitions of services. +** +** Like upb_refcounted objects, defs are mutable only until frozen, and are +** only thread-safe once frozen. +** +** This is a mixed C/C++ interface that offers a full API to both languages. +** See the top-level README for more information. +*/ + +#ifndef UPB_DEF_H_ +#define UPB_DEF_H_ + +/* +** upb::RefCounted (upb_refcounted) +** +** A refcounting scheme that supports circular refs. It accomplishes this by +** partitioning the set of objects into groups such that no cycle spans groups; +** we can then reference-count the group as a whole and ignore refs within the +** group. When objects are mutable, these groups are computed very +** conservatively; we group any objects that have ever had a link between them. +** When objects are frozen, we compute strongly-connected components which +** allows us to be precise and only group objects that are actually cyclic. +** +** This is a mixed C/C++ interface that offers a full API to both languages. +** See the top-level README for more information. +*/ + +#ifndef UPB_REFCOUNTED_H_ +#define UPB_REFCOUNTED_H_ + +/* +** upb_table +** +** This header is INTERNAL-ONLY! Its interfaces are not public or stable! +** This file defines very fast int->upb_value (inttable) and string->upb_value +** (strtable) hash tables. +** +** The table uses chained scatter with Brent's variation (inspired by the Lua +** implementation of hash tables). The hash function for strings is Austin +** Appleby's "MurmurHash." +** +** The inttable uses uintptr_t as its key, which guarantees it can be used to +** store pointers or integers of at least 32 bits (upb isn't really useful on +** systems where sizeof(void*) < 4). +** +** The table must be homogenous (all values of the same type). In debug +** mode, we check this on insert and lookup. +*/ + +#ifndef UPB_TABLE_H_ +#define UPB_TABLE_H_ + +#include +#include +#include +/* +** This file contains shared definitions that are widely used across upb. +** +** This is a mixed C/C++ interface that offers a full API to both languages. +** See the top-level README for more information. +*/ + +#ifndef UPB_H_ +#define UPB_H_ + +#include +#include +#include +#include + +/* UPB_INLINE: inline if possible, emit standalone code if required. */ +#ifdef __cplusplus +#define UPB_INLINE inline +#elif defined (__GNUC__) +#define UPB_INLINE static __inline__ +#else +#define UPB_INLINE static +#endif + +/* Define UPB_BIG_ENDIAN manually if you're on big endian and your compiler + * doesn't provide these preprocessor symbols. */ +#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define UPB_BIG_ENDIAN +#endif + +/* Macros for function attributes on compilers that support them. */ +#ifdef __GNUC__ +#define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) +#define UPB_NOINLINE __attribute__((noinline)) +#define UPB_NORETURN __attribute__((__noreturn__)) +#else /* !defined(__GNUC__) */ +#define UPB_FORCEINLINE +#define UPB_NOINLINE +#define UPB_NORETURN +#endif + +/* A few hacky workarounds for functions not in C89. + * For internal use only! + * TODO(haberman): fix these by including our own implementations, or finding + * another workaround. + */ +#ifdef __GNUC__ +#define _upb_snprintf __builtin_snprintf +#define _upb_vsnprintf __builtin_vsnprintf +#define _upb_va_copy(a, b) __va_copy(a, b) +#elif __STDC_VERSION__ >= 199901L +/* C99 versions. */ +#define _upb_snprintf snprintf +#define _upb_vsnprintf vsnprintf +#define _upb_va_copy(a, b) va_copy(a, b) +#else +#error Need implementations of [v]snprintf and va_copy +#endif + + +#if ((defined(__cplusplus) && __cplusplus >= 201103L) || \ + defined(__GXX_EXPERIMENTAL_CXX0X__)) && !defined(UPB_NO_CXX11) +#define UPB_CXX11 +#endif + +/* UPB_DISALLOW_COPY_AND_ASSIGN() + * UPB_DISALLOW_POD_OPS() + * + * Declare these in the "private" section of a C++ class to forbid copy/assign + * or all POD ops (construct, destruct, copy, assign) on that class. */ +#ifdef UPB_CXX11 +#include +#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \ + class_name(const class_name&) = delete; \ + void operator=(const class_name&) = delete; +#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \ + class_name() = delete; \ + ~class_name() = delete; \ + UPB_DISALLOW_COPY_AND_ASSIGN(class_name) +#define UPB_ASSERT_STDLAYOUT(type) \ + static_assert(std::is_standard_layout::value, \ + #type " must be standard layout"); +#else /* !defined(UPB_CXX11) */ +#define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \ + class_name(const class_name&); \ + void operator=(const class_name&); +#define UPB_DISALLOW_POD_OPS(class_name, full_class_name) \ + class_name(); \ + ~class_name(); \ + UPB_DISALLOW_COPY_AND_ASSIGN(class_name) +#define UPB_ASSERT_STDLAYOUT(type) +#endif + +/* UPB_DECLARE_TYPE() + * UPB_DECLARE_DERIVED_TYPE() + * UPB_DECLARE_DERIVED_TYPE2() + * + * Macros for declaring C and C++ types both, including inheritance. + * The inheritance doesn't use real C++ inheritance, to stay compatible with C. + * + * These macros also provide upcasts: + * - in C: types-specific functions (ie. upb_foo_upcast(foo)) + * - in C++: upb::upcast(foo) along with implicit conversions + * + * Downcasts are not provided, but upb/def.h defines downcasts for upb::Def. */ + +#define UPB_C_UPCASTS(ty, base) \ + UPB_INLINE base *ty ## _upcast_mutable(ty *p) { return (base*)p; } \ + UPB_INLINE const base *ty ## _upcast(const ty *p) { return (const base*)p; } + +#define UPB_C_UPCASTS2(ty, base, base2) \ + UPB_C_UPCASTS(ty, base) \ + UPB_INLINE base2 *ty ## _upcast2_mutable(ty *p) { return (base2*)p; } \ + UPB_INLINE const base2 *ty ## _upcast2(const ty *p) { return (const base2*)p; } + +#ifdef __cplusplus + +#define UPB_BEGIN_EXTERN_C extern "C" { +#define UPB_END_EXTERN_C } +#define UPB_PRIVATE_FOR_CPP private: +#define UPB_DECLARE_TYPE(cppname, cname) typedef cppname cname; + +#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase) \ + UPB_DECLARE_TYPE(cppname, cname) \ + UPB_C_UPCASTS(cname, cbase) \ + namespace upb { \ + template <> \ + class Pointer : public PointerBase { \ + public: \ + explicit Pointer(cppname* ptr) : PointerBase(ptr) {} \ + }; \ + template <> \ + class Pointer \ + : public PointerBase { \ + public: \ + explicit Pointer(const cppname* ptr) : PointerBase(ptr) {} \ + }; \ + } + +#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2, cname, cbase, \ + cbase2) \ + UPB_DECLARE_TYPE(cppname, cname) \ + UPB_C_UPCASTS2(cname, cbase, cbase2) \ + namespace upb { \ + template <> \ + class Pointer : public PointerBase2 { \ + public: \ + explicit Pointer(cppname* ptr) : PointerBase2(ptr) {} \ + }; \ + template <> \ + class Pointer \ + : public PointerBase2 { \ + public: \ + explicit Pointer(const cppname* ptr) : PointerBase2(ptr) {} \ + }; \ + } + +#else /* !defined(__cplusplus) */ + +#define UPB_BEGIN_EXTERN_C +#define UPB_END_EXTERN_C +#define UPB_PRIVATE_FOR_CPP +#define UPB_DECLARE_TYPE(cppname, cname) \ + struct cname; \ + typedef struct cname cname; +#define UPB_DECLARE_DERIVED_TYPE(cppname, cppbase, cname, cbase) \ + UPB_DECLARE_TYPE(cppname, cname) \ + UPB_C_UPCASTS(cname, cbase) +#define UPB_DECLARE_DERIVED_TYPE2(cppname, cppbase, cppbase2, \ + cname, cbase, cbase2) \ + UPB_DECLARE_TYPE(cppname, cname) \ + UPB_C_UPCASTS2(cname, cbase, cbase2) + +#endif /* defined(__cplusplus) */ + +#define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define UPB_UNUSED(var) (void)var + +/* For asserting something about a variable when the variable is not used for + * anything else. This prevents "unused variable" warnings when compiling in + * debug mode. */ +#define UPB_ASSERT_VAR(var, predicate) UPB_UNUSED(var); assert(predicate) + +/* Generic function type. */ +typedef void upb_func(); + +/* C++ Casts ******************************************************************/ + +#ifdef __cplusplus + +namespace upb { + +template class Pointer; + +/* Casts to a subclass. The caller must know that cast is correct; an + * incorrect cast will throw an assertion failure in debug mode. + * + * Example: + * upb::Def* def = GetDef(); + * // Assert-fails if this was not actually a MessageDef. + * upb::MessgeDef* md = upb::down_cast(def); + * + * Note that downcasts are only defined for some types (at the moment you can + * only downcast from a upb::Def to a specific Def type). */ +template To down_cast(From* f); + +/* Casts to a subclass. If the class does not actually match the given To type, + * returns NULL. + * + * Example: + * upb::Def* def = GetDef(); + * // md will be NULL if this was not actually a MessageDef. + * upb::MessgeDef* md = upb::down_cast(def); + * + * Note that dynamic casts are only defined for some types (at the moment you + * can only downcast from a upb::Def to a specific Def type).. */ +template To dyn_cast(From* f); + +/* Casts to any base class, or the type itself (ie. can be a no-op). + * + * Example: + * upb::MessageDef* md = GetDef(); + * // This will fail to compile if this wasn't actually a base class. + * upb::Def* def = upb::upcast(md); + */ +template inline Pointer upcast(T *f) { return Pointer(f); } + +/* Attempt upcast to specific base class. + * + * Example: + * upb::MessageDef* md = GetDef(); + * upb::upcast_to(md)->MethodOnDef(); + */ +template inline T* upcast_to(F *f) { + return static_cast(upcast(f)); +} + +/* PointerBase: implementation detail of upb::upcast(). + * It is implicitly convertable to pointers to the Base class(es). + */ +template +class PointerBase { + public: + explicit PointerBase(T* ptr) : ptr_(ptr) {} + operator T*() { return ptr_; } + operator Base*() { return (Base*)ptr_; } + + private: + T* ptr_; +}; + +template +class PointerBase2 : public PointerBase { + public: + explicit PointerBase2(T* ptr) : PointerBase(ptr) {} + operator Base2*() { return Pointer(*this); } +}; + +} + +#endif + + +/* upb::reffed_ptr ************************************************************/ + +#ifdef __cplusplus + +#include /* For std::swap(). */ + +namespace upb { + +/* Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a + * ref on whatever object it points to (if any). */ +template class reffed_ptr { + public: + reffed_ptr() : ptr_(NULL) {} + + /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ + template + reffed_ptr(U* val, const void* ref_donor = NULL) + : ptr_(upb::upcast(val)) { + if (ref_donor) { + assert(ptr_); + ptr_->DonateRef(ref_donor, this); + } else if (ptr_) { + ptr_->Ref(this); + } + } + + template + reffed_ptr(const reffed_ptr& other) + : ptr_(upb::upcast(other.get())) { + if (ptr_) ptr_->Ref(this); + } + + ~reffed_ptr() { if (ptr_) ptr_->Unref(this); } + + template + reffed_ptr& operator=(const reffed_ptr& other) { + reset(other.get()); + return *this; + } + + reffed_ptr& operator=(const reffed_ptr& other) { + reset(other.get()); + return *this; + } + + /* TODO(haberman): add C++11 move construction/assignment for greater + * efficiency. */ + + void swap(reffed_ptr& other) { + if (ptr_ == other.ptr_) { + return; + } + + if (ptr_) ptr_->DonateRef(this, &other); + if (other.ptr_) other.ptr_->DonateRef(&other, this); + std::swap(ptr_, other.ptr_); + } + + T& operator*() const { + assert(ptr_); + return *ptr_; + } + + T* operator->() const { + assert(ptr_); + return ptr_; + } + + T* get() const { return ptr_; } + + /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ + template + void reset(U* ptr = NULL, const void* ref_donor = NULL) { + reffed_ptr(ptr, ref_donor).swap(*this); + } + + template + reffed_ptr down_cast() { + return reffed_ptr(upb::down_cast(get())); + } + + template + reffed_ptr dyn_cast() { + return reffed_ptr(upb::dyn_cast(get())); + } + + /* Plain release() is unsafe; if we were the only owner, it would leak the + * object. Instead we provide this: */ + T* ReleaseTo(const void* new_owner) { + T* ret = NULL; + ptr_->DonateRef(this, new_owner); + std::swap(ret, ptr_); + return ret; + } + + private: + T* ptr_; +}; + +} /* namespace upb */ + +#endif /* __cplusplus */ + + +/* upb::Status ****************************************************************/ + +#ifdef __cplusplus +namespace upb { +class ErrorSpace; +class Status; +} +#endif + +UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace) +UPB_DECLARE_TYPE(upb::Status, upb_status) + +/* The maximum length of an error message before it will get truncated. */ +#define UPB_STATUS_MAX_MESSAGE 128 + +/* An error callback function is used to report errors from some component. + * The function can return "true" to indicate that the component should try + * to recover and proceed, but this is not always possible. */ +typedef bool upb_errcb_t(void *closure, const upb_status* status); + +#ifdef __cplusplus +class upb::ErrorSpace { +#else +struct upb_errorspace { +#endif + const char *name; + /* Should the error message in the status object according to this code. */ + void (*set_message)(upb_status* status, int code); +}; + +#ifdef __cplusplus + +/* Object representing a success or failure status. + * It owns no resources and allocates no memory, so it should work + * even in OOM situations. */ + +class upb::Status { + public: + Status(); + + /* Returns true if there is no error. */ + bool ok() const; + + /* Optional error space and code, useful if the caller wants to + * programmatically check the specific kind of error. */ + ErrorSpace* error_space(); + int code() const; + + const char *error_message() const; + + /* The error message will be truncated if it is longer than + * UPB_STATUS_MAX_MESSAGE-4. */ + void SetErrorMessage(const char* msg); + void SetFormattedErrorMessage(const char* fmt, ...); + + /* If there is no error message already, this will use the ErrorSpace to + * populate the error message for this code. The caller can still call + * SetErrorMessage() to give a more specific message. */ + void SetErrorCode(ErrorSpace* space, int code); + + /* Resets the status to a successful state with no message. */ + void Clear(); + + void CopyFrom(const Status& other); + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Status) +#else +struct upb_status { +#endif + bool ok_; + + /* Specific status code defined by some error space (optional). */ + int code_; + upb_errorspace *error_space_; + + /* Error message; NULL-terminated. */ + char msg[UPB_STATUS_MAX_MESSAGE]; +}; + +#define UPB_STATUS_INIT {true, 0, NULL, {0}} + +#ifdef __cplusplus +extern "C" { +#endif + +/* The returned string is invalidated by any other call into the status. */ +const char *upb_status_errmsg(const upb_status *status); +bool upb_ok(const upb_status *status); +upb_errorspace *upb_status_errspace(const upb_status *status); +int upb_status_errcode(const upb_status *status); + +/* Any of the functions that write to a status object allow status to be NULL, + * to support use cases where the function's caller does not care about the + * status message. */ +void upb_status_clear(upb_status *status); +void upb_status_seterrmsg(upb_status *status, const char *msg); +void upb_status_seterrf(upb_status *status, const char *fmt, ...); +void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args); +void upb_status_seterrcode(upb_status *status, upb_errorspace *space, int code); +void upb_status_copy(upb_status *to, const upb_status *from); + +#ifdef __cplusplus +} /* extern "C" */ + +namespace upb { + +/* C++ Wrappers */ +inline Status::Status() { Clear(); } +inline bool Status::ok() const { return upb_ok(this); } +inline const char* Status::error_message() const { + return upb_status_errmsg(this); +} +inline void Status::SetErrorMessage(const char* msg) { + upb_status_seterrmsg(this, msg); +} +inline void Status::SetFormattedErrorMessage(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_status_vseterrf(this, fmt, args); + va_end(args); +} +inline void Status::SetErrorCode(ErrorSpace* space, int code) { + upb_status_seterrcode(this, space, code); +} +inline void Status::Clear() { upb_status_clear(this); } +inline void Status::CopyFrom(const Status& other) { + upb_status_copy(this, &other); +} + +} /* namespace upb */ + +#endif + +#endif /* UPB_H_ */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* upb_value ******************************************************************/ + +/* A tagged union (stored untagged inside the table) so that we can check that + * clients calling table accessors are correctly typed without having to have + * an explosion of accessors. */ +typedef enum { + UPB_CTYPE_INT32 = 1, + UPB_CTYPE_INT64 = 2, + UPB_CTYPE_UINT32 = 3, + UPB_CTYPE_UINT64 = 4, + UPB_CTYPE_BOOL = 5, + UPB_CTYPE_CSTR = 6, + UPB_CTYPE_PTR = 7, + UPB_CTYPE_CONSTPTR = 8, + UPB_CTYPE_FPTR = 9 +} upb_ctype_t; + +typedef struct { + uint64_t val; +#ifndef NDEBUG + /* In debug mode we carry the value type around also so we can check accesses + * to be sure the right member is being read. */ + upb_ctype_t ctype; +#endif +} upb_value; + +#ifdef NDEBUG +#define SET_TYPE(dest, val) UPB_UNUSED(val) +#else +#define SET_TYPE(dest, val) dest = val +#endif + +/* Like strdup(), which isn't always available since it's not ANSI C. */ +char *upb_strdup(const char *s); +/* Variant that works with a length-delimited rather than NULL-delimited string, + * as supported by strtable. */ +char *upb_strdup2(const char *s, size_t len); + +UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val, + upb_ctype_t ctype) { + v->val = val; + SET_TYPE(v->ctype, ctype); +} + +UPB_INLINE upb_value _upb_value_val(uint64_t val, upb_ctype_t ctype) { + upb_value ret; + _upb_value_setval(&ret, val, ctype); + return ret; +} + +/* For each value ctype, define the following set of functions: + * + * // Get/set an int32 from a upb_value. + * int32_t upb_value_getint32(upb_value val); + * void upb_value_setint32(upb_value *val, int32_t cval); + * + * // Construct a new upb_value from an int32. + * upb_value upb_value_int32(int32_t val); */ +#define FUNCS(name, membername, type_t, converter, proto_type) \ + UPB_INLINE void upb_value_set ## name(upb_value *val, type_t cval) { \ + val->val = (converter)cval; \ + SET_TYPE(val->ctype, proto_type); \ + } \ + UPB_INLINE upb_value upb_value_ ## name(type_t val) { \ + upb_value ret; \ + upb_value_set ## name(&ret, val); \ + return ret; \ + } \ + UPB_INLINE type_t upb_value_get ## name(upb_value val) { \ + assert(val.ctype == proto_type); \ + return (type_t)(converter)val.val; \ + } + +FUNCS(int32, int32, int32_t, int32_t, UPB_CTYPE_INT32) +FUNCS(int64, int64, int64_t, int64_t, UPB_CTYPE_INT64) +FUNCS(uint32, uint32, uint32_t, uint32_t, UPB_CTYPE_UINT32) +FUNCS(uint64, uint64, uint64_t, uint64_t, UPB_CTYPE_UINT64) +FUNCS(bool, _bool, bool, bool, UPB_CTYPE_BOOL) +FUNCS(cstr, cstr, char*, uintptr_t, UPB_CTYPE_CSTR) +FUNCS(ptr, ptr, void*, uintptr_t, UPB_CTYPE_PTR) +FUNCS(constptr, constptr, const void*, uintptr_t, UPB_CTYPE_CONSTPTR) +FUNCS(fptr, fptr, upb_func*, uintptr_t, UPB_CTYPE_FPTR) + +#undef FUNCS +#undef SET_TYPE + + +/* upb_tabkey *****************************************************************/ + +/* Either: + * 1. an actual integer key, or + * 2. a pointer to a string prefixed by its uint32_t length, owned by us. + * + * ...depending on whether this is a string table or an int table. We would + * make this a union of those two types, but C89 doesn't support statically + * initializing a non-first union member. */ +typedef uintptr_t upb_tabkey; + +#define UPB_TABKEY_NUM(n) n +#define UPB_TABKEY_NONE 0 +/* The preprocessor isn't quite powerful enough to turn the compile-time string + * length into a byte-wise string representation, so code generation needs to + * help it along. + * + * "len1" is the low byte and len4 is the high byte. */ +#ifdef UPB_BIG_ENDIAN +#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \ + (uintptr_t)(len4 len3 len2 len1 strval) +#else +#define UPB_TABKEY_STR(len1, len2, len3, len4, strval) \ + (uintptr_t)(len1 len2 len3 len4 strval) +#endif + +UPB_INLINE char *upb_tabstr(upb_tabkey key, uint32_t *len) { + char* mem = (char*)key; + if (len) memcpy(len, mem, sizeof(*len)); + return mem + sizeof(*len); +} + + +/* upb_tabval *****************************************************************/ + +#ifdef __cplusplus + +/* Status initialization not supported. + * + * This separate definition is necessary because in C++, UINTPTR_MAX isn't + * reliably available. */ +typedef struct { + uint64_t val; +} upb_tabval; + +#else + +/* C -- supports static initialization, but to support static initialization of + * both integers and points for both 32 and 64 bit targets, it takes a little + * bit of doing. */ + +#if UINTPTR_MAX == 0xffffffffffffffffULL +#define UPB_PTR_IS_64BITS +#elif UINTPTR_MAX != 0xffffffff +#error Could not determine how many bits pointers are. +#endif + +typedef union { + /* For static initialization. + * + * Unfortunately this ugliness is necessary -- it is the only way that we can, + * with -std=c89 -pedantic, statically initialize this to either a pointer or + * an integer on 32-bit platforms. */ + struct { +#ifdef UPB_PTR_IS_64BITS + uintptr_t val; +#else + uintptr_t val1; + uintptr_t val2; +#endif + } staticinit; + + /* The normal accessor that we use for everything at runtime. */ + uint64_t val; +} upb_tabval; + +#ifdef UPB_PTR_IS_64BITS +#define UPB_TABVALUE_INT_INIT(v) {{v}} +#define UPB_TABVALUE_EMPTY_INIT {{-1}} +#else + +/* 32-bit pointers */ + +#ifdef UPB_BIG_ENDIAN +#define UPB_TABVALUE_INT_INIT(v) {{0, v}} +#define UPB_TABVALUE_EMPTY_INIT {{-1, -1}} +#else +#define UPB_TABVALUE_INT_INIT(v) {{v, 0}} +#define UPB_TABVALUE_EMPTY_INIT {{-1, -1}} +#endif + +#endif + +#define UPB_TABVALUE_PTR_INIT(v) UPB_TABVALUE_INT_INIT((uintptr_t)v) + +#undef UPB_PTR_IS_64BITS + +#endif /* __cplusplus */ + + +/* upb_table ******************************************************************/ + +typedef struct _upb_tabent { + upb_tabkey key; + upb_tabval val; + + /* Internal chaining. This is const so we can create static initializers for + * tables. We cast away const sometimes, but *only* when the containing + * upb_table is known to be non-const. This requires a bit of care, but + * the subtlety is confined to table.c. */ + const struct _upb_tabent *next; +} upb_tabent; + +typedef struct { + size_t count; /* Number of entries in the hash part. */ + size_t mask; /* Mask to turn hash value -> bucket. */ + upb_ctype_t ctype; /* Type of all values. */ + uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ + + /* Hash table entries. + * Making this const isn't entirely accurate; what we really want is for it to + * have the same const-ness as the table it's inside. But there's no way to + * declare that in C. So we have to make it const so that we can statically + * initialize const hash tables. Then we cast away const when we have to. + */ + const upb_tabent *entries; +} upb_table; + +typedef struct { + upb_table t; +} upb_strtable; + +#define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \ + {{count, mask, ctype, size_lg2, entries}} + +#define UPB_EMPTY_STRTABLE_INIT(ctype) \ + UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL) + +typedef struct { + upb_table t; /* For entries that don't fit in the array part. */ + const upb_tabval *array; /* Array part of the table. See const note above. */ + size_t array_size; /* Array part size. */ + size_t array_count; /* Array part number of elements. */ +} upb_inttable; + +#define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \ + {{count, mask, ctype, size_lg2, ent}, a, asize, acount} + +#define UPB_EMPTY_INTTABLE_INIT(ctype) \ + UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0) + +#define UPB_ARRAY_EMPTYENT -1 + +UPB_INLINE size_t upb_table_size(const upb_table *t) { + if (t->size_lg2 == 0) + return 0; + else + return 1 << t->size_lg2; +} + +/* Internal-only functions, in .h file only out of necessity. */ +UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e) { + return e->key == 0; +} + +/* Used by some of the unit tests for generic hashing functionality. */ +uint32_t MurmurHash2(const void * key, size_t len, uint32_t seed); + +UPB_INLINE uintptr_t upb_intkey(uintptr_t key) { + return key; +} + +UPB_INLINE uint32_t upb_inthash(uintptr_t key) { + return (uint32_t)key; +} + +static const upb_tabent *upb_getentry(const upb_table *t, uint32_t hash) { + return t->entries + (hash & t->mask); +} + +UPB_INLINE bool upb_arrhas(upb_tabval key) { + return key.val != (uint64_t)-1; +} + +/* Initialize and uninitialize a table, respectively. If memory allocation + * failed, false is returned that the table is uninitialized. */ +bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype); +bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype); +void upb_inttable_uninit(upb_inttable *table); +void upb_strtable_uninit(upb_strtable *table); + +/* Returns the number of values in the table. */ +size_t upb_inttable_count(const upb_inttable *t); +UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) { + return t->t.count; +} + +/* Inserts the given key into the hashtable with the given value. The key must + * not already exist in the hash table. For string tables, the key must be + * NULL-terminated, and the table will make an internal copy of the key. + * Inttables must not insert a value of UINTPTR_MAX. + * + * If a table resize was required but memory allocation failed, false is + * returned and the table is unchanged. */ +bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val); +bool upb_strtable_insert2(upb_strtable *t, const char *key, size_t len, + upb_value val); + +/* For NULL-terminated strings. */ +UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key, + upb_value val) { + return upb_strtable_insert2(t, key, strlen(key), val); +} + +/* Looks up key in this table, returning "true" if the key was found. + * If v is non-NULL, copies the value for this key into *v. */ +bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v); +bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, + upb_value *v); + +/* For NULL-terminated strings. */ +UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key, + upb_value *v) { + return upb_strtable_lookup2(t, key, strlen(key), v); +} + +/* Removes an item from the table. Returns true if the remove was successful, + * and stores the removed item in *val if non-NULL. */ +bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val); +bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len, + upb_value *val); + +/* For NULL-terminated strings. */ +UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key, + upb_value *v) { + return upb_strtable_remove2(t, key, strlen(key), v); +} + +/* Updates an existing entry in an inttable. If the entry does not exist, + * returns false and does nothing. Unlike insert/remove, this does not + * invalidate iterators. */ +bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); + +/* Handy routines for treating an inttable like a stack. May not be mixed with + * other insert/remove calls. */ +bool upb_inttable_push(upb_inttable *t, upb_value val); +upb_value upb_inttable_pop(upb_inttable *t); + +/* Convenience routines for inttables with pointer keys. */ +bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val); +bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val); +bool upb_inttable_lookupptr( + const upb_inttable *t, const void *key, upb_value *val); + +/* Optimizes the table for the current set of entries, for both memory use and + * lookup time. Client should call this after all entries have been inserted; + * inserting more entries is legal, but will likely require a table resize. */ +void upb_inttable_compact(upb_inttable *t); + +/* A special-case inlinable version of the lookup routine for 32-bit + * integers. */ +UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, + upb_value *v) { + *v = upb_value_int32(0); /* Silence compiler warnings. */ + if (key < t->array_size) { + upb_tabval arrval = t->array[key]; + if (upb_arrhas(arrval)) { + _upb_value_setval(v, arrval.val, t->t.ctype); + return true; + } else { + return false; + } + } else { + const upb_tabent *e; + if (t->t.entries == NULL) return false; + for (e = upb_getentry(&t->t, upb_inthash(key)); true; e = e->next) { + if ((uint32_t)e->key == key) { + _upb_value_setval(v, e->val.val, t->t.ctype); + return true; + } + if (e->next == NULL) return false; + } + } +} + +/* Exposed for testing only. */ +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2); + +/* Iterators ******************************************************************/ + +/* Iterators for int and string tables. We are subject to some kind of unusual + * design constraints: + * + * For high-level languages: + * - we must be able to guarantee that we don't crash or corrupt memory even if + * the program accesses an invalidated iterator. + * + * For C++11 range-based for: + * - iterators must be copyable + * - iterators must be comparable + * - it must be possible to construct an "end" value. + * + * Iteration order is undefined. + * + * Modifying the table invalidates iterators. upb_{str,int}table_done() is + * guaranteed to work even on an invalidated iterator, as long as the table it + * is iterating over has not been freed. Calling next() or accessing data from + * an invalidated iterator yields unspecified elements from the table, but it is + * guaranteed not to crash and to return real table elements (except when done() + * is true). */ + + +/* upb_strtable_iter **********************************************************/ + +/* upb_strtable_iter i; + * upb_strtable_begin(&i, t); + * for(; !upb_strtable_done(&i); upb_strtable_next(&i)) { + * const char *key = upb_strtable_iter_key(&i); + * const upb_value val = upb_strtable_iter_value(&i); + * // ... + * } + */ + +typedef struct { + const upb_strtable *t; + size_t index; +} upb_strtable_iter; + +void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t); +void upb_strtable_next(upb_strtable_iter *i); +bool upb_strtable_done(const upb_strtable_iter *i); +const char *upb_strtable_iter_key(upb_strtable_iter *i); +size_t upb_strtable_iter_keylength(upb_strtable_iter *i); +upb_value upb_strtable_iter_value(const upb_strtable_iter *i); +void upb_strtable_iter_setdone(upb_strtable_iter *i); +bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, + const upb_strtable_iter *i2); + + +/* upb_inttable_iter **********************************************************/ + +/* upb_inttable_iter i; + * upb_inttable_begin(&i, t); + * for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { + * uintptr_t key = upb_inttable_iter_key(&i); + * upb_value val = upb_inttable_iter_value(&i); + * // ... + * } + */ + +typedef struct { + const upb_inttable *t; + size_t index; + bool array_part; +} upb_inttable_iter; + +void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t); +void upb_inttable_next(upb_inttable_iter *i); +bool upb_inttable_done(const upb_inttable_iter *i); +uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i); +upb_value upb_inttable_iter_value(const upb_inttable_iter *i); +void upb_inttable_iter_setdone(upb_inttable_iter *i); +bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, + const upb_inttable_iter *i2); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_TABLE_H_ */ + +/* Reference tracking will check ref()/unref() operations to make sure the + * ref ownership is correct. Where possible it will also make tools like + * Valgrind attribute ref leaks to the code that took the leaked ref, not + * the code that originally created the object. + * + * Enabling this requires the application to define upb_lock()/upb_unlock() + * functions that acquire/release a global mutex (or #define UPB_THREAD_UNSAFE). + * For this reason we don't enable it by default, even in debug builds. + */ + +/* #define UPB_DEBUG_REFS */ + +#ifdef __cplusplus +namespace upb { class RefCounted; } +#endif + +UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted) + +struct upb_refcounted_vtbl; + +#ifdef __cplusplus + +class upb::RefCounted { + public: + /* Returns true if the given object is frozen. */ + bool IsFrozen() const; + + /* Increases the ref count, the new ref is owned by "owner" which must not + * already own a ref (and should not itself be a refcounted object if the ref + * could possibly be circular; see below). + * Thread-safe iff "this" is frozen. */ + void Ref(const void *owner) const; + + /* Release a ref that was acquired from upb_refcounted_ref() and collects any + * objects it can. */ + void Unref(const void *owner) const; + + /* Moves an existing ref from "from" to "to", without changing the overall + * ref count. DonateRef(foo, NULL, owner) is the same as Ref(foo, owner), + * but "to" may not be NULL. */ + void DonateRef(const void *from, const void *to) const; + + /* Verifies that a ref to the given object is currently held by the given + * owner. Only effective in UPB_DEBUG_REFS builds. */ + void CheckRef(const void *owner) const; + + private: + UPB_DISALLOW_POD_OPS(RefCounted, upb::RefCounted) +#else +struct upb_refcounted { +#endif + /* TODO(haberman): move the actual structure definition to structdefs.int.h. + * The only reason they are here is because inline functions need to see the + * definition of upb_handlers, which needs to see this definition. But we + * can change the upb_handlers inline functions to deal in raw offsets + * instead. + */ + + /* A single reference count shared by all objects in the group. */ + uint32_t *group; + + /* A singly-linked list of all objects in the group. */ + upb_refcounted *next; + + /* Table of function pointers for this type. */ + const struct upb_refcounted_vtbl *vtbl; + + /* Maintained only when mutable, this tracks the number of refs (but not + * ref2's) to this object. *group should be the sum of all individual_count + * in the group. */ + uint32_t individual_count; + + bool is_frozen; + +#ifdef UPB_DEBUG_REFS + upb_inttable *refs; /* Maps owner -> trackedref for incoming refs. */ + upb_inttable *ref2s; /* Set of targets for outgoing ref2s. */ +#endif +}; + +#ifdef UPB_DEBUG_REFS +#define UPB_REFCOUNT_INIT(refs, ref2s) \ + {&static_refcount, NULL, NULL, 0, true, refs, ref2s} +#else +#define UPB_REFCOUNT_INIT(refs, ref2s) {&static_refcount, NULL, NULL, 0, true} +#endif + +UPB_BEGIN_EXTERN_C + +/* It is better to use tracked refs when possible, for the extra debugging + * capability. But if this is not possible (because you don't have easy access + * to a stable pointer value that is associated with the ref), you can pass + * UPB_UNTRACKED_REF instead. */ +extern const void *UPB_UNTRACKED_REF; + +/* Native C API. */ +bool upb_refcounted_isfrozen(const upb_refcounted *r); +void upb_refcounted_ref(const upb_refcounted *r, const void *owner); +void upb_refcounted_unref(const upb_refcounted *r, const void *owner); +void upb_refcounted_donateref( + const upb_refcounted *r, const void *from, const void *to); +void upb_refcounted_checkref(const upb_refcounted *r, const void *owner); + +#define UPB_REFCOUNTED_CMETHODS(type, upcastfunc) \ + UPB_INLINE bool type ## _isfrozen(const type *v) { \ + return upb_refcounted_isfrozen(upcastfunc(v)); \ + } \ + UPB_INLINE void type ## _ref(const type *v, const void *owner) { \ + upb_refcounted_ref(upcastfunc(v), owner); \ + } \ + UPB_INLINE void type ## _unref(const type *v, const void *owner) { \ + upb_refcounted_unref(upcastfunc(v), owner); \ + } \ + UPB_INLINE void type ## _donateref(const type *v, const void *from, const void *to) { \ + upb_refcounted_donateref(upcastfunc(v), from, to); \ + } \ + UPB_INLINE void type ## _checkref(const type *v, const void *owner) { \ + upb_refcounted_checkref(upcastfunc(v), owner); \ + } + +#define UPB_REFCOUNTED_CPPMETHODS \ + bool IsFrozen() const { \ + return upb::upcast_to(this)->IsFrozen(); \ + } \ + void Ref(const void *owner) const { \ + return upb::upcast_to(this)->Ref(owner); \ + } \ + void Unref(const void *owner) const { \ + return upb::upcast_to(this)->Unref(owner); \ + } \ + void DonateRef(const void *from, const void *to) const { \ + return upb::upcast_to(this)->DonateRef(from, to); \ + } \ + void CheckRef(const void *owner) const { \ + return upb::upcast_to(this)->CheckRef(owner); \ + } + +/* Internal-to-upb Interface **************************************************/ + +typedef void upb_refcounted_visit(const upb_refcounted *r, + const upb_refcounted *subobj, + void *closure); + +struct upb_refcounted_vtbl { + /* Must visit all subobjects that are currently ref'd via upb_refcounted_ref2. + * Must be longjmp()-safe. */ + void (*visit)(const upb_refcounted *r, upb_refcounted_visit *visit, void *c); + + /* Must free the object and release all references to other objects. */ + void (*free)(upb_refcounted *r); +}; + +/* Initializes the refcounted with a single ref for the given owner. Returns + * false if memory could not be allocated. */ +bool upb_refcounted_init(upb_refcounted *r, + const struct upb_refcounted_vtbl *vtbl, + const void *owner); + +/* Adds a ref from one refcounted object to another ("from" must not already + * own a ref). These refs may be circular; cycles will be collected correctly + * (if conservatively). These refs do not need to be freed in from's free() + * function. */ +void upb_refcounted_ref2(const upb_refcounted *r, upb_refcounted *from); + +/* Removes a ref that was acquired from upb_refcounted_ref2(), and collects any + * object it can. This is only necessary when "from" no longer points to "r", + * and not from from's "free" function. */ +void upb_refcounted_unref2(const upb_refcounted *r, upb_refcounted *from); + +#define upb_ref2(r, from) \ + upb_refcounted_ref2((const upb_refcounted*)r, (upb_refcounted*)from) +#define upb_unref2(r, from) \ + upb_refcounted_unref2((const upb_refcounted*)r, (upb_refcounted*)from) + +/* Freezes all mutable object reachable by ref2() refs from the given roots. + * This will split refcounting groups into precise SCC groups, so that + * refcounting of frozen objects can be more aggressive. If memory allocation + * fails, or if more than 2**31 mutable objects are reachable from "roots", or + * if the maximum depth of the graph exceeds "maxdepth", false is returned and + * the objects are unchanged. + * + * After this operation succeeds, the objects are frozen/const, and may not be + * used through non-const pointers. In particular, they may not be passed as + * the second parameter of upb_refcounted_{ref,unref}2(). On the upside, all + * operations on frozen refcounteds are threadsafe, and objects will be freed + * at the precise moment that they become unreachable. + * + * Caller must own refs on each object in the "roots" list. */ +bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, + int maxdepth); + +/* Shared by all compiled-in refcounted objects. */ +extern uint32_t static_refcount; + +UPB_END_EXTERN_C + +#ifdef __cplusplus +/* C++ Wrappers. */ +namespace upb { +inline bool RefCounted::IsFrozen() const { + return upb_refcounted_isfrozen(this); +} +inline void RefCounted::Ref(const void *owner) const { + upb_refcounted_ref(this, owner); +} +inline void RefCounted::Unref(const void *owner) const { + upb_refcounted_unref(this, owner); +} +inline void RefCounted::DonateRef(const void *from, const void *to) const { + upb_refcounted_donateref(this, from, to); +} +inline void RefCounted::CheckRef(const void *owner) const { + upb_refcounted_checkref(this, owner); +} +} /* namespace upb */ +#endif + +#endif /* UPB_REFCOUNT_H_ */ + +#ifdef __cplusplus +#include +#include +#include + +namespace upb { +class Def; +class EnumDef; +class FieldDef; +class MessageDef; +class OneofDef; +} +#endif + +UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted) + +/* The maximum message depth that the type graph can have. This is a resource + * limit for the C stack since we sometimes need to recursively traverse the + * graph. Cycles are ok; the traversal will stop when it detects a cycle, but + * we must hit the cycle before the maximum depth is reached. + * + * If having a single static limit is too inflexible, we can add another variant + * of Def::Freeze that allows specifying this as a parameter. */ +#define UPB_MAX_MESSAGE_DEPTH 64 + + +/* upb::Def: base class for defs *********************************************/ + +/* All the different kind of defs we support. These correspond 1:1 with + * declarations in a .proto file. */ +typedef enum { + UPB_DEF_MSG, + UPB_DEF_FIELD, + UPB_DEF_ENUM, + UPB_DEF_ONEOF, + UPB_DEF_SERVICE, /* Not yet implemented. */ + UPB_DEF_ANY = -1 /* Wildcard for upb_symtab_get*() */ +} upb_deftype_t; + +#ifdef __cplusplus + +/* The base class of all defs. Its base is upb::RefCounted (use upb::upcast() + * to convert). */ +class upb::Def { + public: + typedef upb_deftype_t Type; + + Def* Dup(const void *owner) const; + + /* upb::RefCounted methods like Ref()/Unref(). */ + UPB_REFCOUNTED_CPPMETHODS + + Type def_type() const; + + /* "fullname" is the def's fully-qualified name (eg. foo.bar.Message). */ + const char *full_name() const; + + /* The def must be mutable. Caller retains ownership of fullname. Defs are + * not required to have a name; if a def has no name when it is frozen, it + * will remain an anonymous def. On failure, returns false and details in "s" + * if non-NULL. */ + bool set_full_name(const char* fullname, upb::Status* s); + bool set_full_name(const std::string &fullname, upb::Status* s); + + /* Freezes the given defs; this validates all constraints and marks the defs + * as frozen (read-only). "defs" may not contain any fielddefs, but fields + * of any msgdefs will be frozen. + * + * Symbolic references to sub-types and enum defaults must have already been + * resolved. Any mutable defs reachable from any of "defs" must also be in + * the list; more formally, "defs" must be a transitive closure of mutable + * defs. + * + * After this operation succeeds, the finalized defs must only be accessed + * through a const pointer! */ + static bool Freeze(Def* const* defs, int n, Status* status); + static bool Freeze(const std::vector& defs, Status* status); + + private: + UPB_DISALLOW_POD_OPS(Def, upb::Def) +}; + +#endif /* __cplusplus */ + +UPB_BEGIN_EXTERN_C + +/* Native C API. */ +upb_def *upb_def_dup(const upb_def *def, const void *owner); + +/* Include upb_refcounted methods like upb_def_ref()/upb_def_unref(). */ +UPB_REFCOUNTED_CMETHODS(upb_def, upb_def_upcast) + +upb_deftype_t upb_def_type(const upb_def *d); +const char *upb_def_fullname(const upb_def *d); +bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s); +bool upb_def_freeze(upb_def *const *defs, int n, upb_status *s); + +UPB_END_EXTERN_C + + +/* upb::Def casts *************************************************************/ + +#ifdef __cplusplus +#define UPB_CPP_CASTS(cname, cpptype) \ + namespace upb { \ + template <> \ + inline cpptype *down_cast(Def * def) { \ + return upb_downcast_##cname##_mutable(def); \ + } \ + template <> \ + inline cpptype *dyn_cast(Def * def) { \ + return upb_dyncast_##cname##_mutable(def); \ + } \ + template <> \ + inline const cpptype *down_cast( \ + const Def *def) { \ + return upb_downcast_##cname(def); \ + } \ + template <> \ + inline const cpptype *dyn_cast(const Def *def) { \ + return upb_dyncast_##cname(def); \ + } \ + template <> \ + inline const cpptype *down_cast(Def * def) { \ + return upb_downcast_##cname(def); \ + } \ + template <> \ + inline const cpptype *dyn_cast(Def * def) { \ + return upb_dyncast_##cname(def); \ + } \ + } /* namespace upb */ +#else +#define UPB_CPP_CASTS(cname, cpptype) +#endif /* __cplusplus */ + +/* Dynamic casts, for determining if a def is of a particular type at runtime. + * Downcasts, for when some wants to assert that a def is of a particular type. + * These are only checked if we are building debug. */ +#define UPB_DEF_CASTS(lower, upper, cpptype) \ + UPB_INLINE const upb_##lower *upb_dyncast_##lower(const upb_def *def) { \ + if (upb_def_type(def) != UPB_DEF_##upper) return NULL; \ + return (upb_##lower *)def; \ + } \ + UPB_INLINE const upb_##lower *upb_downcast_##lower(const upb_def *def) { \ + assert(upb_def_type(def) == UPB_DEF_##upper); \ + return (const upb_##lower *)def; \ + } \ + UPB_INLINE upb_##lower *upb_dyncast_##lower##_mutable(upb_def *def) { \ + return (upb_##lower *)upb_dyncast_##lower(def); \ + } \ + UPB_INLINE upb_##lower *upb_downcast_##lower##_mutable(upb_def *def) { \ + return (upb_##lower *)upb_downcast_##lower(def); \ + } \ + UPB_CPP_CASTS(lower, cpptype) + +#define UPB_DEFINE_DEF(cppname, lower, upper, cppmethods, members) \ + UPB_DEFINE_CLASS2(cppname, upb::Def, upb::RefCounted, cppmethods, \ + members) \ + UPB_DEF_CASTS(lower, upper, cppname) + +#define UPB_DECLARE_DEF_TYPE(cppname, lower, upper) \ + UPB_DECLARE_DERIVED_TYPE2(cppname, upb::Def, upb::RefCounted, \ + upb_ ## lower, upb_def, upb_refcounted) \ + UPB_DEF_CASTS(lower, upper, cppname) + +UPB_DECLARE_DEF_TYPE(upb::FieldDef, fielddef, FIELD) +UPB_DECLARE_DEF_TYPE(upb::MessageDef, msgdef, MSG) +UPB_DECLARE_DEF_TYPE(upb::EnumDef, enumdef, ENUM) +UPB_DECLARE_DEF_TYPE(upb::OneofDef, oneofdef, ONEOF) + +#undef UPB_DECLARE_DEF_TYPE +#undef UPB_DEF_CASTS +#undef UPB_CPP_CASTS + + +/* upb::FieldDef **************************************************************/ + +/* The types a field can have. Note that this list is not identical to the + * types defined in descriptor.proto, which gives INT32 and SINT32 separate + * types (we distinguish the two with the "integer encoding" enum below). */ +typedef enum { + UPB_TYPE_FLOAT = 1, + UPB_TYPE_DOUBLE = 2, + UPB_TYPE_BOOL = 3, + UPB_TYPE_STRING = 4, + UPB_TYPE_BYTES = 5, + UPB_TYPE_MESSAGE = 6, + UPB_TYPE_ENUM = 7, /* Enum values are int32. */ + UPB_TYPE_INT32 = 8, + UPB_TYPE_UINT32 = 9, + UPB_TYPE_INT64 = 10, + UPB_TYPE_UINT64 = 11 +} upb_fieldtype_t; + +/* The repeated-ness of each field; this matches descriptor.proto. */ +typedef enum { + UPB_LABEL_OPTIONAL = 1, + UPB_LABEL_REQUIRED = 2, + UPB_LABEL_REPEATED = 3 +} upb_label_t; + +/* How integers should be encoded in serializations that offer multiple + * integer encoding methods. */ +typedef enum { + UPB_INTFMT_VARIABLE = 1, + UPB_INTFMT_FIXED = 2, + UPB_INTFMT_ZIGZAG = 3 /* Only for signed types (INT32/INT64). */ +} upb_intfmt_t; + +/* Descriptor types, as defined in descriptor.proto. */ +typedef enum { + UPB_DESCRIPTOR_TYPE_DOUBLE = 1, + UPB_DESCRIPTOR_TYPE_FLOAT = 2, + UPB_DESCRIPTOR_TYPE_INT64 = 3, + UPB_DESCRIPTOR_TYPE_UINT64 = 4, + UPB_DESCRIPTOR_TYPE_INT32 = 5, + UPB_DESCRIPTOR_TYPE_FIXED64 = 6, + UPB_DESCRIPTOR_TYPE_FIXED32 = 7, + UPB_DESCRIPTOR_TYPE_BOOL = 8, + UPB_DESCRIPTOR_TYPE_STRING = 9, + UPB_DESCRIPTOR_TYPE_GROUP = 10, + UPB_DESCRIPTOR_TYPE_MESSAGE = 11, + UPB_DESCRIPTOR_TYPE_BYTES = 12, + UPB_DESCRIPTOR_TYPE_UINT32 = 13, + UPB_DESCRIPTOR_TYPE_ENUM = 14, + UPB_DESCRIPTOR_TYPE_SFIXED32 = 15, + UPB_DESCRIPTOR_TYPE_SFIXED64 = 16, + UPB_DESCRIPTOR_TYPE_SINT32 = 17, + UPB_DESCRIPTOR_TYPE_SINT64 = 18 +} upb_descriptortype_t; + +/* Maximum field number allowed for FieldDefs. This is an inherent limit of the + * protobuf wire format. */ +#define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) + +#ifdef __cplusplus + +/* A upb_fielddef describes a single field in a message. It is most often + * found as a part of a upb_msgdef, but can also stand alone to represent + * an extension. + * + * Its base class is upb::Def (use upb::upcast() to convert). */ +class upb::FieldDef { + public: + typedef upb_fieldtype_t Type; + typedef upb_label_t Label; + typedef upb_intfmt_t IntegerFormat; + typedef upb_descriptortype_t DescriptorType; + + /* These return true if the given value is a valid member of the enumeration. */ + static bool CheckType(int32_t val); + static bool CheckLabel(int32_t val); + static bool CheckDescriptorType(int32_t val); + static bool CheckIntegerFormat(int32_t val); + + /* These convert to the given enumeration; they require that the value is + * valid. */ + static Type ConvertType(int32_t val); + static Label ConvertLabel(int32_t val); + static DescriptorType ConvertDescriptorType(int32_t val); + static IntegerFormat ConvertIntegerFormat(int32_t val); + + /* Returns NULL if memory allocation failed. */ + static reffed_ptr New(); + + /* Duplicates the given field, returning NULL if memory allocation failed. + * When a fielddef is duplicated, the subdef (if any) is made symbolic if it + * wasn't already. If the subdef is set but has no name (which is possible + * since msgdefs are not required to have a name) the new fielddef's subdef + * will be unset. */ + FieldDef* Dup(const void* owner) const; + + /* upb::RefCounted methods like Ref()/Unref(). */ + UPB_REFCOUNTED_CPPMETHODS + + /* Functionality from upb::Def. */ + const char* full_name() const; + + bool type_is_set() const; /* set_[descriptor_]type() has been called? */ + Type type() const; /* Requires that type_is_set() == true. */ + Label label() const; /* Defaults to UPB_LABEL_OPTIONAL. */ + const char* name() const; /* NULL if uninitialized. */ + uint32_t number() const; /* Returns 0 if uninitialized. */ + bool is_extension() const; + + /* For UPB_TYPE_MESSAGE fields only where is_tag_delimited() == false, + * indicates whether this field should have lazy parsing handlers that yield + * the unparsed string for the submessage. + * + * TODO(haberman): I think we want to move this into a FieldOptions container + * when we add support for custom options (the FieldOptions struct will + * contain both regular FieldOptions like "lazy" *and* custom options). */ + bool lazy() const; + + /* For non-string, non-submessage fields, this indicates whether binary + * protobufs are encoded in packed or non-packed format. + * + * TODO(haberman): see note above about putting options like this into a + * FieldOptions container. */ + bool packed() const; + + /* An integer that can be used as an index into an array of fields for + * whatever message this field belongs to. Guaranteed to be less than + * f->containing_type()->field_count(). May only be accessed once the def has + * been finalized. */ + int index() const; + + /* The MessageDef to which this field belongs. + * + * If this field has been added to a MessageDef, that message can be retrieved + * directly (this is always the case for frozen FieldDefs). + * + * If the field has not yet been added to a MessageDef, you can set the name + * of the containing type symbolically instead. This is mostly useful for + * extensions, where the extension is declared separately from the message. */ + const MessageDef* containing_type() const; + const char* containing_type_name(); + + /* The OneofDef to which this field belongs, or NULL if this field is not part + * of a oneof. */ + const OneofDef* containing_oneof() const; + + /* The field's type according to the enum in descriptor.proto. This is not + * the same as UPB_TYPE_*, because it distinguishes between (for example) + * INT32 and SINT32, whereas our "type" enum does not. This return of + * descriptor_type() is a function of type(), integer_format(), and + * is_tag_delimited(). Likewise set_descriptor_type() sets all three + * appropriately. */ + DescriptorType descriptor_type() const; + + /* Convenient field type tests. */ + bool IsSubMessage() const; + bool IsString() const; + bool IsSequence() const; + bool IsPrimitive() const; + bool IsMap() const; + + /* How integers are encoded. Only meaningful for integer types. + * Defaults to UPB_INTFMT_VARIABLE, and is reset when "type" changes. */ + IntegerFormat integer_format() const; + + /* Whether a submessage field is tag-delimited or not (if false, then + * length-delimited). May only be set when type() == UPB_TYPE_MESSAGE. */ + bool is_tag_delimited() const; + + /* Returns the non-string default value for this fielddef, which may either + * be something the client set explicitly or the "default default" (0 for + * numbers, empty for strings). The field's type indicates the type of the + * returned value, except for enum fields that are still mutable. + * + * Requires that the given function matches the field's current type. */ + int64_t default_int64() const; + int32_t default_int32() const; + uint64_t default_uint64() const; + uint32_t default_uint32() const; + bool default_bool() const; + float default_float() const; + double default_double() const; + + /* The resulting string is always NULL-terminated. If non-NULL, the length + * will be stored in *len. */ + const char *default_string(size_t* len) const; + + /* For frozen UPB_TYPE_ENUM fields, enum defaults can always be read as either + * string or int32, and both of these methods will always return true. + * + * For mutable UPB_TYPE_ENUM fields, the story is a bit more complicated. + * Enum defaults are unusual. They can be specified either as string or int32, + * but to be valid the enum must have that value as a member. And if no + * default is specified, the "default default" comes from the EnumDef. + * + * We allow reading the default as either an int32 or a string, but only if + * we have a meaningful value to report. We have a meaningful value if it was + * set explicitly, or if we could get the "default default" from the EnumDef. + * Also if you explicitly set the name and we find the number in the EnumDef */ + bool EnumHasStringDefault() const; + bool EnumHasInt32Default() const; + + /* Submessage and enum fields must reference a "subdef", which is the + * upb::MessageDef or upb::EnumDef that defines their type. Note that when + * the FieldDef is mutable it may not have a subdef *yet*, but this function + * still returns true to indicate that the field's type requires a subdef. */ + bool HasSubDef() const; + + /* Returns the enum or submessage def for this field, if any. The field's + * type must match (ie. you may only call enum_subdef() for fields where + * type() == UPB_TYPE_ENUM). Returns NULL if the subdef has not been set or + * is currently set symbolically. */ + const EnumDef* enum_subdef() const; + const MessageDef* message_subdef() const; + + /* Returns the generic subdef for this field. Requires that HasSubDef() (ie. + * only works for UPB_TYPE_ENUM and UPB_TYPE_MESSAGE fields). */ + const Def* subdef() const; + + /* Returns the symbolic name of the subdef. If the subdef is currently set + * unresolved (ie. set symbolically) returns the symbolic name. If it has + * been resolved to a specific subdef, returns the name from that subdef. */ + const char* subdef_name() const; + + /* Setters (non-const methods), only valid for mutable FieldDefs! ***********/ + + bool set_full_name(const char* fullname, upb::Status* s); + bool set_full_name(const std::string& fullname, upb::Status* s); + + /* This may only be called if containing_type() == NULL (ie. the field has not + * been added to a message yet). */ + bool set_containing_type_name(const char *name, Status* status); + bool set_containing_type_name(const std::string& name, Status* status); + + /* Defaults to false. When we freeze, we ensure that this can only be true + * for length-delimited message fields. Prior to freezing this can be true or + * false with no restrictions. */ + void set_lazy(bool lazy); + + /* Defaults to true. Sets whether this field is encoded in packed format. */ + void set_packed(bool packed); + + /* "type" or "descriptor_type" MUST be set explicitly before the fielddef is + * finalized. These setters require that the enum value is valid; if the + * value did not come directly from an enum constant, the caller should + * validate it first with the functions above (CheckFieldType(), etc). */ + void set_type(Type type); + void set_label(Label label); + void set_descriptor_type(DescriptorType type); + void set_is_extension(bool is_extension); + + /* "number" and "name" must be set before the FieldDef is added to a + * MessageDef, and may not be set after that. + * + * "name" is the same as full_name()/set_full_name(), but since fielddefs + * most often use simple, non-qualified names, we provide this accessor + * also. Generally only extensions will want to think of this name as + * fully-qualified. */ + bool set_number(uint32_t number, upb::Status* s); + bool set_name(const char* name, upb::Status* s); + bool set_name(const std::string& name, upb::Status* s); + + void set_integer_format(IntegerFormat format); + bool set_tag_delimited(bool tag_delimited, upb::Status* s); + + /* Sets default value for the field. The call must exactly match the type + * of the field. Enum fields may use either setint32 or setstring to set + * the default numerically or symbolically, respectively, but symbolic + * defaults must be resolved before finalizing (see ResolveEnumDefault()). + * + * Changing the type of a field will reset its default. */ + void set_default_int64(int64_t val); + void set_default_int32(int32_t val); + void set_default_uint64(uint64_t val); + void set_default_uint32(uint32_t val); + void set_default_bool(bool val); + void set_default_float(float val); + void set_default_double(double val); + bool set_default_string(const void *str, size_t len, Status *s); + bool set_default_string(const std::string &str, Status *s); + void set_default_cstr(const char *str, Status *s); + + /* Before a fielddef is frozen, its subdef may be set either directly (with a + * upb::Def*) or symbolically. Symbolic refs must be resolved before the + * containing msgdef can be frozen (see upb_resolve() above). upb always + * guarantees that any def reachable from a live def will also be kept alive. + * + * Both methods require that upb_hassubdef(f) (so the type must be set prior + * to calling these methods). Returns false if this is not the case, or if + * the given subdef is not of the correct type. The subdef is reset if the + * field's type is changed. The subdef can be set to NULL to clear it. */ + bool set_subdef(const Def* subdef, Status* s); + bool set_enum_subdef(const EnumDef* subdef, Status* s); + bool set_message_subdef(const MessageDef* subdef, Status* s); + bool set_subdef_name(const char* name, Status* s); + bool set_subdef_name(const std::string &name, Status* s); + + private: + UPB_DISALLOW_POD_OPS(FieldDef, upb::FieldDef) +}; + +# endif /* defined(__cplusplus) */ + +UPB_BEGIN_EXTERN_C + +/* Native C API. */ +upb_fielddef *upb_fielddef_new(const void *owner); +upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner); + +/* Include upb_refcounted methods like upb_fielddef_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_fielddef, upb_fielddef_upcast2) + +/* Methods from upb_def. */ +const char *upb_fielddef_fullname(const upb_fielddef *f); +bool upb_fielddef_setfullname(upb_fielddef *f, const char *fullname, + upb_status *s); + +bool upb_fielddef_typeisset(const upb_fielddef *f); +upb_fieldtype_t upb_fielddef_type(const upb_fielddef *f); +upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f); +upb_label_t upb_fielddef_label(const upb_fielddef *f); +uint32_t upb_fielddef_number(const upb_fielddef *f); +const char *upb_fielddef_name(const upb_fielddef *f); +bool upb_fielddef_isextension(const upb_fielddef *f); +bool upb_fielddef_lazy(const upb_fielddef *f); +bool upb_fielddef_packed(const upb_fielddef *f); +const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); +const upb_oneofdef *upb_fielddef_containingoneof(const upb_fielddef *f); +upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f); +const char *upb_fielddef_containingtypename(upb_fielddef *f); +upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f); +uint32_t upb_fielddef_index(const upb_fielddef *f); +bool upb_fielddef_istagdelim(const upb_fielddef *f); +bool upb_fielddef_issubmsg(const upb_fielddef *f); +bool upb_fielddef_isstring(const upb_fielddef *f); +bool upb_fielddef_isseq(const upb_fielddef *f); +bool upb_fielddef_isprimitive(const upb_fielddef *f); +bool upb_fielddef_ismap(const upb_fielddef *f); +int64_t upb_fielddef_defaultint64(const upb_fielddef *f); +int32_t upb_fielddef_defaultint32(const upb_fielddef *f); +uint64_t upb_fielddef_defaultuint64(const upb_fielddef *f); +uint32_t upb_fielddef_defaultuint32(const upb_fielddef *f); +bool upb_fielddef_defaultbool(const upb_fielddef *f); +float upb_fielddef_defaultfloat(const upb_fielddef *f); +double upb_fielddef_defaultdouble(const upb_fielddef *f); +const char *upb_fielddef_defaultstr(const upb_fielddef *f, size_t *len); +bool upb_fielddef_enumhasdefaultint32(const upb_fielddef *f); +bool upb_fielddef_enumhasdefaultstr(const upb_fielddef *f); +bool upb_fielddef_hassubdef(const upb_fielddef *f); +const upb_def *upb_fielddef_subdef(const upb_fielddef *f); +const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f); +const upb_enumdef *upb_fielddef_enumsubdef(const upb_fielddef *f); +const char *upb_fielddef_subdefname(const upb_fielddef *f); + +void upb_fielddef_settype(upb_fielddef *f, upb_fieldtype_t type); +void upb_fielddef_setdescriptortype(upb_fielddef *f, int type); +void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label); +bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s); +bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s); +bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, + upb_status *s); +void upb_fielddef_setisextension(upb_fielddef *f, bool is_extension); +void upb_fielddef_setlazy(upb_fielddef *f, bool lazy); +void upb_fielddef_setpacked(upb_fielddef *f, bool packed); +void upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt); +void upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim); +void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val); +void upb_fielddef_setdefaultint32(upb_fielddef *f, int32_t val); +void upb_fielddef_setdefaultuint64(upb_fielddef *f, uint64_t val); +void upb_fielddef_setdefaultuint32(upb_fielddef *f, uint32_t val); +void upb_fielddef_setdefaultbool(upb_fielddef *f, bool val); +void upb_fielddef_setdefaultfloat(upb_fielddef *f, float val); +void upb_fielddef_setdefaultdouble(upb_fielddef *f, double val); +bool upb_fielddef_setdefaultstr(upb_fielddef *f, const void *str, size_t len, + upb_status *s); +void upb_fielddef_setdefaultcstr(upb_fielddef *f, const char *str, + upb_status *s); +bool upb_fielddef_setsubdef(upb_fielddef *f, const upb_def *subdef, + upb_status *s); +bool upb_fielddef_setmsgsubdef(upb_fielddef *f, const upb_msgdef *subdef, + upb_status *s); +bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef, + upb_status *s); +bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, + upb_status *s); + +bool upb_fielddef_checklabel(int32_t label); +bool upb_fielddef_checktype(int32_t type); +bool upb_fielddef_checkdescriptortype(int32_t type); +bool upb_fielddef_checkintfmt(int32_t fmt); + +UPB_END_EXTERN_C + + +/* upb::MessageDef ************************************************************/ + +typedef upb_inttable_iter upb_msg_field_iter; +typedef upb_strtable_iter upb_msg_oneof_iter; + +#ifdef __cplusplus + +/* Structure that describes a single .proto message type. + * + * Its base class is upb::Def (use upb::upcast() to convert). */ +class upb::MessageDef { + public: + /* Returns NULL if memory allocation failed. */ + static reffed_ptr New(); + + /* upb::RefCounted methods like Ref()/Unref(). */ + UPB_REFCOUNTED_CPPMETHODS + + /* Functionality from upb::Def. */ + const char* full_name() const; + bool set_full_name(const char* fullname, Status* s); + bool set_full_name(const std::string& fullname, Status* s); + + /* Call to freeze this MessageDef. + * WARNING: this will fail if this message has any unfrozen submessages! + * Messages with cycles must be frozen as a batch using upb::Def::Freeze(). */ + bool Freeze(Status* s); + + /* The number of fields that belong to the MessageDef. */ + int field_count() const; + + /* The number of oneofs that belong to the MessageDef. */ + int oneof_count() const; + + /* Adds a field (upb_fielddef object) to a msgdef. Requires that the msgdef + * and the fielddefs are mutable. The fielddef's name and number must be + * set, and the message may not already contain any field with this name or + * number, and this fielddef may not be part of another message. In error + * cases false is returned and the msgdef is unchanged. + * + * If the given field is part of a oneof, this call succeeds if and only if + * that oneof is already part of this msgdef. (Note that adding a oneof to a + * msgdef automatically adds all of its fields to the msgdef at the time that + * the oneof is added, so it is usually more idiomatic to add the oneof's + * fields first then add the oneof to the msgdef. This case is supported for + * convenience.) + * + * If |f| is already part of this MessageDef, this method performs no action + * and returns true (success). Thus, this method is idempotent. */ + bool AddField(FieldDef* f, Status* s); + bool AddField(const reffed_ptr& f, Status* s); + + /* Adds a oneof (upb_oneofdef object) to a msgdef. Requires that the msgdef, + * oneof, and any fielddefs are mutable, that the fielddefs contained in the + * oneof do not have any name or number conflicts with existing fields in the + * msgdef, and that the oneof's name is unique among all oneofs in the msgdef. + * If the oneof is added successfully, all of its fields will be added + * directly to the msgdef as well. In error cases, false is returned and the + * msgdef is unchanged. */ + bool AddOneof(OneofDef* o, Status* s); + bool AddOneof(const reffed_ptr& o, Status* s); + + /* These return NULL if the field is not found. */ + FieldDef* FindFieldByNumber(uint32_t number); + FieldDef* FindFieldByName(const char *name, size_t len); + const FieldDef* FindFieldByNumber(uint32_t number) const; + const FieldDef* FindFieldByName(const char* name, size_t len) const; + + + FieldDef* FindFieldByName(const char *name) { + return FindFieldByName(name, strlen(name)); + } + const FieldDef* FindFieldByName(const char *name) const { + return FindFieldByName(name, strlen(name)); + } + + template + FieldDef* FindFieldByName(const T& str) { + return FindFieldByName(str.c_str(), str.size()); + } + template + const FieldDef* FindFieldByName(const T& str) const { + return FindFieldByName(str.c_str(), str.size()); + } + + OneofDef* FindOneofByName(const char* name, size_t len); + const OneofDef* FindOneofByName(const char* name, size_t len) const; + + OneofDef* FindOneofByName(const char* name) { + return FindOneofByName(name, strlen(name)); + } + const OneofDef* FindOneofByName(const char* name) const { + return FindOneofByName(name, strlen(name)); + } + + template + OneofDef* FindOneofByName(const T& str) { + return FindOneofByName(str.c_str(), str.size()); + } + template + const OneofDef* FindOneofByName(const T& str) const { + return FindOneofByName(str.c_str(), str.size()); + } + + /* Returns a new msgdef that is a copy of the given msgdef (and a copy of all + * the fields) but with any references to submessages broken and replaced + * with just the name of the submessage. Returns NULL if memory allocation + * failed. + * + * TODO(haberman): which is more useful, keeping fields resolved or + * unresolving them? If there's no obvious answer, Should this functionality + * just be moved into symtab.c? */ + MessageDef* Dup(const void* owner) const; + + /* Is this message a map entry? */ + void setmapentry(bool map_entry); + bool mapentry() const; + + /* Iteration over fields. The order is undefined. */ + class field_iterator + : public std::iterator { + public: + explicit field_iterator(MessageDef* md); + static field_iterator end(MessageDef* md); + + void operator++(); + FieldDef* operator*() const; + bool operator!=(const field_iterator& other) const; + bool operator==(const field_iterator& other) const; + + private: + upb_msg_field_iter iter_; + }; + + class const_field_iterator + : public std::iterator { + public: + explicit const_field_iterator(const MessageDef* md); + static const_field_iterator end(const MessageDef* md); + + void operator++(); + const FieldDef* operator*() const; + bool operator!=(const const_field_iterator& other) const; + bool operator==(const const_field_iterator& other) const; + + private: + upb_msg_field_iter iter_; + }; + + /* Iteration over oneofs. The order is undefined. */ + class oneof_iterator + : public std::iterator { + public: + explicit oneof_iterator(MessageDef* md); + static oneof_iterator end(MessageDef* md); + + void operator++(); + OneofDef* operator*() const; + bool operator!=(const oneof_iterator& other) const; + bool operator==(const oneof_iterator& other) const; + + private: + upb_msg_oneof_iter iter_; + }; + + class const_oneof_iterator + : public std::iterator { + public: + explicit const_oneof_iterator(const MessageDef* md); + static const_oneof_iterator end(const MessageDef* md); + + void operator++(); + const OneofDef* operator*() const; + bool operator!=(const const_oneof_iterator& other) const; + bool operator==(const const_oneof_iterator& other) const; + + private: + upb_msg_oneof_iter iter_; + }; + + class FieldAccessor { + public: + explicit FieldAccessor(MessageDef* msg) : msg_(msg) {} + field_iterator begin() { return msg_->field_begin(); } + field_iterator end() { return msg_->field_end(); } + private: + MessageDef* msg_; + }; + + class ConstFieldAccessor { + public: + explicit ConstFieldAccessor(const MessageDef* msg) : msg_(msg) {} + const_field_iterator begin() { return msg_->field_begin(); } + const_field_iterator end() { return msg_->field_end(); } + private: + const MessageDef* msg_; + }; + + class OneofAccessor { + public: + explicit OneofAccessor(MessageDef* msg) : msg_(msg) {} + oneof_iterator begin() { return msg_->oneof_begin(); } + oneof_iterator end() { return msg_->oneof_end(); } + private: + MessageDef* msg_; + }; + + class ConstOneofAccessor { + public: + explicit ConstOneofAccessor(const MessageDef* msg) : msg_(msg) {} + const_oneof_iterator begin() { return msg_->oneof_begin(); } + const_oneof_iterator end() { return msg_->oneof_end(); } + private: + const MessageDef* msg_; + }; + + field_iterator field_begin(); + field_iterator field_end(); + const_field_iterator field_begin() const; + const_field_iterator field_end() const; + + oneof_iterator oneof_begin(); + oneof_iterator oneof_end(); + const_oneof_iterator oneof_begin() const; + const_oneof_iterator oneof_end() const; + + FieldAccessor fields() { return FieldAccessor(this); } + ConstFieldAccessor fields() const { return ConstFieldAccessor(this); } + OneofAccessor oneofs() { return OneofAccessor(this); } + ConstOneofAccessor oneofs() const { return ConstOneofAccessor(this); } + + private: + UPB_DISALLOW_POD_OPS(MessageDef, upb::MessageDef) +}; + +#endif /* __cplusplus */ + +UPB_BEGIN_EXTERN_C + +/* Returns NULL if memory allocation failed. */ +upb_msgdef *upb_msgdef_new(const void *owner); + +/* Include upb_refcounted methods like upb_msgdef_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_msgdef, upb_msgdef_upcast2) + +bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status); + +const char *upb_msgdef_fullname(const upb_msgdef *m); +bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s); + +upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner); +bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor, + upb_status *s); +bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, + upb_status *s); + +/* Field lookup in a couple of different variations: + * - itof = int to field + * - ntof = name to field + * - ntofz = name to field, null-terminated string. */ +const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i); +const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, + size_t len); +int upb_msgdef_numfields(const upb_msgdef *m); + +UPB_INLINE const upb_fielddef *upb_msgdef_ntofz(const upb_msgdef *m, + const char *name) { + return upb_msgdef_ntof(m, name, strlen(name)); +} + +UPB_INLINE upb_fielddef *upb_msgdef_itof_mutable(upb_msgdef *m, uint32_t i) { + return (upb_fielddef*)upb_msgdef_itof(m, i); +} + +UPB_INLINE upb_fielddef *upb_msgdef_ntof_mutable(upb_msgdef *m, + const char *name, size_t len) { + return (upb_fielddef *)upb_msgdef_ntof(m, name, len); +} + +/* Oneof lookup: + * - ntoo = name to oneof + * - ntooz = name to oneof, null-terminated string. */ +const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, + size_t len); +int upb_msgdef_numoneofs(const upb_msgdef *m); + +UPB_INLINE const upb_oneofdef *upb_msgdef_ntooz(const upb_msgdef *m, + const char *name) { + return upb_msgdef_ntoo(m, name, strlen(name)); +} + +UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m, + const char *name, size_t len) { + return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len); +} + +void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry); +bool upb_msgdef_mapentry(const upb_msgdef *m); + +/* Well-known field tag numbers for map-entry messages. */ +#define UPB_MAPENTRY_KEY 1 +#define UPB_MAPENTRY_VALUE 2 + +const upb_oneofdef *upb_msgdef_findoneof(const upb_msgdef *m, + const char *name); +int upb_msgdef_numoneofs(const upb_msgdef *m); + +/* upb_msg_field_iter i; + * for(upb_msg_field_begin(&i, m); + * !upb_msg_field_done(&i); + * upb_msg_field_next(&i)) { + * upb_fielddef *f = upb_msg_iter_field(&i); + * // ... + * } + * + * For C we don't have separate iterators for const and non-const. + * It is the caller's responsibility to cast the upb_fielddef* to + * const if the upb_msgdef* is const. */ +void upb_msg_field_begin(upb_msg_field_iter *iter, const upb_msgdef *m); +void upb_msg_field_next(upb_msg_field_iter *iter); +bool upb_msg_field_done(const upb_msg_field_iter *iter); +upb_fielddef *upb_msg_iter_field(const upb_msg_field_iter *iter); +void upb_msg_field_iter_setdone(upb_msg_field_iter *iter); + +/* Similar to above, we also support iterating through the oneofs in a + * msgdef. */ +void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m); +void upb_msg_oneof_next(upb_msg_oneof_iter *iter); +bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter); +upb_oneofdef *upb_msg_iter_oneof(const upb_msg_oneof_iter *iter); +void upb_msg_oneof_iter_setdone(upb_msg_oneof_iter *iter); + +UPB_END_EXTERN_C + + +/* upb::EnumDef ***************************************************************/ + +typedef upb_strtable_iter upb_enum_iter; + +#ifdef __cplusplus + +/* Class that represents an enum. Its base class is upb::Def (convert with + * upb::upcast()). */ +class upb::EnumDef { + public: + /* Returns NULL if memory allocation failed. */ + static reffed_ptr New(); + + /* upb::RefCounted methods like Ref()/Unref(). */ + UPB_REFCOUNTED_CPPMETHODS + + /* Functionality from upb::Def. */ + const char* full_name() const; + bool set_full_name(const char* fullname, Status* s); + bool set_full_name(const std::string& fullname, Status* s); + + /* Call to freeze this EnumDef. */ + bool Freeze(Status* s); + + /* The value that is used as the default when no field default is specified. + * If not set explicitly, the first value that was added will be used. + * The default value must be a member of the enum. + * Requires that value_count() > 0. */ + int32_t default_value() const; + + /* Sets the default value. If this value is not valid, returns false and an + * error message in status. */ + bool set_default_value(int32_t val, Status* status); + + /* Returns the number of values currently defined in the enum. Note that + * multiple names can refer to the same number, so this may be greater than + * the total number of unique numbers. */ + int value_count() const; + + /* Adds a single name/number pair to the enum. Fails if this name has + * already been used by another value. */ + bool AddValue(const char* name, int32_t num, Status* status); + bool AddValue(const std::string& name, int32_t num, Status* status); + + /* Lookups from name to integer, returning true if found. */ + bool FindValueByName(const char* name, int32_t* num) const; + + /* Finds the name corresponding to the given number, or NULL if none was + * found. If more than one name corresponds to this number, returns the + * first one that was added. */ + const char* FindValueByNumber(int32_t num) const; + + /* Returns a new EnumDef with all the same values. The new EnumDef will be + * owned by the given owner. */ + EnumDef* Dup(const void* owner) const; + + /* Iteration over name/value pairs. The order is undefined. + * Adding an enum val invalidates any iterators. + * + * TODO: make compatible with range-for, with elements as pairs? */ + class Iterator { + public: + explicit Iterator(const EnumDef*); + + int32_t number(); + const char *name(); + bool Done(); + void Next(); + + private: + upb_enum_iter iter_; + }; + + private: + UPB_DISALLOW_POD_OPS(EnumDef, upb::EnumDef) +}; + +#endif /* __cplusplus */ + +UPB_BEGIN_EXTERN_C + +/* Native C API. */ +upb_enumdef *upb_enumdef_new(const void *owner); +upb_enumdef *upb_enumdef_dup(const upb_enumdef *e, const void *owner); + +/* Include upb_refcounted methods like upb_enumdef_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_enumdef, upb_enumdef_upcast2) + +bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status); + +/* From upb_def. */ +const char *upb_enumdef_fullname(const upb_enumdef *e); +bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, + upb_status *s); + +int32_t upb_enumdef_default(const upb_enumdef *e); +bool upb_enumdef_setdefault(upb_enumdef *e, int32_t val, upb_status *s); +int upb_enumdef_numvals(const upb_enumdef *e); +bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num, + upb_status *status); + +/* Enum lookups: + * - ntoi: look up a name with specified length. + * - ntoiz: look up a name provided as a null-terminated string. + * - iton: look up an integer, returning the name as a null-terminated + * string. */ +bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len, + int32_t *num); +UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e, + const char *name, int32_t *num) { + return upb_enumdef_ntoi(e, name, strlen(name), num); +} +const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num); + +/* upb_enum_iter i; + * for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) { + * // ... + * } + */ +void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e); +void upb_enum_next(upb_enum_iter *iter); +bool upb_enum_done(upb_enum_iter *iter); +const char *upb_enum_iter_name(upb_enum_iter *iter); +int32_t upb_enum_iter_number(upb_enum_iter *iter); + +UPB_END_EXTERN_C + +/* upb::OneofDef **************************************************************/ + +typedef upb_inttable_iter upb_oneof_iter; + +#ifdef __cplusplus + +/* Class that represents a oneof. Its base class is upb::Def (convert with + * upb::upcast()). */ +class upb::OneofDef { + public: + /* Returns NULL if memory allocation failed. */ + static reffed_ptr New(); + + /* upb::RefCounted methods like Ref()/Unref(). */ + UPB_REFCOUNTED_CPPMETHODS + + /* Functionality from upb::Def. */ + const char* full_name() const; + + /* Returns the MessageDef that owns this OneofDef. */ + const MessageDef* containing_type() const; + + /* Returns the name of this oneof. This is the name used to look up the oneof + * by name once added to a message def. */ + const char* name() const; + bool set_name(const char* name, Status* s); + + /* Returns the number of fields currently defined in the oneof. */ + int field_count() const; + + /* Adds a field to the oneof. The field must not have been added to any other + * oneof or msgdef. If the oneof is not yet part of a msgdef, then when the + * oneof is eventually added to a msgdef, all fields added to the oneof will + * also be added to the msgdef at that time. If the oneof is already part of a + * msgdef, the field must either be a part of that msgdef already, or must not + * be a part of any msgdef; in the latter case, the field is added to the + * msgdef as a part of this operation. + * + * The field may only have an OPTIONAL label, never REQUIRED or REPEATED. + * + * If |f| is already part of this MessageDef, this method performs no action + * and returns true (success). Thus, this method is idempotent. */ + bool AddField(FieldDef* field, Status* s); + bool AddField(const reffed_ptr& field, Status* s); + + /* Looks up by name. */ + const FieldDef* FindFieldByName(const char* name, size_t len) const; + FieldDef* FindFieldByName(const char* name, size_t len); + const FieldDef* FindFieldByName(const char* name) const { + return FindFieldByName(name, strlen(name)); + } + FieldDef* FindFieldByName(const char* name) { + return FindFieldByName(name, strlen(name)); + } + + template + FieldDef* FindFieldByName(const T& str) { + return FindFieldByName(str.c_str(), str.size()); + } + template + const FieldDef* FindFieldByName(const T& str) const { + return FindFieldByName(str.c_str(), str.size()); + } + + /* Looks up by tag number. */ + const FieldDef* FindFieldByNumber(uint32_t num) const; + + /* Returns a new OneofDef with all the same fields. The OneofDef will be owned + * by the given owner. */ + OneofDef* Dup(const void* owner) const; + + /* Iteration over fields. The order is undefined. */ + class iterator : public std::iterator { + public: + explicit iterator(OneofDef* md); + static iterator end(OneofDef* md); + + void operator++(); + FieldDef* operator*() const; + bool operator!=(const iterator& other) const; + bool operator==(const iterator& other) const; + + private: + upb_oneof_iter iter_; + }; + + class const_iterator + : public std::iterator { + public: + explicit const_iterator(const OneofDef* md); + static const_iterator end(const OneofDef* md); + + void operator++(); + const FieldDef* operator*() const; + bool operator!=(const const_iterator& other) const; + bool operator==(const const_iterator& other) const; + + private: + upb_oneof_iter iter_; + }; + + iterator begin(); + iterator end(); + const_iterator begin() const; + const_iterator end() const; + + private: + UPB_DISALLOW_POD_OPS(OneofDef, upb::OneofDef) +}; + +#endif /* __cplusplus */ + +UPB_BEGIN_EXTERN_C + +/* Native C API. */ +upb_oneofdef *upb_oneofdef_new(const void *owner); +upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner); + +/* Include upb_refcounted methods like upb_oneofdef_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast2) + +const char *upb_oneofdef_name(const upb_oneofdef *o); +bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s); + +const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o); +int upb_oneofdef_numfields(const upb_oneofdef *o); +bool upb_oneofdef_addfield(upb_oneofdef *o, upb_fielddef *f, + const void *ref_donor, + upb_status *s); + +/* Oneof lookups: + * - ntof: look up a field by name. + * - ntofz: look up a field by name (as a null-terminated string). + * - itof: look up a field by number. */ +const upb_fielddef *upb_oneofdef_ntof(const upb_oneofdef *o, + const char *name, size_t length); +UPB_INLINE const upb_fielddef *upb_oneofdef_ntofz(const upb_oneofdef *o, + const char *name) { + return upb_oneofdef_ntof(o, name, strlen(name)); +} +const upb_fielddef *upb_oneofdef_itof(const upb_oneofdef *o, uint32_t num); + +/* upb_oneof_iter i; + * for(upb_oneof_begin(&i, e); !upb_oneof_done(&i); upb_oneof_next(&i)) { + * // ... + * } + */ +void upb_oneof_begin(upb_oneof_iter *iter, const upb_oneofdef *o); +void upb_oneof_next(upb_oneof_iter *iter); +bool upb_oneof_done(upb_oneof_iter *iter); +upb_fielddef *upb_oneof_iter_field(const upb_oneof_iter *iter); +void upb_oneof_iter_setdone(upb_oneof_iter *iter); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +UPB_INLINE const char* upb_safecstr(const std::string& str) { + assert(str.size() == std::strlen(str.c_str())); + return str.c_str(); +} + +/* Inline C++ wrappers. */ +namespace upb { + +inline Def* Def::Dup(const void* owner) const { + return upb_def_dup(this, owner); +} +inline Def::Type Def::def_type() const { return upb_def_type(this); } +inline const char* Def::full_name() const { return upb_def_fullname(this); } +inline bool Def::set_full_name(const char* fullname, Status* s) { + return upb_def_setfullname(this, fullname, s); +} +inline bool Def::set_full_name(const std::string& fullname, Status* s) { + return upb_def_setfullname(this, upb_safecstr(fullname), s); +} +inline bool Def::Freeze(Def* const* defs, int n, Status* status) { + return upb_def_freeze(defs, n, status); +} +inline bool Def::Freeze(const std::vector& defs, Status* status) { + return upb_def_freeze((Def* const*)&defs[0], defs.size(), status); +} + +inline bool FieldDef::CheckType(int32_t val) { + return upb_fielddef_checktype(val); +} +inline bool FieldDef::CheckLabel(int32_t val) { + return upb_fielddef_checklabel(val); +} +inline bool FieldDef::CheckDescriptorType(int32_t val) { + return upb_fielddef_checkdescriptortype(val); +} +inline bool FieldDef::CheckIntegerFormat(int32_t val) { + return upb_fielddef_checkintfmt(val); +} +inline FieldDef::Type FieldDef::ConvertType(int32_t val) { + assert(CheckType(val)); + return static_cast(val); +} +inline FieldDef::Label FieldDef::ConvertLabel(int32_t val) { + assert(CheckLabel(val)); + return static_cast(val); +} +inline FieldDef::DescriptorType FieldDef::ConvertDescriptorType(int32_t val) { + assert(CheckDescriptorType(val)); + return static_cast(val); +} +inline FieldDef::IntegerFormat FieldDef::ConvertIntegerFormat(int32_t val) { + assert(CheckIntegerFormat(val)); + return static_cast(val); +} + +inline reffed_ptr FieldDef::New() { + upb_fielddef *f = upb_fielddef_new(&f); + return reffed_ptr(f, &f); +} +inline FieldDef* FieldDef::Dup(const void* owner) const { + return upb_fielddef_dup(this, owner); +} +inline const char* FieldDef::full_name() const { + return upb_fielddef_fullname(this); +} +inline bool FieldDef::set_full_name(const char* fullname, Status* s) { + return upb_fielddef_setfullname(this, fullname, s); +} +inline bool FieldDef::set_full_name(const std::string& fullname, Status* s) { + return upb_fielddef_setfullname(this, upb_safecstr(fullname), s); +} +inline bool FieldDef::type_is_set() const { + return upb_fielddef_typeisset(this); +} +inline FieldDef::Type FieldDef::type() const { return upb_fielddef_type(this); } +inline FieldDef::DescriptorType FieldDef::descriptor_type() const { + return upb_fielddef_descriptortype(this); +} +inline FieldDef::Label FieldDef::label() const { + return upb_fielddef_label(this); +} +inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); } +inline const char* FieldDef::name() const { return upb_fielddef_name(this); } +inline bool FieldDef::is_extension() const { + return upb_fielddef_isextension(this); +} +inline bool FieldDef::lazy() const { + return upb_fielddef_lazy(this); +} +inline void FieldDef::set_lazy(bool lazy) { + upb_fielddef_setlazy(this, lazy); +} +inline bool FieldDef::packed() const { + return upb_fielddef_packed(this); +} +inline void FieldDef::set_packed(bool packed) { + upb_fielddef_setpacked(this, packed); +} +inline const MessageDef* FieldDef::containing_type() const { + return upb_fielddef_containingtype(this); +} +inline const OneofDef* FieldDef::containing_oneof() const { + return upb_fielddef_containingoneof(this); +} +inline const char* FieldDef::containing_type_name() { + return upb_fielddef_containingtypename(this); +} +inline bool FieldDef::set_number(uint32_t number, Status* s) { + return upb_fielddef_setnumber(this, number, s); +} +inline bool FieldDef::set_name(const char *name, Status* s) { + return upb_fielddef_setname(this, name, s); +} +inline bool FieldDef::set_name(const std::string& name, Status* s) { + return upb_fielddef_setname(this, upb_safecstr(name), s); +} +inline bool FieldDef::set_containing_type_name(const char *name, Status* s) { + return upb_fielddef_setcontainingtypename(this, name, s); +} +inline bool FieldDef::set_containing_type_name(const std::string &name, + Status *s) { + return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s); +} +inline void FieldDef::set_type(upb_fieldtype_t type) { + upb_fielddef_settype(this, type); +} +inline void FieldDef::set_is_extension(bool is_extension) { + upb_fielddef_setisextension(this, is_extension); +} +inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) { + upb_fielddef_setdescriptortype(this, type); +} +inline void FieldDef::set_label(upb_label_t label) { + upb_fielddef_setlabel(this, label); +} +inline bool FieldDef::IsSubMessage() const { + return upb_fielddef_issubmsg(this); +} +inline bool FieldDef::IsString() const { return upb_fielddef_isstring(this); } +inline bool FieldDef::IsSequence() const { return upb_fielddef_isseq(this); } +inline bool FieldDef::IsMap() const { return upb_fielddef_ismap(this); } +inline int64_t FieldDef::default_int64() const { + return upb_fielddef_defaultint64(this); +} +inline int32_t FieldDef::default_int32() const { + return upb_fielddef_defaultint32(this); +} +inline uint64_t FieldDef::default_uint64() const { + return upb_fielddef_defaultuint64(this); +} +inline uint32_t FieldDef::default_uint32() const { + return upb_fielddef_defaultuint32(this); +} +inline bool FieldDef::default_bool() const { + return upb_fielddef_defaultbool(this); +} +inline float FieldDef::default_float() const { + return upb_fielddef_defaultfloat(this); +} +inline double FieldDef::default_double() const { + return upb_fielddef_defaultdouble(this); +} +inline const char* FieldDef::default_string(size_t* len) const { + return upb_fielddef_defaultstr(this, len); +} +inline void FieldDef::set_default_int64(int64_t value) { + upb_fielddef_setdefaultint64(this, value); +} +inline void FieldDef::set_default_int32(int32_t value) { + upb_fielddef_setdefaultint32(this, value); +} +inline void FieldDef::set_default_uint64(uint64_t value) { + upb_fielddef_setdefaultuint64(this, value); +} +inline void FieldDef::set_default_uint32(uint32_t value) { + upb_fielddef_setdefaultuint32(this, value); +} +inline void FieldDef::set_default_bool(bool value) { + upb_fielddef_setdefaultbool(this, value); +} +inline void FieldDef::set_default_float(float value) { + upb_fielddef_setdefaultfloat(this, value); +} +inline void FieldDef::set_default_double(double value) { + upb_fielddef_setdefaultdouble(this, value); +} +inline bool FieldDef::set_default_string(const void *str, size_t len, + Status *s) { + return upb_fielddef_setdefaultstr(this, str, len, s); +} +inline bool FieldDef::set_default_string(const std::string& str, Status* s) { + return upb_fielddef_setdefaultstr(this, str.c_str(), str.size(), s); +} +inline void FieldDef::set_default_cstr(const char* str, Status* s) { + return upb_fielddef_setdefaultcstr(this, str, s); +} +inline bool FieldDef::HasSubDef() const { return upb_fielddef_hassubdef(this); } +inline const Def* FieldDef::subdef() const { return upb_fielddef_subdef(this); } +inline const MessageDef *FieldDef::message_subdef() const { + return upb_fielddef_msgsubdef(this); +} +inline const EnumDef *FieldDef::enum_subdef() const { + return upb_fielddef_enumsubdef(this); +} +inline const char* FieldDef::subdef_name() const { + return upb_fielddef_subdefname(this); +} +inline bool FieldDef::set_subdef(const Def* subdef, Status* s) { + return upb_fielddef_setsubdef(this, subdef, s); +} +inline bool FieldDef::set_enum_subdef(const EnumDef* subdef, Status* s) { + return upb_fielddef_setenumsubdef(this, subdef, s); +} +inline bool FieldDef::set_message_subdef(const MessageDef* subdef, Status* s) { + return upb_fielddef_setmsgsubdef(this, subdef, s); +} +inline bool FieldDef::set_subdef_name(const char* name, Status* s) { + return upb_fielddef_setsubdefname(this, name, s); +} +inline bool FieldDef::set_subdef_name(const std::string& name, Status* s) { + return upb_fielddef_setsubdefname(this, upb_safecstr(name), s); +} + +inline reffed_ptr MessageDef::New() { + upb_msgdef *m = upb_msgdef_new(&m); + return reffed_ptr(m, &m); +} +inline const char *MessageDef::full_name() const { + return upb_msgdef_fullname(this); +} +inline bool MessageDef::set_full_name(const char* fullname, Status* s) { + return upb_msgdef_setfullname(this, fullname, s); +} +inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) { + return upb_msgdef_setfullname(this, upb_safecstr(fullname), s); +} +inline bool MessageDef::Freeze(Status* status) { + return upb_msgdef_freeze(this, status); +} +inline int MessageDef::field_count() const { + return upb_msgdef_numfields(this); +} +inline int MessageDef::oneof_count() const { + return upb_msgdef_numoneofs(this); +} +inline bool MessageDef::AddField(upb_fielddef* f, Status* s) { + return upb_msgdef_addfield(this, f, NULL, s); +} +inline bool MessageDef::AddField(const reffed_ptr& f, Status* s) { + return upb_msgdef_addfield(this, f.get(), NULL, s); +} +inline bool MessageDef::AddOneof(upb_oneofdef* o, Status* s) { + return upb_msgdef_addoneof(this, o, NULL, s); +} +inline bool MessageDef::AddOneof(const reffed_ptr& o, Status* s) { + return upb_msgdef_addoneof(this, o.get(), NULL, s); +} +inline FieldDef* MessageDef::FindFieldByNumber(uint32_t number) { + return upb_msgdef_itof_mutable(this, number); +} +inline FieldDef* MessageDef::FindFieldByName(const char* name, size_t len) { + return upb_msgdef_ntof_mutable(this, name, len); +} +inline const FieldDef* MessageDef::FindFieldByNumber(uint32_t number) const { + return upb_msgdef_itof(this, number); +} +inline const FieldDef *MessageDef::FindFieldByName(const char *name, + size_t len) const { + return upb_msgdef_ntof(this, name, len); +} +inline OneofDef* MessageDef::FindOneofByName(const char* name, size_t len) { + return upb_msgdef_ntoo_mutable(this, name, len); +} +inline const OneofDef* MessageDef::FindOneofByName(const char* name, + size_t len) const { + return upb_msgdef_ntoo(this, name, len); +} +inline MessageDef* MessageDef::Dup(const void *owner) const { + return upb_msgdef_dup(this, owner); +} +inline void MessageDef::setmapentry(bool map_entry) { + upb_msgdef_setmapentry(this, map_entry); +} +inline bool MessageDef::mapentry() const { + return upb_msgdef_mapentry(this); +} +inline MessageDef::field_iterator MessageDef::field_begin() { + return field_iterator(this); +} +inline MessageDef::field_iterator MessageDef::field_end() { + return field_iterator::end(this); +} +inline MessageDef::const_field_iterator MessageDef::field_begin() const { + return const_field_iterator(this); +} +inline MessageDef::const_field_iterator MessageDef::field_end() const { + return const_field_iterator::end(this); +} + +inline MessageDef::oneof_iterator MessageDef::oneof_begin() { + return oneof_iterator(this); +} +inline MessageDef::oneof_iterator MessageDef::oneof_end() { + return oneof_iterator::end(this); +} +inline MessageDef::const_oneof_iterator MessageDef::oneof_begin() const { + return const_oneof_iterator(this); +} +inline MessageDef::const_oneof_iterator MessageDef::oneof_end() const { + return const_oneof_iterator::end(this); +} + +inline MessageDef::field_iterator::field_iterator(MessageDef* md) { + upb_msg_field_begin(&iter_, md); +} +inline MessageDef::field_iterator MessageDef::field_iterator::end( + MessageDef* md) { + MessageDef::field_iterator iter(md); + upb_msg_field_iter_setdone(&iter.iter_); + return iter; +} +inline FieldDef* MessageDef::field_iterator::operator*() const { + return upb_msg_iter_field(&iter_); +} +inline void MessageDef::field_iterator::operator++() { + return upb_msg_field_next(&iter_); +} +inline bool MessageDef::field_iterator::operator==( + const field_iterator &other) const { + return upb_inttable_iter_isequal(&iter_, &other.iter_); +} +inline bool MessageDef::field_iterator::operator!=( + const field_iterator &other) const { + return !(*this == other); +} + +inline MessageDef::const_field_iterator::const_field_iterator( + const MessageDef* md) { + upb_msg_field_begin(&iter_, md); +} +inline MessageDef::const_field_iterator MessageDef::const_field_iterator::end( + const MessageDef *md) { + MessageDef::const_field_iterator iter(md); + upb_msg_field_iter_setdone(&iter.iter_); + return iter; +} +inline const FieldDef* MessageDef::const_field_iterator::operator*() const { + return upb_msg_iter_field(&iter_); +} +inline void MessageDef::const_field_iterator::operator++() { + return upb_msg_field_next(&iter_); +} +inline bool MessageDef::const_field_iterator::operator==( + const const_field_iterator &other) const { + return upb_inttable_iter_isequal(&iter_, &other.iter_); +} +inline bool MessageDef::const_field_iterator::operator!=( + const const_field_iterator &other) const { + return !(*this == other); +} + +inline MessageDef::oneof_iterator::oneof_iterator(MessageDef* md) { + upb_msg_oneof_begin(&iter_, md); +} +inline MessageDef::oneof_iterator MessageDef::oneof_iterator::end( + MessageDef* md) { + MessageDef::oneof_iterator iter(md); + upb_msg_oneof_iter_setdone(&iter.iter_); + return iter; +} +inline OneofDef* MessageDef::oneof_iterator::operator*() const { + return upb_msg_iter_oneof(&iter_); +} +inline void MessageDef::oneof_iterator::operator++() { + return upb_msg_oneof_next(&iter_); +} +inline bool MessageDef::oneof_iterator::operator==( + const oneof_iterator &other) const { + return upb_strtable_iter_isequal(&iter_, &other.iter_); +} +inline bool MessageDef::oneof_iterator::operator!=( + const oneof_iterator &other) const { + return !(*this == other); +} + +inline MessageDef::const_oneof_iterator::const_oneof_iterator( + const MessageDef* md) { + upb_msg_oneof_begin(&iter_, md); +} +inline MessageDef::const_oneof_iterator MessageDef::const_oneof_iterator::end( + const MessageDef *md) { + MessageDef::const_oneof_iterator iter(md); + upb_msg_oneof_iter_setdone(&iter.iter_); + return iter; +} +inline const OneofDef* MessageDef::const_oneof_iterator::operator*() const { + return upb_msg_iter_oneof(&iter_); +} +inline void MessageDef::const_oneof_iterator::operator++() { + return upb_msg_oneof_next(&iter_); +} +inline bool MessageDef::const_oneof_iterator::operator==( + const const_oneof_iterator &other) const { + return upb_strtable_iter_isequal(&iter_, &other.iter_); +} +inline bool MessageDef::const_oneof_iterator::operator!=( + const const_oneof_iterator &other) const { + return !(*this == other); +} + +inline reffed_ptr EnumDef::New() { + upb_enumdef *e = upb_enumdef_new(&e); + return reffed_ptr(e, &e); +} +inline const char* EnumDef::full_name() const { + return upb_enumdef_fullname(this); +} +inline bool EnumDef::set_full_name(const char* fullname, Status* s) { + return upb_enumdef_setfullname(this, fullname, s); +} +inline bool EnumDef::set_full_name(const std::string& fullname, Status* s) { + return upb_enumdef_setfullname(this, upb_safecstr(fullname), s); +} +inline bool EnumDef::Freeze(Status* status) { + return upb_enumdef_freeze(this, status); +} +inline int32_t EnumDef::default_value() const { + return upb_enumdef_default(this); +} +inline bool EnumDef::set_default_value(int32_t val, Status* status) { + return upb_enumdef_setdefault(this, val, status); +} +inline int EnumDef::value_count() const { return upb_enumdef_numvals(this); } +inline bool EnumDef::AddValue(const char* name, int32_t num, Status* status) { + return upb_enumdef_addval(this, name, num, status); +} +inline bool EnumDef::AddValue(const std::string& name, int32_t num, + Status* status) { + return upb_enumdef_addval(this, upb_safecstr(name), num, status); +} +inline bool EnumDef::FindValueByName(const char* name, int32_t *num) const { + return upb_enumdef_ntoiz(this, name, num); +} +inline const char* EnumDef::FindValueByNumber(int32_t num) const { + return upb_enumdef_iton(this, num); +} +inline EnumDef* EnumDef::Dup(const void* owner) const { + return upb_enumdef_dup(this, owner); +} + +inline EnumDef::Iterator::Iterator(const EnumDef* e) { + upb_enum_begin(&iter_, e); +} +inline int32_t EnumDef::Iterator::number() { + return upb_enum_iter_number(&iter_); +} +inline const char* EnumDef::Iterator::name() { + return upb_enum_iter_name(&iter_); +} +inline bool EnumDef::Iterator::Done() { return upb_enum_done(&iter_); } +inline void EnumDef::Iterator::Next() { return upb_enum_next(&iter_); } + +inline reffed_ptr OneofDef::New() { + upb_oneofdef *o = upb_oneofdef_new(&o); + return reffed_ptr(o, &o); +} +inline const char* OneofDef::full_name() const { + return upb_oneofdef_name(this); +} + +inline const MessageDef* OneofDef::containing_type() const { + return upb_oneofdef_containingtype(this); +} +inline const char* OneofDef::name() const { + return upb_oneofdef_name(this); +} +inline bool OneofDef::set_name(const char* name, Status* s) { + return upb_oneofdef_setname(this, name, s); +} +inline int OneofDef::field_count() const { + return upb_oneofdef_numfields(this); +} +inline bool OneofDef::AddField(FieldDef* field, Status* s) { + return upb_oneofdef_addfield(this, field, NULL, s); +} +inline bool OneofDef::AddField(const reffed_ptr& field, Status* s) { + return upb_oneofdef_addfield(this, field.get(), NULL, s); +} +inline const FieldDef* OneofDef::FindFieldByName(const char* name, + size_t len) const { + return upb_oneofdef_ntof(this, name, len); +} +inline const FieldDef* OneofDef::FindFieldByNumber(uint32_t num) const { + return upb_oneofdef_itof(this, num); +} +inline OneofDef::iterator OneofDef::begin() { return iterator(this); } +inline OneofDef::iterator OneofDef::end() { return iterator::end(this); } +inline OneofDef::const_iterator OneofDef::begin() const { + return const_iterator(this); +} +inline OneofDef::const_iterator OneofDef::end() const { + return const_iterator::end(this); +} + +inline OneofDef::iterator::iterator(OneofDef* o) { + upb_oneof_begin(&iter_, o); +} +inline OneofDef::iterator OneofDef::iterator::end(OneofDef* o) { + OneofDef::iterator iter(o); + upb_oneof_iter_setdone(&iter.iter_); + return iter; +} +inline FieldDef* OneofDef::iterator::operator*() const { + return upb_oneof_iter_field(&iter_); +} +inline void OneofDef::iterator::operator++() { return upb_oneof_next(&iter_); } +inline bool OneofDef::iterator::operator==(const iterator &other) const { + return upb_inttable_iter_isequal(&iter_, &other.iter_); +} +inline bool OneofDef::iterator::operator!=(const iterator &other) const { + return !(*this == other); +} + +inline OneofDef::const_iterator::const_iterator(const OneofDef* md) { + upb_oneof_begin(&iter_, md); +} +inline OneofDef::const_iterator OneofDef::const_iterator::end( + const OneofDef *md) { + OneofDef::const_iterator iter(md); + upb_oneof_iter_setdone(&iter.iter_); + return iter; +} +inline const FieldDef* OneofDef::const_iterator::operator*() const { + return upb_msg_iter_field(&iter_); +} +inline void OneofDef::const_iterator::operator++() { + return upb_oneof_next(&iter_); +} +inline bool OneofDef::const_iterator::operator==( + const const_iterator &other) const { + return upb_inttable_iter_isequal(&iter_, &other.iter_); +} +inline bool OneofDef::const_iterator::operator!=( + const const_iterator &other) const { + return !(*this == other); +} + +} /* namespace upb */ +#endif + +#endif /* UPB_DEF_H_ */ +/* +** This file contains definitions of structs that should be considered private +** and NOT stable across versions of upb. +** +** The only reason they are declared here and not in .c files is to allow upb +** and the application (if desired) to embed statically-initialized instances +** of structures like defs. +** +** If you include this file, all guarantees of ABI compatibility go out the +** window! Any code that includes this file needs to recompile against the +** exact same version of upb that they are linking against. +** +** You also need to recompile if you change the value of the UPB_DEBUG_REFS +** flag. +*/ + + +#ifndef UPB_STATICINIT_H_ +#define UPB_STATICINIT_H_ + +#ifdef __cplusplus +/* Because of how we do our typedefs, this header can't be included from C++. */ +#error This file cannot be included from C++ +#endif + +/* upb_refcounted *************************************************************/ + + +/* upb_def ********************************************************************/ + +struct upb_def { + upb_refcounted base; + + const char *fullname; + char type; /* A upb_deftype_t (char to save space) */ + + /* Used as a flag during the def's mutable stage. Must be false unless + * it is currently being used by a function on the stack. This allows + * us to easily determine which defs were passed into the function's + * current invocation. */ + bool came_from_user; +}; + +#define UPB_DEF_INIT(name, type, refs, ref2s) \ + { UPB_REFCOUNT_INIT(refs, ref2s), name, type, false } + + +/* upb_fielddef ***************************************************************/ + +struct upb_fielddef { + upb_def base; + + union { + int64_t sint; + uint64_t uint; + double dbl; + float flt; + void *bytes; + } defaultval; + union { + const upb_msgdef *def; /* If !msg_is_symbolic. */ + char *name; /* If msg_is_symbolic. */ + } msg; + union { + const upb_def *def; /* If !subdef_is_symbolic. */ + char *name; /* If subdef_is_symbolic. */ + } sub; /* The msgdef or enumdef for this field, if upb_hassubdef(f). */ + bool subdef_is_symbolic; + bool msg_is_symbolic; + const upb_oneofdef *oneof; + bool default_is_string; + bool type_is_set_; /* False until type is explicitly set. */ + bool is_extension_; + bool lazy_; + bool packed_; + upb_intfmt_t intfmt; + bool tagdelim; + upb_fieldtype_t type_; + upb_label_t label_; + uint32_t number_; + uint32_t selector_base; /* Used to index into a upb::Handlers table. */ + uint32_t index_; +}; + +#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy, \ + packed, name, num, msgdef, subdef, selector_base, \ + index, defaultval, refs, ref2s) \ + { \ + UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, {msgdef}, \ + {subdef}, NULL, false, false, \ + type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \ + lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \ + } + + +/* upb_msgdef *****************************************************************/ + +struct upb_msgdef { + upb_def base; + + size_t selector_count; + uint32_t submsg_field_count; + + /* Tables for looking up fields by number and name. */ + upb_inttable itof; /* int to field */ + upb_strtable ntof; /* name to field */ + + /* Tables for looking up oneofs by name. */ + upb_strtable ntoo; /* name to oneof */ + + /* Is this a map-entry message? + * TODO: set this flag properly for static descriptors; regenerate + * descriptor.upb.c. */ + bool map_entry; + + /* TODO(haberman): proper extension ranges (there can be multiple). */ +}; + +/* TODO: also support static initialization of the oneofs table. This will be + * needed if we compile in descriptors that contain oneofs. */ +#define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \ + refs, ref2s) \ + { \ + UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, \ + submsg_field_count, itof, ntof, \ + UPB_EMPTY_STRTABLE_INIT(UPB_CTYPE_PTR), false \ + } + + +/* upb_enumdef ****************************************************************/ + +struct upb_enumdef { + upb_def base; + + upb_strtable ntoi; + upb_inttable iton; + int32_t defaultval; +}; + +#define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \ + { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntoi, iton, defaultval } + + +/* upb_oneofdef ***************************************************************/ + +struct upb_oneofdef { + upb_def base; + + upb_strtable ntof; + upb_inttable itof; + const upb_msgdef *parent; +}; + +#define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \ + { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntof, itof } + + +/* upb_symtab *****************************************************************/ + +struct upb_symtab { + upb_refcounted base; + + upb_strtable symtab; +}; + +#define UPB_SYMTAB_INIT(symtab, refs, ref2s) \ + { UPB_REFCOUNT_INIT(refs, ref2s), symtab } + + +#endif /* UPB_STATICINIT_H_ */ +/* +** upb::Handlers (upb_handlers) +** +** A upb_handlers is like a virtual table for a upb_msgdef. Each field of the +** message can have associated functions that will be called when we are +** parsing or visiting a stream of data. This is similar to how handlers work +** in SAX (the Simple API for XML). +** +** The handlers have no idea where the data is coming from, so a single set of +** handlers could be used with two completely different data sources (for +** example, a parser and a visitor over in-memory objects). This decoupling is +** the most important feature of upb, because it allows parsers and serializers +** to be highly reusable. +** +** This is a mixed C/C++ interface that offers a full API to both languages. +** See the top-level README for more information. +*/ + +#ifndef UPB_HANDLERS_H +#define UPB_HANDLERS_H + + +#ifdef __cplusplus +namespace upb { +class BufferHandle; +class BytesHandler; +class HandlerAttributes; +class Handlers; +template class Handler; +template struct CanonicalType; +} /* namespace upb */ +#endif + +UPB_DECLARE_TYPE(upb::BufferHandle, upb_bufhandle) +UPB_DECLARE_TYPE(upb::BytesHandler, upb_byteshandler) +UPB_DECLARE_TYPE(upb::HandlerAttributes, upb_handlerattr) +UPB_DECLARE_DERIVED_TYPE(upb::Handlers, upb::RefCounted, + upb_handlers, upb_refcounted) + +/* The maximum depth that the handler graph can have. This is a resource limit + * for the C stack since we sometimes need to recursively traverse the graph. + * Cycles are ok; the traversal will stop when it detects a cycle, but we must + * hit the cycle before the maximum depth is reached. + * + * If having a single static limit is too inflexible, we can add another variant + * of Handlers::Freeze that allows specifying this as a parameter. */ +#define UPB_MAX_HANDLER_DEPTH 64 + +/* All the different types of handlers that can be registered. + * Only needed for the advanced functions in upb::Handlers. */ +typedef enum { + UPB_HANDLER_INT32, + UPB_HANDLER_INT64, + UPB_HANDLER_UINT32, + UPB_HANDLER_UINT64, + UPB_HANDLER_FLOAT, + UPB_HANDLER_DOUBLE, + UPB_HANDLER_BOOL, + UPB_HANDLER_STARTSTR, + UPB_HANDLER_STRING, + UPB_HANDLER_ENDSTR, + UPB_HANDLER_STARTSUBMSG, + UPB_HANDLER_ENDSUBMSG, + UPB_HANDLER_STARTSEQ, + UPB_HANDLER_ENDSEQ +} upb_handlertype_t; + +#define UPB_HANDLER_MAX (UPB_HANDLER_ENDSEQ+1) + +#define UPB_BREAK NULL + +/* A convenient definition for when no closure is needed. */ +extern char _upb_noclosure; +#define UPB_NO_CLOSURE &_upb_noclosure + +/* A selector refers to a specific field handler in the Handlers object + * (for example: the STARTSUBMSG handler for field "field15"). */ +typedef int32_t upb_selector_t; + +UPB_BEGIN_EXTERN_C + +/* Forward-declares for C inline accessors. We need to declare these here + * so we can "friend" them in the class declarations in C++. */ +UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, + upb_selector_t s); +UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr); +UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, + upb_selector_t s); + +UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h); +UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, + const void *type); +UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, + size_t ofs); +UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h); +UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h); +UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h); + +UPB_END_EXTERN_C + + +/* Static selectors for upb::Handlers. */ +#define UPB_STARTMSG_SELECTOR 0 +#define UPB_ENDMSG_SELECTOR 1 +#define UPB_STATIC_SELECTOR_COUNT 2 + +/* Static selectors for upb::BytesHandler. */ +#define UPB_STARTSTR_SELECTOR 0 +#define UPB_STRING_SELECTOR 1 +#define UPB_ENDSTR_SELECTOR 2 + +typedef void upb_handlerfree(void *d); + +#ifdef __cplusplus + +/* A set of attributes that accompanies a handler's function pointer. */ +class upb::HandlerAttributes { + public: + HandlerAttributes(); + ~HandlerAttributes(); + + /* Sets the handler data that will be passed as the second parameter of the + * handler. To free this pointer when the handlers are freed, call + * Handlers::AddCleanup(). */ + bool SetHandlerData(const void *handler_data); + const void* handler_data() const; + + /* Use this to specify the type of the closure. This will be checked against + * all other closure types for handler that use the same closure. + * Registration will fail if this does not match all other non-NULL closure + * types. */ + bool SetClosureType(const void *closure_type); + const void* closure_type() const; + + /* Use this to specify the type of the returned closure. Only used for + * Start*{String,SubMessage,Sequence} handlers. This must match the closure + * type of any handlers that use it (for example, the StringBuf handler must + * match the closure returned from StartString). */ + bool SetReturnClosureType(const void *return_closure_type); + const void* return_closure_type() const; + + /* Set to indicate that the handler always returns "ok" (either "true" or a + * non-NULL closure). This is a hint that can allow code generators to + * generate more efficient code. */ + bool SetAlwaysOk(bool always_ok); + bool always_ok() const; + + private: + friend UPB_INLINE const void * ::upb_handlerattr_handlerdata( + const upb_handlerattr *attr); +#else +struct upb_handlerattr { +#endif + const void *handler_data_; + const void *closure_type_; + const void *return_closure_type_; + bool alwaysok_; +}; + +#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, false} + +typedef struct { + upb_func *func; + + /* It is wasteful to include the entire attributes here: + * + * * Some of the information is redundant (like storing the closure type + * separately for each handler that must match). + * * Some of the info is only needed prior to freeze() (like closure types). + * * alignment padding wastes a lot of space for alwaysok_. + * + * If/when the size and locality of handlers is an issue, we can optimize this + * not to store the entire attr like this. We do not expose the table's + * layout to allow this optimization in the future. */ + upb_handlerattr attr; +} upb_handlers_tabent; + +#ifdef __cplusplus + +/* Extra information about a buffer that is passed to a StringBuf handler. + * TODO(haberman): allow the handle to be pinned so that it will outlive + * the handler invocation. */ +class upb::BufferHandle { + public: + BufferHandle(); + ~BufferHandle(); + + /* The beginning of the buffer. This may be different than the pointer + * passed to a StringBuf handler because the handler may receive data + * that is from the middle or end of a larger buffer. */ + const char* buffer() const; + + /* The offset within the attached object where this buffer begins. Only + * meaningful if there is an attached object. */ + size_t object_offset() const; + + /* Note that object_offset is the offset of "buf" within the attached + * object. */ + void SetBuffer(const char* buf, size_t object_offset); + + /* The BufferHandle can have an "attached object", which can be used to + * tunnel through a pointer to the buffer's underlying representation. */ + template + void SetAttachedObject(const T* obj); + + /* Returns NULL if the attached object is not of this type. */ + template + const T* GetAttachedObject() const; + + private: + friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h); + friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h, + const void *obj, + const void *type); + friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h, + const char *buf, size_t ofs); + friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h); + friend UPB_INLINE const void* ::upb_bufhandle_objtype( + const upb_bufhandle *h); + friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h); +#else +struct upb_bufhandle { +#endif + const char *buf_; + const void *obj_; + const void *objtype_; + size_t objofs_; +}; + +#ifdef __cplusplus + +/* A upb::Handlers object represents the set of handlers associated with a + * message in the graph of messages. You can think of it as a big virtual + * table with functions corresponding to all the events that can fire while + * parsing or visiting a message of a specific type. + * + * Any handlers that are not set behave as if they had successfully consumed + * the value. Any unset Start* handlers will propagate their closure to the + * inner frame. + * + * The easiest way to create the *Handler objects needed by the Set* methods is + * with the UpbBind() and UpbMakeHandler() macros; see below. */ +class upb::Handlers { + public: + typedef upb_selector_t Selector; + typedef upb_handlertype_t Type; + + typedef Handler StartFieldHandler; + typedef Handler EndFieldHandler; + typedef Handler StartMessageHandler; + typedef Handler EndMessageHandler; + typedef Handler StartStringHandler; + typedef Handler StringHandler; + + template struct ValueHandler { + typedef Handler H; + }; + + typedef ValueHandler::H Int32Handler; + typedef ValueHandler::H Int64Handler; + typedef ValueHandler::H UInt32Handler; + typedef ValueHandler::H UInt64Handler; + typedef ValueHandler::H FloatHandler; + typedef ValueHandler::H DoubleHandler; + typedef ValueHandler::H BoolHandler; + + /* Any function pointer can be converted to this and converted back to its + * correct type. */ + typedef void GenericFunction(); + + typedef void HandlersCallback(const void *closure, upb_handlers *h); + + /* Returns a new handlers object for the given frozen msgdef. + * Returns NULL if memory allocation failed. */ + static reffed_ptr New(const MessageDef *m); + + /* Convenience function for registering a graph of handlers that mirrors the + * graph of msgdefs for some message. For "m" and all its children a new set + * of handlers will be created and the given callback will be invoked, + * allowing the client to register handlers for this message. Note that any + * subhandlers set by the callback will be overwritten. */ + static reffed_ptr NewFrozen(const MessageDef *m, + HandlersCallback *callback, + const void *closure); + + /* Functionality from upb::RefCounted. */ + UPB_REFCOUNTED_CPPMETHODS + + /* All handler registration functions return bool to indicate success or + * failure; details about failures are stored in this status object. If a + * failure does occur, it must be cleared before the Handlers are frozen, + * otherwise the freeze() operation will fail. The functions may *only* be + * used while the Handlers are mutable. */ + const Status* status(); + void ClearError(); + + /* Call to freeze these Handlers. Requires that any SubHandlers are already + * frozen. For cycles, you must use the static version below and freeze the + * whole graph at once. */ + bool Freeze(Status* s); + + /* Freezes the given set of handlers. You may not freeze a handler without + * also freezing any handlers they point to. */ + static bool Freeze(Handlers*const* handlers, int n, Status* s); + static bool Freeze(const std::vector& handlers, Status* s); + + /* Returns the msgdef associated with this handlers object. */ + const MessageDef* message_def() const; + + /* Adds the given pointer and function to the list of cleanup functions that + * will be run when these handlers are freed. If this pointer has previously + * been registered, the function returns false and does nothing. */ + bool AddCleanup(void *ptr, upb_handlerfree *cleanup); + + /* Sets the startmsg handler for the message, which is defined as follows: + * + * bool startmsg(MyType* closure) { + * // Called when the message begins. Returns true if processing should + * // continue. + * return true; + * } + */ + bool SetStartMessageHandler(const StartMessageHandler& handler); + + /* Sets the endmsg handler for the message, which is defined as follows: + * + * bool endmsg(MyType* closure, upb_status *status) { + * // Called when processing of this message ends, whether in success or + * // failure. "status" indicates the final status of processing, and + * // can also be modified in-place to update the final status. + * } + */ + bool SetEndMessageHandler(const EndMessageHandler& handler); + + /* Sets the value handler for the given field, which is defined as follows + * (this is for an int32 field; other field types will pass their native + * C/C++ type for "val"): + * + * bool OnValue(MyClosure* c, const MyHandlerData* d, int32_t val) { + * // Called when the field's value is encountered. "d" contains + * // whatever data was bound to this field when it was registered. + * // Returns true if processing should continue. + * return true; + * } + * + * handers->SetInt32Handler(f, UpbBind(OnValue, new MyHandlerData(...))); + * + * The value type must exactly match f->type(). + * For example, a handler that takes an int32_t parameter may only be used for + * fields of type UPB_TYPE_INT32 and UPB_TYPE_ENUM. + * + * Returns false if the handler failed to register; in this case the cleanup + * handler (if any) will be called immediately. + */ + bool SetInt32Handler (const FieldDef* f, const Int32Handler& h); + bool SetInt64Handler (const FieldDef* f, const Int64Handler& h); + bool SetUInt32Handler(const FieldDef* f, const UInt32Handler& h); + bool SetUInt64Handler(const FieldDef* f, const UInt64Handler& h); + bool SetFloatHandler (const FieldDef* f, const FloatHandler& h); + bool SetDoubleHandler(const FieldDef* f, const DoubleHandler& h); + bool SetBoolHandler (const FieldDef* f, const BoolHandler& h); + + /* Like the previous, but templated on the type on the value (ie. int32). + * This is mostly useful to call from other templates. To call this you must + * specify the template parameter explicitly, ie: + * h->SetValueHandler(f, UpbBind(MyHandler, MyData)); */ + template + bool SetValueHandler( + const FieldDef *f, + const typename ValueHandler::Type>::H& handler); + + /* Sets handlers for a string field, which are defined as follows: + * + * MySubClosure* startstr(MyClosure* c, const MyHandlerData* d, + * size_t size_hint) { + * // Called when a string value begins. The return value indicates the + * // closure for the string. "size_hint" indicates the size of the + * // string if it is known, however if the string is length-delimited + * // and the end-of-string is not available size_hint will be zero. + * // This case is indistinguishable from the case where the size is + * // known to be zero. + * // + * // TODO(haberman): is it important to distinguish these cases? + * // If we had ssize_t as a type we could make -1 "unknown", but + * // ssize_t is POSIX (not ANSI) and therefore less portable. + * // In practice I suspect it won't be important to distinguish. + * return closure; + * } + * + * size_t str(MyClosure* closure, const MyHandlerData* d, + * const char *str, size_t len) { + * // Called for each buffer of string data; the multiple physical buffers + * // are all part of the same logical string. The return value indicates + * // how many bytes were consumed. If this number is less than "len", + * // this will also indicate that processing should be halted for now, + * // like returning false or UPB_BREAK from any other callback. If + * // number is greater than "len", the excess bytes will be skipped over + * // and not passed to the callback. + * return len; + * } + * + * bool endstr(MyClosure* c, const MyHandlerData* d) { + * // Called when a string value ends. Return value indicates whether + * // processing should continue. + * return true; + * } + */ + bool SetStartStringHandler(const FieldDef* f, const StartStringHandler& h); + bool SetStringHandler(const FieldDef* f, const StringHandler& h); + bool SetEndStringHandler(const FieldDef* f, const EndFieldHandler& h); + + /* Sets the startseq handler, which is defined as follows: + * + * MySubClosure *startseq(MyClosure* c, const MyHandlerData* d) { + * // Called when a sequence (repeated field) begins. The returned + * // pointer indicates the closure for the sequence (or UPB_BREAK + * // to interrupt processing). + * return closure; + * } + * + * h->SetStartSequenceHandler(f, UpbBind(startseq, new MyHandlerData(...))); + * + * Returns "false" if "f" does not belong to this message or is not a + * repeated field. + */ + bool SetStartSequenceHandler(const FieldDef* f, const StartFieldHandler& h); + + /* Sets the startsubmsg handler for the given field, which is defined as + * follows: + * + * MySubClosure* startsubmsg(MyClosure* c, const MyHandlerData* d) { + * // Called when a submessage begins. The returned pointer indicates the + * // closure for the sequence (or UPB_BREAK to interrupt processing). + * return closure; + * } + * + * h->SetStartSubMessageHandler(f, UpbBind(startsubmsg, + * new MyHandlerData(...))); + * + * Returns "false" if "f" does not belong to this message or is not a + * submessage/group field. + */ + bool SetStartSubMessageHandler(const FieldDef* f, const StartFieldHandler& h); + + /* Sets the endsubmsg handler for the given field, which is defined as + * follows: + * + * bool endsubmsg(MyClosure* c, const MyHandlerData* d) { + * // Called when a submessage ends. Returns true to continue processing. + * return true; + * } + * + * Returns "false" if "f" does not belong to this message or is not a + * submessage/group field. + */ + bool SetEndSubMessageHandler(const FieldDef *f, const EndFieldHandler &h); + + /* Starts the endsubseq handler for the given field, which is defined as + * follows: + * + * bool endseq(MyClosure* c, const MyHandlerData* d) { + * // Called when a sequence ends. Returns true continue processing. + * return true; + * } + * + * Returns "false" if "f" does not belong to this message or is not a + * repeated field. + */ + bool SetEndSequenceHandler(const FieldDef* f, const EndFieldHandler& h); + + /* Sets or gets the object that specifies handlers for the given field, which + * must be a submessage or group. Returns NULL if no handlers are set. */ + bool SetSubHandlers(const FieldDef* f, const Handlers* sub); + const Handlers* GetSubHandlers(const FieldDef* f) const; + + /* Equivalent to GetSubHandlers, but takes the STARTSUBMSG selector for the + * field. */ + const Handlers* GetSubHandlers(Selector startsubmsg) const; + + /* A selector refers to a specific field handler in the Handlers object + * (for example: the STARTSUBMSG handler for field "field15"). + * On success, returns true and stores the selector in "s". + * If the FieldDef or Type are invalid, returns false. + * The returned selector is ONLY valid for Handlers whose MessageDef + * contains this FieldDef. */ + static bool GetSelector(const FieldDef* f, Type type, Selector* s); + + /* Given a START selector of any kind, returns the corresponding END selector. */ + static Selector GetEndSelector(Selector start_selector); + + /* Returns the function pointer for this handler. It is the client's + * responsibility to cast to the correct function type before calling it. */ + GenericFunction* GetHandler(Selector selector); + + /* Sets the given attributes to the attributes for this selector. */ + bool GetAttributes(Selector selector, HandlerAttributes* attr); + + /* Returns the handler data that was registered with this handler. */ + const void* GetHandlerData(Selector selector); + + /* Could add any of the following functions as-needed, with some minor + * implementation changes: + * + * const FieldDef* GetFieldDef(Selector selector); + * static bool IsSequence(Selector selector); */ + + private: + UPB_DISALLOW_POD_OPS(Handlers, upb::Handlers) + + friend UPB_INLINE GenericFunction *::upb_handlers_gethandler( + const upb_handlers *h, upb_selector_t s); + friend UPB_INLINE const void *::upb_handlers_gethandlerdata( + const upb_handlers *h, upb_selector_t s); +#else +struct upb_handlers { +#endif + upb_refcounted base; + + const upb_msgdef *msg; + const upb_handlers **sub; + const void *top_closure_type; + upb_inttable cleanup_; + upb_status status_; /* Used only when mutable. */ + upb_handlers_tabent table[1]; /* Dynamically-sized field handler array. */ +}; + +#ifdef __cplusplus + +namespace upb { + +/* Convenience macros for creating a Handler object that is wrapped with a + * type-safe wrapper function that converts the "void*" parameters/returns + * of the underlying C API into nice C++ function. + * + * Sample usage: + * void OnValue1(MyClosure* c, const MyHandlerData* d, int32_t val) { + * // do stuff ... + * } + * + * // Handler that doesn't need any data bound to it. + * void OnValue2(MyClosure* c, int32_t val) { + * // do stuff ... + * } + * + * // Handler that returns bool so it can return failure if necessary. + * bool OnValue3(MyClosure* c, int32_t val) { + * // do stuff ... + * return ok; + * } + * + * // Member function handler. + * class MyClosure { + * public: + * void OnValue(int32_t val) { + * // do stuff ... + * } + * }; + * + * // Takes ownership of the MyHandlerData. + * handlers->SetInt32Handler(f1, UpbBind(OnValue1, new MyHandlerData(...))); + * handlers->SetInt32Handler(f2, UpbMakeHandler(OnValue2)); + * handlers->SetInt32Handler(f1, UpbMakeHandler(OnValue3)); + * handlers->SetInt32Handler(f2, UpbMakeHandler(&MyClosure::OnValue)); + */ + +#ifdef UPB_CXX11 + +/* In C++11, the "template" disambiguator can appear even outside templates, + * so all calls can safely use this pair of macros. */ + +#define UpbMakeHandler(f) upb::MatchFunc(f).template GetFunc() + +/* We have to be careful to only evaluate "d" once. */ +#define UpbBind(f, d) upb::MatchFunc(f).template GetFunc((d)) + +#else + +/* Prior to C++11, the "template" disambiguator may only appear inside a + * template, so the regular macro must not use "template" */ + +#define UpbMakeHandler(f) upb::MatchFunc(f).GetFunc() + +#define UpbBind(f, d) upb::MatchFunc(f).GetFunc((d)) + +#endif /* UPB_CXX11 */ + +/* This macro must be used in C++98 for calls from inside a template. But we + * define this variant in all cases; code that wants to be compatible with both + * C++98 and C++11 should always use this macro when calling from a template. */ +#define UpbMakeHandlerT(f) upb::MatchFunc(f).template GetFunc() + +/* We have to be careful to only evaluate "d" once. */ +#define UpbBindT(f, d) upb::MatchFunc(f).template GetFunc((d)) + +/* Handler: a struct that contains the (handler, data, deleter) tuple that is + * used to register all handlers. Users can Make() these directly but it's + * more convenient to use the UpbMakeHandler/UpbBind macros above. */ +template class Handler { + public: + /* The underlying, handler function signature that upb uses internally. */ + typedef T FuncPtr; + + /* Intentionally implicit. */ + template Handler(F func); + ~Handler(); + + private: + void AddCleanup(Handlers* h) const { + if (cleanup_func_) { + bool ok = h->AddCleanup(cleanup_data_, cleanup_func_); + UPB_ASSERT_VAR(ok, ok); + } + } + + UPB_DISALLOW_COPY_AND_ASSIGN(Handler) + friend class Handlers; + FuncPtr handler_; + mutable HandlerAttributes attr_; + mutable bool registered_; + void *cleanup_data_; + upb_handlerfree *cleanup_func_; +}; + +} /* namespace upb */ + +#endif /* __cplusplus */ + +UPB_BEGIN_EXTERN_C + +/* Native C API. */ + +/* Handler function typedefs. */ +typedef bool upb_startmsg_handlerfunc(void *c, const void*); +typedef bool upb_endmsg_handlerfunc(void *c, const void *, upb_status *status); +typedef void* upb_startfield_handlerfunc(void *c, const void *hd); +typedef bool upb_endfield_handlerfunc(void *c, const void *hd); +typedef bool upb_int32_handlerfunc(void *c, const void *hd, int32_t val); +typedef bool upb_int64_handlerfunc(void *c, const void *hd, int64_t val); +typedef bool upb_uint32_handlerfunc(void *c, const void *hd, uint32_t val); +typedef bool upb_uint64_handlerfunc(void *c, const void *hd, uint64_t val); +typedef bool upb_float_handlerfunc(void *c, const void *hd, float val); +typedef bool upb_double_handlerfunc(void *c, const void *hd, double val); +typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val); +typedef void *upb_startstr_handlerfunc(void *c, const void *hd, + size_t size_hint); +typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf, + size_t n, const upb_bufhandle* handle); + +/* upb_bufhandle */ +size_t upb_bufhandle_objofs(const upb_bufhandle *h); + +/* upb_handlerattr */ +void upb_handlerattr_init(upb_handlerattr *attr); +void upb_handlerattr_uninit(upb_handlerattr *attr); + +bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, const void *hd); +bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type); +const void *upb_handlerattr_closuretype(const upb_handlerattr *attr); +bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, + const void *type); +const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr); +bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok); +bool upb_handlerattr_alwaysok(const upb_handlerattr *attr); + +UPB_INLINE const void *upb_handlerattr_handlerdata( + const upb_handlerattr *attr) { + return attr->handler_data_; +} + +/* upb_handlers */ +typedef void upb_handlers_callback(const void *closure, upb_handlers *h); +upb_handlers *upb_handlers_new(const upb_msgdef *m, + const void *owner); +const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, + const void *owner, + upb_handlers_callback *callback, + const void *closure); + +/* Include refcounted methods like upb_handlers_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_handlers, upb_handlers_upcast) + +const upb_status *upb_handlers_status(upb_handlers *h); +void upb_handlers_clearerr(upb_handlers *h); +const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h); +bool upb_handlers_addcleanup(upb_handlers *h, void *p, upb_handlerfree *hfree); + +bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setint32(upb_handlers *h, const upb_fielddef *f, + upb_int32_handlerfunc *func, upb_handlerattr *attr); +bool upb_handlers_setint64(upb_handlers *h, const upb_fielddef *f, + upb_int64_handlerfunc *func, upb_handlerattr *attr); +bool upb_handlers_setuint32(upb_handlers *h, const upb_fielddef *f, + upb_uint32_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setuint64(upb_handlers *h, const upb_fielddef *f, + upb_uint64_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setfloat(upb_handlers *h, const upb_fielddef *f, + upb_float_handlerfunc *func, upb_handlerattr *attr); +bool upb_handlers_setdouble(upb_handlers *h, const upb_fielddef *f, + upb_double_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setbool(upb_handlers *h, const upb_fielddef *f, + upb_bool_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setstartstr(upb_handlers *h, const upb_fielddef *f, + upb_startstr_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setstring(upb_handlers *h, const upb_fielddef *f, + upb_string_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setendstr(upb_handlers *h, const upb_fielddef *f, + upb_endfield_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setstartseq(upb_handlers *h, const upb_fielddef *f, + upb_startfield_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setstartsubmsg(upb_handlers *h, const upb_fielddef *f, + upb_startfield_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setendsubmsg(upb_handlers *h, const upb_fielddef *f, + upb_endfield_handlerfunc *func, + upb_handlerattr *attr); +bool upb_handlers_setendseq(upb_handlers *h, const upb_fielddef *f, + upb_endfield_handlerfunc *func, + upb_handlerattr *attr); + +bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, + const upb_handlers *sub); +const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, + const upb_fielddef *f); +const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, + upb_selector_t sel); + +UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, + upb_selector_t s) { + return (upb_func *)h->table[s].func; +} + +bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s, + upb_handlerattr *attr); + +UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, + upb_selector_t s) { + return upb_handlerattr_handlerdata(&h->table[s].attr); +} + +#ifdef __cplusplus + +/* Handler types for single fields. + * Right now we only have one for TYPE_BYTES but ones for other types + * should follow. + * + * These follow the same handlers protocol for fields of a message. */ +class upb::BytesHandler { + public: + BytesHandler(); + ~BytesHandler(); +#else +struct upb_byteshandler { +#endif + upb_handlers_tabent table[3]; +}; + +void upb_byteshandler_init(upb_byteshandler *h); + +/* Caller must ensure that "d" outlives the handlers. + * TODO(haberman): should this have a "freeze" operation? It's not necessary + * for memory management, but could be useful to force immutability and provide + * a convenient moment to verify that all registration succeeded. */ +bool upb_byteshandler_setstartstr(upb_byteshandler *h, + upb_startstr_handlerfunc *func, void *d); +bool upb_byteshandler_setstring(upb_byteshandler *h, + upb_string_handlerfunc *func, void *d); +bool upb_byteshandler_setendstr(upb_byteshandler *h, + upb_endfield_handlerfunc *func, void *d); + +/* "Static" methods */ +bool upb_handlers_freeze(upb_handlers *const *handlers, int n, upb_status *s); +upb_handlertype_t upb_handlers_getprimitivehandlertype(const upb_fielddef *f); +bool upb_handlers_getselector(const upb_fielddef *f, upb_handlertype_t type, + upb_selector_t *s); +UPB_INLINE upb_selector_t upb_handlers_getendselector(upb_selector_t start) { + return start + 1; +} + +/* Internal-only. */ +uint32_t upb_handlers_selectorbaseoffset(const upb_fielddef *f); +uint32_t upb_handlers_selectorcount(const upb_fielddef *f); + +UPB_END_EXTERN_C + +/* +** Inline definitions for handlers.h, which are particularly long and a bit +** tricky. +*/ + +#ifndef UPB_HANDLERS_INL_H_ +#define UPB_HANDLERS_INL_H_ + +#include + +/* C inline methods. */ + +/* upb_bufhandle */ +UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) { + h->obj_ = NULL; + h->objtype_ = NULL; + h->buf_ = NULL; + h->objofs_ = 0; +} +UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) { + UPB_UNUSED(h); +} +UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, + const void *type) { + h->obj_ = obj; + h->objtype_ = type; +} +UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, + size_t ofs) { + h->buf_ = buf; + h->objofs_ = ofs; +} +UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) { + return h->obj_; +} +UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) { + return h->objtype_; +} +UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) { + return h->buf_; +} + + +#ifdef __cplusplus + +/* Type detection and typedefs for integer types. + * For platforms where there are multiple 32-bit or 64-bit types, we need to be + * able to enumerate them so we can properly create overloads for all variants. + * + * If any platform existed where there were three integer types with the same + * size, this would have to become more complicated. For example, short, int, + * and long could all be 32-bits. Even more diabolically, short, int, long, + * and long long could all be 64 bits and still be standard-compliant. + * However, few platforms are this strange, and it's unlikely that upb will be + * used on the strangest ones. */ + +/* Can't count on stdint.h limits like INT32_MAX, because in C++ these are + * only defined when __STDC_LIMIT_MACROS are defined before the *first* include + * of stdint.h. We can't guarantee that someone else didn't include these first + * without defining __STDC_LIMIT_MACROS. */ +#define UPB_INT32_MAX 0x7fffffffLL +#define UPB_INT32_MIN (-UPB_INT32_MAX - 1) +#define UPB_INT64_MAX 0x7fffffffffffffffLL +#define UPB_INT64_MIN (-UPB_INT64_MAX - 1) + +#if INT_MAX == UPB_INT32_MAX && INT_MIN == UPB_INT32_MIN +#define UPB_INT_IS_32BITS 1 +#endif + +#if LONG_MAX == UPB_INT32_MAX && LONG_MIN == UPB_INT32_MIN +#define UPB_LONG_IS_32BITS 1 +#endif + +#if LONG_MAX == UPB_INT64_MAX && LONG_MIN == UPB_INT64_MIN +#define UPB_LONG_IS_64BITS 1 +#endif + +#if LLONG_MAX == UPB_INT64_MAX && LLONG_MIN == UPB_INT64_MIN +#define UPB_LLONG_IS_64BITS 1 +#endif + +/* We use macros instead of typedefs so we can undefine them later and avoid + * leaking them outside this header file. */ +#if UPB_INT_IS_32BITS +#define UPB_INT32_T int +#define UPB_UINT32_T unsigned int + +#if UPB_LONG_IS_32BITS +#define UPB_TWO_32BIT_TYPES 1 +#define UPB_INT32ALT_T long +#define UPB_UINT32ALT_T unsigned long +#endif /* UPB_LONG_IS_32BITS */ + +#elif UPB_LONG_IS_32BITS /* && !UPB_INT_IS_32BITS */ +#define UPB_INT32_T long +#define UPB_UINT32_T unsigned long +#endif /* UPB_INT_IS_32BITS */ + + +#if UPB_LONG_IS_64BITS +#define UPB_INT64_T long +#define UPB_UINT64_T unsigned long + +#if UPB_LLONG_IS_64BITS +#define UPB_TWO_64BIT_TYPES 1 +#define UPB_INT64ALT_T long long +#define UPB_UINT64ALT_T unsigned long long +#endif /* UPB_LLONG_IS_64BITS */ + +#elif UPB_LLONG_IS_64BITS /* && !UPB_LONG_IS_64BITS */ +#define UPB_INT64_T long long +#define UPB_UINT64_T unsigned long long +#endif /* UPB_LONG_IS_64BITS */ + +#undef UPB_INT32_MAX +#undef UPB_INT32_MIN +#undef UPB_INT64_MAX +#undef UPB_INT64_MIN +#undef UPB_INT_IS_32BITS +#undef UPB_LONG_IS_32BITS +#undef UPB_LONG_IS_64BITS +#undef UPB_LLONG_IS_64BITS + + +namespace upb { + +typedef void CleanupFunc(void *ptr); + +/* Template to remove "const" from "const T*" and just return "T*". + * + * We define a nonsense default because otherwise it will fail to instantiate as + * a function parameter type even in cases where we don't expect any caller to + * actually match the overload. */ +class CouldntRemoveConst {}; +template struct remove_constptr { typedef CouldntRemoveConst type; }; +template struct remove_constptr { typedef T *type; }; + +/* Template that we use below to remove a template specialization from + * consideration if it matches a specific type. */ +template struct disable_if_same { typedef void Type; }; +template struct disable_if_same {}; + +template void DeletePointer(void *p) { delete static_cast(p); } + +template +struct FirstUnlessVoidOrBool { + typedef T1 value; +}; + +template +struct FirstUnlessVoidOrBool { + typedef T2 value; +}; + +template +struct FirstUnlessVoidOrBool { + typedef T2 value; +}; + +template +struct is_same { + static bool value; +}; + +template +struct is_same { + static bool value; +}; + +template +bool is_same::value = false; + +template +bool is_same::value = true; + +/* FuncInfo *******************************************************************/ + +/* Info about the user's original, pre-wrapped function. */ +template +struct FuncInfo { + /* The type of the closure that the function takes (its first param). */ + typedef C Closure; + + /* The return type. */ + typedef R Return; +}; + +/* Func ***********************************************************************/ + +/* Func1, Func2, Func3: Template classes representing a function and its + * signature. + * + * Since the function is a template parameter, calling the function can be + * inlined at compile-time and does not require a function pointer at runtime. + * These functions are not bound to a handler data so have no data or cleanup + * handler. */ +struct UnboundFunc { + CleanupFunc *GetCleanup() { return NULL; } + void *GetData() { return NULL; } +}; + +template +struct Func1 : public UnboundFunc { + typedef R Return; + typedef I FuncInfo; + static R Call(P1 p1) { return F(p1); } +}; + +template +struct Func2 : public UnboundFunc { + typedef R Return; + typedef I FuncInfo; + static R Call(P1 p1, P2 p2) { return F(p1, p2); } +}; + +template +struct Func3 : public UnboundFunc { + typedef R Return; + typedef I FuncInfo; + static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } +}; + +template +struct Func4 : public UnboundFunc { + typedef R Return; + typedef I FuncInfo; + static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); } +}; + +template +struct Func5 : public UnboundFunc { + typedef R Return; + typedef I FuncInfo; + static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { + return F(p1, p2, p3, p4, p5); + } +}; + +/* BoundFunc ******************************************************************/ + +/* BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that + * shall be bound to the function's second parameter. + * + * Note that the second parameter is a const pointer, but our stored bound value + * is non-const so we can free it when the handlers are destroyed. */ +template +struct BoundFunc { + typedef typename remove_constptr::type MutableP2; + explicit BoundFunc(MutableP2 data_) : data(data_) {} + CleanupFunc *GetCleanup() { return &DeletePointer; } + MutableP2 GetData() { return data; } + MutableP2 data; +}; + +template +struct BoundFunc2 : public BoundFunc { + typedef BoundFunc Base; + typedef I FuncInfo; + explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} +}; + +template +struct BoundFunc3 : public BoundFunc { + typedef BoundFunc Base; + typedef I FuncInfo; + explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} +}; + +template +struct BoundFunc4 : public BoundFunc { + typedef BoundFunc Base; + typedef I FuncInfo; + explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} +}; + +template +struct BoundFunc5 : public BoundFunc { + typedef BoundFunc Base; + typedef I FuncInfo; + explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {} +}; + +/* FuncSig ********************************************************************/ + +/* FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function + * *signature*, but without a specific function attached. + * + * These classes contain member functions that can be invoked with a + * specific function to return a Func/BoundFunc class. */ +template +struct FuncSig1 { + template + Func1 > GetFunc() { + return Func1 >(); + } +}; + +template +struct FuncSig2 { + template + Func2 > GetFunc() { + return Func2 >(); + } + + template + BoundFunc2 > GetFunc( + typename remove_constptr::type param2) { + return BoundFunc2 >(param2); + } +}; + +template +struct FuncSig3 { + template + Func3 > GetFunc() { + return Func3 >(); + } + + template + BoundFunc3 > GetFunc( + typename remove_constptr::type param2) { + return BoundFunc3 >(param2); + } +}; + +template +struct FuncSig4 { + template + Func4 > GetFunc() { + return Func4 >(); + } + + template + BoundFunc4 > GetFunc( + typename remove_constptr::type param2) { + return BoundFunc4 >(param2); + } +}; + +template +struct FuncSig5 { + template + Func5 > GetFunc() { + return Func5 >(); + } + + template + BoundFunc5 > GetFunc( + typename remove_constptr::type param2) { + return BoundFunc5 >(param2); + } +}; + +/* Overloaded template function that can construct the appropriate FuncSig* + * class given a function pointer by deducing the template parameters. */ +template +inline FuncSig1 MatchFunc(R (*f)(P1)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return FuncSig1(); +} + +template +inline FuncSig2 MatchFunc(R (*f)(P1, P2)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return FuncSig2(); +} + +template +inline FuncSig3 MatchFunc(R (*f)(P1, P2, P3)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return FuncSig3(); +} + +template +inline FuncSig4 MatchFunc(R (*f)(P1, P2, P3, P4)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return FuncSig4(); +} + +template +inline FuncSig5 MatchFunc(R (*f)(P1, P2, P3, P4, P5)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return FuncSig5(); +} + +/* MethodSig ******************************************************************/ + +/* CallMethod*: a function template that calls a given method. */ +template +R CallMethod0(C *obj) { + return ((*obj).*F)(); +} + +template +R CallMethod1(C *obj, P1 arg1) { + return ((*obj).*F)(arg1); +} + +template +R CallMethod2(C *obj, P1 arg1, P2 arg2) { + return ((*obj).*F)(arg1, arg2); +} + +template +R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { + return ((*obj).*F)(arg1, arg2, arg3); +} + +template +R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) { + return ((*obj).*F)(arg1, arg2, arg3, arg4); +} + +/* MethodSig: like FuncSig, but for member functions. + * + * GetFunc() returns a normal FuncN object, so after calling GetFunc() no + * more logic is required to special-case methods. */ +template +struct MethodSig0 { + template + Func1, FuncInfo > GetFunc() { + return Func1, FuncInfo >(); + } +}; + +template +struct MethodSig1 { + template + Func2, FuncInfo > GetFunc() { + return Func2, FuncInfo >(); + } + + template + BoundFunc2, FuncInfo > GetFunc( + typename remove_constptr::type param1) { + return BoundFunc2, FuncInfo >( + param1); + } +}; + +template +struct MethodSig2 { + template + Func3, FuncInfo > + GetFunc() { + return Func3, + FuncInfo >(); + } + + template + BoundFunc3, FuncInfo > + GetFunc(typename remove_constptr::type param1) { + return BoundFunc3, + FuncInfo >(param1); + } +}; + +template +struct MethodSig3 { + template + Func4, FuncInfo > + GetFunc() { + return Func4, + FuncInfo >(); + } + + template + BoundFunc4, + FuncInfo > + GetFunc(typename remove_constptr::type param1) { + return BoundFunc4, + FuncInfo >(param1); + } +}; + +template +struct MethodSig4 { + template + Func5, + FuncInfo > + GetFunc() { + return Func5, + FuncInfo >(); + } + + template + BoundFunc5, + FuncInfo > + GetFunc(typename remove_constptr::type param1) { + return BoundFunc5, FuncInfo >( + param1); + } +}; + +template +inline MethodSig0 MatchFunc(R (C::*f)()) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return MethodSig0(); +} + +template +inline MethodSig1 MatchFunc(R (C::*f)(P1)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return MethodSig1(); +} + +template +inline MethodSig2 MatchFunc(R (C::*f)(P1, P2)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return MethodSig2(); +} + +template +inline MethodSig3 MatchFunc(R (C::*f)(P1, P2, P3)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return MethodSig3(); +} + +template +inline MethodSig4 MatchFunc(R (C::*f)(P1, P2, P3, P4)) { + UPB_UNUSED(f); /* Only used for template parameter deduction. */ + return MethodSig4(); +} + +/* MaybeWrapReturn ************************************************************/ + +/* Template class that attempts to wrap the return value of the function so it + * matches the expected type. There are two main adjustments it may make: + * + * 1. If the function returns void, make it return the expected type and with + * a value that always indicates success. + * 2. If the function returns bool, make it return the expected type with a + * value that indicates success or failure. + * + * The "expected type" for return is: + * 1. void* for start handlers. If the closure parameter has a different type + * we will cast it to void* for the return in the success case. + * 2. size_t for string buffer handlers. + * 3. bool for everything else. */ + +/* Template parameters are FuncN type and desired return type. */ +template +struct MaybeWrapReturn; + +/* If the return type matches, return the given function unwrapped. */ +template +struct MaybeWrapReturn { + typedef F Func; +}; + +/* Function wrapper that munges the return value from void to (bool)true. */ +template +bool ReturnTrue2(P1 p1, P2 p2) { + F(p1, p2); + return true; +} + +template +bool ReturnTrue3(P1 p1, P2 p2, P3 p3) { + F(p1, p2, p3); + return true; +} + +/* Function wrapper that munges the return value from void to (void*)arg1 */ +template +void *ReturnClosure2(P1 p1, P2 p2) { + F(p1, p2); + return p1; +} + +template +void *ReturnClosure3(P1 p1, P2 p2, P3 p3) { + F(p1, p2, p3); + return p1; +} + +/* Function wrapper that munges the return value from R to void*. */ +template +void *CastReturnToVoidPtr2(P1 p1, P2 p2) { + return F(p1, p2); +} + +template +void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { + return F(p1, p2, p3); +} + +/* Function wrapper that munges the return value from bool to void*. */ +template +void *ReturnClosureOrBreak2(P1 p1, P2 p2) { + return F(p1, p2) ? p1 : UPB_BREAK; +} + +template +void *ReturnClosureOrBreak3(P1 p1, P2 p2, P3 p3) { + return F(p1, p2, p3) ? p1 : UPB_BREAK; +} + +/* For the string callback, which takes five params, returns the size param. */ +template +size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4, + const BufferHandle *p5) { + F(p1, p2, p3, p4, p5); + return p4; +} + +/* For the string callback, which takes five params, returns the size param or + * zero. */ +template +size_t ReturnNOr0(P1 p1, P2 p2, const char *p3, size_t p4, + const BufferHandle *p5) { + return F(p1, p2, p3, p4, p5) ? p4 : 0; +} + +/* If we have a function returning void but want a function returning bool, wrap + * it in a function that returns true. */ +template +struct MaybeWrapReturn, bool> { + typedef Func2, I> Func; +}; + +template +struct MaybeWrapReturn, bool> { + typedef Func3, I> Func; +}; + +/* If our function returns void but we want one returning void*, wrap it in a + * function that returns the first argument. */ +template +struct MaybeWrapReturn, void *> { + typedef Func2, I> Func; +}; + +template +struct MaybeWrapReturn, void *> { + typedef Func3, I> Func; +}; + +/* If our function returns R* but we want one returning void*, wrap it in a + * function that casts to void*. */ +template +struct MaybeWrapReturn, void *, + typename disable_if_same::Type> { + typedef Func2, I> Func; +}; + +template +struct MaybeWrapReturn, void *, + typename disable_if_same::Type> { + typedef Func3, I> + Func; +}; + +/* If our function returns bool but we want one returning void*, wrap it in a + * function that returns either the first param or UPB_BREAK. */ +template +struct MaybeWrapReturn, void *> { + typedef Func2, I> Func; +}; + +template +struct MaybeWrapReturn, void *> { + typedef Func3, I> + Func; +}; + +/* If our function returns void but we want one returning size_t, wrap it in a + * function that returns the size argument. */ +template +struct MaybeWrapReturn< + Func5, + size_t> { + typedef Func5, I> Func; +}; + +/* If our function returns bool but we want one returning size_t, wrap it in a + * function that returns either 0 or the buf size. */ +template +struct MaybeWrapReturn< + Func5, + size_t> { + typedef Func5, I> Func; +}; + +/* ConvertParams **************************************************************/ + +/* Template class that converts the function parameters if necessary, and + * ignores the HandlerData parameter if appropriate. + * + * Template parameter is the are FuncN function type. */ +template +struct ConvertParams; + +/* Function that discards the handler data parameter. */ +template +R IgnoreHandlerData2(void *p1, const void *hd) { + UPB_UNUSED(hd); + return F(static_cast(p1)); +} + +template +R IgnoreHandlerData3(void *p1, const void *hd, P2Wrapper p2) { + UPB_UNUSED(hd); + return F(static_cast(p1), p2); +} + +template +R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { + UPB_UNUSED(hd); + return F(static_cast(p1), p2, p3); +} + +template +R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) { + UPB_UNUSED(hd); + return F(static_cast(p1), p2, p3, p4); +} + +template +R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2, + size_t p3, const BufferHandle *handle) { + UPB_UNUSED(hd); + UPB_UNUSED(handle); + return F(static_cast(p1), p2, p3); +} + +/* Function that casts the handler data parameter. */ +template +R CastHandlerData2(void *c, const void *hd) { + return F(static_cast(c), static_cast(hd)); +} + +template +R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { + return F(static_cast(c), static_cast(hd), p3); +} + +template +R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) { + return F(static_cast(c), static_cast(hd), p3, p4, p5); +} + +template +R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3, + size_t p4, const BufferHandle *handle) { + UPB_UNUSED(handle); + return F(static_cast(c), static_cast(hd), p3, p4); +} + +/* For unbound functions, ignore the handler data. */ +template +struct ConvertParams, T> { + typedef Func2, I> Func; +}; + +template +struct ConvertParams, + R2 (*)(P1_2, P2_2, P3_2)> { + typedef Func3, I> Func; +}; + +/* For StringBuffer only; this ignores both the handler data and the + * BufferHandle. */ +template +struct ConvertParams, T> { + typedef Func5, + I> Func; +}; + +template +struct ConvertParams, T> { + typedef Func5, I> Func; +}; + +/* For bound functions, cast the handler data. */ +template +struct ConvertParams, T> { + typedef Func2, I> + Func; +}; + +template +struct ConvertParams, + R2 (*)(P1_2, P2_2, P3_2)> { + typedef Func3, I> Func; +}; + +/* For StringBuffer only; this ignores the BufferHandle. */ +template +struct ConvertParams, T> { + typedef Func5, + I> Func; +}; + +template +struct ConvertParams, T> { + typedef Func5, I> Func; +}; + +/* utype/ltype are upper/lower-case, ctype is canonical C type, vtype is + * variant C type. */ +#define TYPE_METHODS(utype, ltype, ctype, vtype) \ + template <> struct CanonicalType { \ + typedef ctype Type; \ + }; \ + template <> \ + inline bool Handlers::SetValueHandler( \ + const FieldDef *f, \ + const Handlers::utype ## Handler& handler) { \ + assert(!handler.registered_); \ + handler.AddCleanup(this); \ + handler.registered_ = true; \ + return upb_handlers_set##ltype(this, f, handler.handler_, &handler.attr_); \ + } \ + +TYPE_METHODS(Double, double, double, double) +TYPE_METHODS(Float, float, float, float) +TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64_T) +TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32_T) +TYPE_METHODS(Int64, int64, int64_t, UPB_INT64_T) +TYPE_METHODS(Int32, int32, int32_t, UPB_INT32_T) +TYPE_METHODS(Bool, bool, bool, bool) + +#ifdef UPB_TWO_32BIT_TYPES +TYPE_METHODS(Int32, int32, int32_t, UPB_INT32ALT_T) +TYPE_METHODS(UInt32, uint32, uint32_t, UPB_UINT32ALT_T) +#endif + +#ifdef UPB_TWO_64BIT_TYPES +TYPE_METHODS(Int64, int64, int64_t, UPB_INT64ALT_T) +TYPE_METHODS(UInt64, uint64, uint64_t, UPB_UINT64ALT_T) +#endif +#undef TYPE_METHODS + +template <> struct CanonicalType { + typedef Status* Type; +}; + +/* Type methods that are only one-per-canonical-type and not + * one-per-cvariant. */ + +#define TYPE_METHODS(utype, ctype) \ + inline bool Handlers::Set##utype##Handler(const FieldDef *f, \ + const utype##Handler &h) { \ + return SetValueHandler(f, h); \ + } \ + +TYPE_METHODS(Double, double) +TYPE_METHODS(Float, float) +TYPE_METHODS(UInt64, uint64_t) +TYPE_METHODS(UInt32, uint32_t) +TYPE_METHODS(Int64, int64_t) +TYPE_METHODS(Int32, int32_t) +TYPE_METHODS(Bool, bool) +#undef TYPE_METHODS + +template struct ReturnOf; + +template +struct ReturnOf { + typedef R Return; +}; + +template +struct ReturnOf { + typedef R Return; +}; + +template +struct ReturnOf { + typedef R Return; +}; + +template +struct ReturnOf { + typedef R Return; +}; + +template const void *UniquePtrForType() { + static const char ch = 0; + return &ch; +} + +template +template +inline Handler::Handler(F func) + : registered_(false), + cleanup_data_(func.GetData()), + cleanup_func_(func.GetCleanup()) { + upb_handlerattr_sethandlerdata(&attr_, func.GetData()); + typedef typename ReturnOf::Return Return; + typedef typename ConvertParams::Func ConvertedParamsFunc; + typedef typename MaybeWrapReturn::Func + ReturnWrappedFunc; + handler_ = ReturnWrappedFunc().Call; + + /* Set attributes based on what templates can statically tell us about the + * user's function. */ + + /* If the original function returns void, then we know that we wrapped it to + * always return ok. */ + bool always_ok = is_same::value; + attr_.SetAlwaysOk(always_ok); + + /* Closure parameter and return type. */ + attr_.SetClosureType(UniquePtrForType()); + + /* We use the closure type (from the first parameter) if the return type is + * void or bool, since these are the two cases we wrap to return the closure's + * type anyway. + * + * This is all nonsense for non START* handlers, but it doesn't matter because + * in that case the value will be ignored. */ + typedef typename FirstUnlessVoidOrBool::value + EffectiveReturn; + attr_.SetReturnClosureType(UniquePtrForType()); +} + +template +inline Handler::~Handler() { + assert(registered_); +} + +inline HandlerAttributes::HandlerAttributes() { upb_handlerattr_init(this); } +inline HandlerAttributes::~HandlerAttributes() { upb_handlerattr_uninit(this); } +inline bool HandlerAttributes::SetHandlerData(const void *hd) { + return upb_handlerattr_sethandlerdata(this, hd); +} +inline const void* HandlerAttributes::handler_data() const { + return upb_handlerattr_handlerdata(this); +} +inline bool HandlerAttributes::SetClosureType(const void *type) { + return upb_handlerattr_setclosuretype(this, type); +} +inline const void* HandlerAttributes::closure_type() const { + return upb_handlerattr_closuretype(this); +} +inline bool HandlerAttributes::SetReturnClosureType(const void *type) { + return upb_handlerattr_setreturnclosuretype(this, type); +} +inline const void* HandlerAttributes::return_closure_type() const { + return upb_handlerattr_returnclosuretype(this); +} +inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) { + return upb_handlerattr_setalwaysok(this, always_ok); +} +inline bool HandlerAttributes::always_ok() const { + return upb_handlerattr_alwaysok(this); +} + +inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); } +inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); } +inline const char* BufferHandle::buffer() const { + return upb_bufhandle_buf(this); +} +inline size_t BufferHandle::object_offset() const { + return upb_bufhandle_objofs(this); +} +inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) { + upb_bufhandle_setbuf(this, buf, ofs); +} +template +void BufferHandle::SetAttachedObject(const T* obj) { + upb_bufhandle_setobj(this, obj, UniquePtrForType()); +} +template +const T* BufferHandle::GetAttachedObject() const { + return upb_bufhandle_objtype(this) == UniquePtrForType() + ? static_cast(upb_bufhandle_obj(this)) + : NULL; +} + +inline reffed_ptr Handlers::New(const MessageDef *m) { + upb_handlers *h = upb_handlers_new(m, &h); + return reffed_ptr(h, &h); +} +inline reffed_ptr Handlers::NewFrozen( + const MessageDef *m, upb_handlers_callback *callback, + const void *closure) { + const upb_handlers *h = upb_handlers_newfrozen(m, &h, callback, closure); + return reffed_ptr(h, &h); +} +inline const Status* Handlers::status() { + return upb_handlers_status(this); +} +inline void Handlers::ClearError() { + return upb_handlers_clearerr(this); +} +inline bool Handlers::Freeze(Status *s) { + upb::Handlers* h = this; + return upb_handlers_freeze(&h, 1, s); +} +inline bool Handlers::Freeze(Handlers *const *handlers, int n, Status *s) { + return upb_handlers_freeze(handlers, n, s); +} +inline bool Handlers::Freeze(const std::vector& h, Status* status) { + return upb_handlers_freeze((Handlers* const*)&h[0], h.size(), status); +} +inline const MessageDef *Handlers::message_def() const { + return upb_handlers_msgdef(this); +} +inline bool Handlers::AddCleanup(void *p, upb_handlerfree *func) { + return upb_handlers_addcleanup(this, p, func); +} +inline bool Handlers::SetStartMessageHandler( + const Handlers::StartMessageHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setstartmsg(this, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetEndMessageHandler( + const Handlers::EndMessageHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setendmsg(this, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetStartStringHandler(const FieldDef *f, + const StartStringHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setstartstr(this, f, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetEndStringHandler(const FieldDef *f, + const EndFieldHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setendstr(this, f, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetStringHandler(const FieldDef *f, + const StringHandler& handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setstring(this, f, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetStartSequenceHandler( + const FieldDef *f, const StartFieldHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setstartseq(this, f, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetStartSubMessageHandler( + const FieldDef *f, const StartFieldHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setstartsubmsg(this, f, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetEndSubMessageHandler(const FieldDef *f, + const EndFieldHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setendsubmsg(this, f, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetEndSequenceHandler(const FieldDef *f, + const EndFieldHandler &handler) { + assert(!handler.registered_); + handler.registered_ = true; + handler.AddCleanup(this); + return upb_handlers_setendseq(this, f, handler.handler_, &handler.attr_); +} +inline bool Handlers::SetSubHandlers(const FieldDef *f, const Handlers *sub) { + return upb_handlers_setsubhandlers(this, f, sub); +} +inline const Handlers *Handlers::GetSubHandlers(const FieldDef *f) const { + return upb_handlers_getsubhandlers(this, f); +} +inline const Handlers *Handlers::GetSubHandlers(Handlers::Selector sel) const { + return upb_handlers_getsubhandlers_sel(this, sel); +} +inline bool Handlers::GetSelector(const FieldDef *f, Handlers::Type type, + Handlers::Selector *s) { + return upb_handlers_getselector(f, type, s); +} +inline Handlers::Selector Handlers::GetEndSelector(Handlers::Selector start) { + return upb_handlers_getendselector(start); +} +inline Handlers::GenericFunction *Handlers::GetHandler( + Handlers::Selector selector) { + return upb_handlers_gethandler(this, selector); +} +inline const void *Handlers::GetHandlerData(Handlers::Selector selector) { + return upb_handlers_gethandlerdata(this, selector); +} + +inline BytesHandler::BytesHandler() { + upb_byteshandler_init(this); +} + +inline BytesHandler::~BytesHandler() {} + +} /* namespace upb */ + +#endif /* __cplusplus */ + + +#undef UPB_TWO_32BIT_TYPES +#undef UPB_TWO_64BIT_TYPES +#undef UPB_INT32_T +#undef UPB_UINT32_T +#undef UPB_INT32ALT_T +#undef UPB_UINT32ALT_T +#undef UPB_INT64_T +#undef UPB_UINT64_T +#undef UPB_INT64ALT_T +#undef UPB_UINT64ALT_T + +#endif /* UPB_HANDLERS_INL_H_ */ + +#endif /* UPB_HANDLERS_H */ +/* +** upb::Environment (upb_env) +** +** A upb::Environment provides a means for injecting malloc and an +** error-reporting callback into encoders/decoders. This allows them to be +** independent of nearly all assumptions about their actual environment. +** +** It is also a container for allocating the encoders/decoders themselves that +** insulates clients from knowing their actual size. This provides ABI +** compatibility even if the size of the objects change. And this allows the +** structure definitions to be in the .c files instead of the .h files, making +** the .h files smaller and more readable. +*/ + + +#ifndef UPB_ENV_H_ +#define UPB_ENV_H_ + +#ifdef __cplusplus +namespace upb { +class Environment; +class SeededAllocator; +} +#endif + +UPB_DECLARE_TYPE(upb::Environment, upb_env) +UPB_DECLARE_TYPE(upb::SeededAllocator, upb_seededalloc) + +typedef void *upb_alloc_func(void *ud, void *ptr, size_t oldsize, size_t size); +typedef void upb_cleanup_func(void *ud); +typedef bool upb_error_func(void *ud, const upb_status *status); + +#ifdef __cplusplus + +/* An environment is *not* thread-safe. */ +class upb::Environment { + public: + Environment(); + ~Environment(); + + /* Set a custom memory allocation function for the environment. May ONLY + * be called before any calls to Malloc()/Realloc()/AddCleanup() below. + * If this is not called, the system realloc() function will be used. + * The given user pointer "ud" will be passed to the allocation function. + * + * The allocation function will not receive corresponding "free" calls. it + * must ensure that the memory is valid for the lifetime of the Environment, + * but it may be reclaimed any time thereafter. The likely usage is that + * "ud" points to a stateful allocator, and that the allocator frees all + * memory, arena-style, when it is destroyed. In this case the allocator must + * outlive the Environment. Another possibility is that the allocation + * function returns GC-able memory that is guaranteed to be GC-rooted for the + * life of the Environment. */ + void SetAllocationFunction(upb_alloc_func* alloc, void* ud); + + template + void SetAllocator(T* allocator) { + SetAllocationFunction(allocator->GetAllocationFunction(), allocator); + } + + /* Set a custom error reporting function. */ + void SetErrorFunction(upb_error_func* func, void* ud); + + /* Set the error reporting function to simply copy the status to the given + * status and abort. */ + void ReportErrorsTo(Status* status); + + /* Returns true if all allocations and AddCleanup() calls have succeeded, + * and no errors were reported with ReportError() (except ones that recovered + * successfully). */ + bool ok() const; + + /* Functions for use by encoders/decoders. **********************************/ + + /* Reports an error to this environment's callback, returning true if + * the caller should try to recover. */ + bool ReportError(const Status* status); + + /* Allocate memory. Uses the environment's allocation function. + * + * There is no need to free(). All memory will be freed automatically, but is + * guaranteed to outlive the Environment. */ + void* Malloc(size_t size); + + /* Reallocate memory. Preserves "oldsize" bytes from the existing buffer + * Requires: oldsize <= existing_size. + * + * TODO(haberman): should we also enforce that oldsize <= size? */ + void* Realloc(void* ptr, size_t oldsize, size_t size); + + /* Add a cleanup function to run when the environment is destroyed. + * Returns false on out-of-memory. + * + * The first call to AddCleanup() after SetAllocationFunction() is guaranteed + * to return true -- this makes it possible to robustly set a cleanup handler + * for a custom allocation function. */ + bool AddCleanup(upb_cleanup_func* func, void* ud); + + /* Total number of bytes that have been allocated. It is undefined what + * Realloc() does to this counter. */ + size_t BytesAllocated() const; + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Environment) + +#else +struct upb_env { +#endif /* __cplusplus */ + + bool ok_; + size_t bytes_allocated; + + /* Alloc function. */ + upb_alloc_func *alloc; + void *alloc_ud; + + /* Error-reporting function. */ + upb_error_func *err; + void *err_ud; + + /* Userdata for default alloc func. */ + void *default_alloc_ud; + + /* Cleanup entries. Pointer to a cleanup_ent, defined in env.c */ + void *cleanup_head; + + /* For future expansion, since the size of this struct is exposed to users. */ + void *future1; + void *future2; +}; + +UPB_BEGIN_EXTERN_C + +void upb_env_init(upb_env *e); +void upb_env_uninit(upb_env *e); +void upb_env_setallocfunc(upb_env *e, upb_alloc_func *func, void *ud); +void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud); +void upb_env_reporterrorsto(upb_env *e, upb_status *status); +bool upb_env_ok(const upb_env *e); +bool upb_env_reporterror(upb_env *e, const upb_status *status); +void *upb_env_malloc(upb_env *e, size_t size); +void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size); +bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud); +size_t upb_env_bytesallocated(const upb_env *e); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +/* An allocator that allocates from an initial memory region (likely the stack) + * before falling back to another allocator. */ +class upb::SeededAllocator { + public: + SeededAllocator(void *mem, size_t len); + ~SeededAllocator(); + + /* Set a custom fallback memory allocation function for the allocator, to use + * once the initial region runs out. + * + * May ONLY be called before GetAllocationFunction(). If this is not + * called, the system realloc() will be the fallback allocator. */ + void SetFallbackAllocator(upb_alloc_func *alloc, void *ud); + + /* Gets the allocation function for this allocator. */ + upb_alloc_func* GetAllocationFunction(); + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(SeededAllocator) + +#else +struct upb_seededalloc { +#endif /* __cplusplus */ + + /* Fallback alloc function. */ + upb_alloc_func *alloc; + upb_cleanup_func *alloc_cleanup; + void *alloc_ud; + bool need_cleanup; + bool returned_allocfunc; + + /* Userdata for default alloc func. */ + void *default_alloc_ud; + + /* Pointers for the initial memory region. */ + char *mem_base; + char *mem_ptr; + char *mem_limit; + + /* For future expansion, since the size of this struct is exposed to users. */ + void *future1; + void *future2; +}; + +UPB_BEGIN_EXTERN_C + +void upb_seededalloc_init(upb_seededalloc *a, void *mem, size_t len); +void upb_seededalloc_uninit(upb_seededalloc *a); +void upb_seededalloc_setfallbackalloc(upb_seededalloc *a, upb_alloc_func *func, + void *ud); +upb_alloc_func *upb_seededalloc_getallocfunc(upb_seededalloc *a); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upb { + +inline Environment::Environment() { + upb_env_init(this); +} +inline Environment::~Environment() { + upb_env_uninit(this); +} +inline void Environment::SetAllocationFunction(upb_alloc_func *alloc, + void *ud) { + upb_env_setallocfunc(this, alloc, ud); +} +inline void Environment::SetErrorFunction(upb_error_func *func, void *ud) { + upb_env_seterrorfunc(this, func, ud); +} +inline void Environment::ReportErrorsTo(Status* status) { + upb_env_reporterrorsto(this, status); +} +inline bool Environment::ok() const { + return upb_env_ok(this); +} +inline bool Environment::ReportError(const Status* status) { + return upb_env_reporterror(this, status); +} +inline void *Environment::Malloc(size_t size) { + return upb_env_malloc(this, size); +} +inline void *Environment::Realloc(void *ptr, size_t oldsize, size_t size) { + return upb_env_realloc(this, ptr, oldsize, size); +} +inline bool Environment::AddCleanup(upb_cleanup_func *func, void *ud) { + return upb_env_addcleanup(this, func, ud); +} +inline size_t Environment::BytesAllocated() const { + return upb_env_bytesallocated(this); +} + +inline SeededAllocator::SeededAllocator(void *mem, size_t len) { + upb_seededalloc_init(this, mem, len); +} +inline SeededAllocator::~SeededAllocator() { + upb_seededalloc_uninit(this); +} +inline void SeededAllocator::SetFallbackAllocator(upb_alloc_func *alloc, + void *ud) { + upb_seededalloc_setfallbackalloc(this, alloc, ud); +} +inline upb_alloc_func *SeededAllocator::GetAllocationFunction() { + return upb_seededalloc_getallocfunc(this); +} + +} /* namespace upb */ + +#endif /* __cplusplus */ + +#endif /* UPB_ENV_H_ */ +/* +** upb::Sink (upb_sink) +** upb::BytesSink (upb_bytessink) +** +** A upb_sink is an object that binds a upb_handlers object to some runtime +** state. It is the object that can actually receive data via the upb_handlers +** interface. +** +** Unlike upb_def and upb_handlers, upb_sink is never frozen, immutable, or +** thread-safe. You can create as many of them as you want, but each one may +** only be used in a single thread at a time. +** +** If we compare with class-based OOP, a you can think of a upb_def as an +** abstract base class, a upb_handlers as a concrete derived class, and a +** upb_sink as an object (class instance). +*/ + +#ifndef UPB_SINK_H +#define UPB_SINK_H + + +#ifdef __cplusplus +namespace upb { +class BufferSource; +class BytesSink; +class Sink; +} +#endif + +UPB_DECLARE_TYPE(upb::BufferSource, upb_bufsrc) +UPB_DECLARE_TYPE(upb::BytesSink, upb_bytessink) +UPB_DECLARE_TYPE(upb::Sink, upb_sink) + +#ifdef __cplusplus + +/* A upb::Sink is an object that binds a upb::Handlers object to some runtime + * state. It represents an endpoint to which data can be sent. + * + * TODO(haberman): right now all of these functions take selectors. Should they + * take selectorbase instead? + * + * ie. instead of calling: + * sink->StartString(FOO_FIELD_START_STRING, ...) + * a selector base would let you say: + * sink->StartString(FOO_FIELD, ...) + * + * This would make call sites a little nicer and require emitting fewer selector + * definitions in .h files. + * + * But the current scheme has the benefit that you can retrieve a function + * pointer for any handler with handlers->GetHandler(selector), without having + * to have a separate GetHandler() function for each handler type. The JIT + * compiler uses this. To accommodate we'd have to expose a separate + * GetHandler() for every handler type. + * + * Also to ponder: selectors right now are independent of a specific Handlers + * instance. In other words, they allocate a number to every possible handler + * that *could* be registered, without knowing anything about what handlers + * *are* registered. That means that using selectors as table offsets prohibits + * us from compacting the handler table at Freeze() time. If the table is very + * sparse, this could be wasteful. + * + * Having another selector-like thing that is specific to a Handlers instance + * would allow this compacting, but then it would be impossible to write code + * ahead-of-time that can be bound to any Handlers instance at runtime. For + * example, a .proto file parser written as straight C will not know what + * Handlers it will be bound to, so when it calls sink->StartString() what + * selector will it pass? It needs a selector like we have today, that is + * independent of any particular upb::Handlers. + * + * Is there a way then to allow Handlers table compaction? */ +class upb::Sink { + public: + /* Constructor with no initialization; must be Reset() before use. */ + Sink() {} + + /* Constructs a new sink for the given frozen handlers and closure. + * + * TODO: once the Handlers know the expected closure type, verify that T + * matches it. */ + template Sink(const Handlers* handlers, T* closure); + + /* Resets the value of the sink. */ + template void Reset(const Handlers* handlers, T* closure); + + /* Returns the top-level object that is bound to this sink. + * + * TODO: once the Handlers know the expected closure type, verify that T + * matches it. */ + template T* GetObject() const; + + /* Functions for pushing data into the sink. + * + * These return false if processing should stop (either due to error or just + * to suspend). + * + * These may not be called from within one of the same sink's handlers (in + * other words, handlers are not re-entrant). */ + + /* Should be called at the start and end of every message; both the top-level + * message and submessages. This means that submessages should use the + * following sequence: + * sink->StartSubMessage(startsubmsg_selector); + * sink->StartMessage(); + * // ... + * sink->EndMessage(&status); + * sink->EndSubMessage(endsubmsg_selector); */ + bool StartMessage(); + bool EndMessage(Status* status); + + /* Putting of individual values. These work for both repeated and + * non-repeated fields, but for repeated fields you must wrap them in + * calls to StartSequence()/EndSequence(). */ + bool PutInt32(Handlers::Selector s, int32_t val); + bool PutInt64(Handlers::Selector s, int64_t val); + bool PutUInt32(Handlers::Selector s, uint32_t val); + bool PutUInt64(Handlers::Selector s, uint64_t val); + bool PutFloat(Handlers::Selector s, float val); + bool PutDouble(Handlers::Selector s, double val); + bool PutBool(Handlers::Selector s, bool val); + + /* Putting of string/bytes values. Each string can consist of zero or more + * non-contiguous buffers of data. + * + * For StartString(), the function will write a sink for the string to "sub." + * The sub-sink must be used for any/all PutStringBuffer() calls. */ + bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub); + size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len, + const BufferHandle *handle); + bool EndString(Handlers::Selector s); + + /* For submessage fields. + * + * For StartSubMessage(), the function will write a sink for the string to + * "sub." The sub-sink must be used for any/all handlers called within the + * submessage. */ + bool StartSubMessage(Handlers::Selector s, Sink* sub); + bool EndSubMessage(Handlers::Selector s); + + /* For repeated fields of any type, the sequence of values must be wrapped in + * these calls. + * + * For StartSequence(), the function will write a sink for the string to + * "sub." The sub-sink must be used for any/all handlers called within the + * sequence. */ + bool StartSequence(Handlers::Selector s, Sink* sub); + bool EndSequence(Handlers::Selector s); + + /* Copy and assign specifically allowed. + * We don't even bother making these members private because so many + * functions need them and this is mainly just a dumb data container anyway. + */ +#else +struct upb_sink { +#endif + const upb_handlers *handlers; + void *closure; +}; + +#ifdef __cplusplus +class upb::BytesSink { + public: + BytesSink() {} + + /* Constructs a new sink for the given frozen handlers and closure. + * + * TODO(haberman): once the Handlers know the expected closure type, verify + * that T matches it. */ + template BytesSink(const BytesHandler* handler, T* closure); + + /* Resets the value of the sink. */ + template void Reset(const BytesHandler* handler, T* closure); + + bool Start(size_t size_hint, void **subc); + size_t PutBuffer(void *subc, const char *buf, size_t len, + const BufferHandle *handle); + bool End(); +#else +struct upb_bytessink { +#endif + const upb_byteshandler *handler; + void *closure; +}; + +#ifdef __cplusplus + +/* A class for pushing a flat buffer of data to a BytesSink. + * You can construct an instance of this to get a resumable source, + * or just call the static PutBuffer() to do a non-resumable push all in one + * go. */ +class upb::BufferSource { + public: + BufferSource(); + BufferSource(const char* buf, size_t len, BytesSink* sink); + + /* Returns true if the entire buffer was pushed successfully. Otherwise the + * next call to PutNext() will resume where the previous one left off. + * TODO(haberman): implement this. */ + bool PutNext(); + + /* A static version; with this version is it not possible to resume in the + * case of failure or a partially-consumed buffer. */ + static bool PutBuffer(const char* buf, size_t len, BytesSink* sink); + + template static bool PutBuffer(const T& str, BytesSink* sink) { + return PutBuffer(str.c_str(), str.size(), sink); + } +#else +struct upb_bufsrc { + char dummy; +#endif +}; + +UPB_BEGIN_EXTERN_C + +/* Inline definitions. */ + +UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h, + void *closure) { + s->handler = h; + s->closure = closure; +} + +UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint, + void **subc) { + typedef upb_startstr_handlerfunc func; + func *start; + *subc = s->closure; + if (!s->handler) return true; + start = (func *)s->handler->table[UPB_STARTSTR_SELECTOR].func; + + if (!start) return true; + *subc = start(s->closure, upb_handlerattr_handlerdata( + &s->handler->table[UPB_STARTSTR_SELECTOR].attr), + size_hint); + return *subc != NULL; +} + +UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc, + const char *buf, size_t size, + const upb_bufhandle* handle) { + typedef upb_string_handlerfunc func; + func *putbuf; + if (!s->handler) return true; + putbuf = (func *)s->handler->table[UPB_STRING_SELECTOR].func; + + if (!putbuf) return true; + return putbuf(subc, upb_handlerattr_handlerdata( + &s->handler->table[UPB_STRING_SELECTOR].attr), + buf, size, handle); +} + +UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) { + typedef upb_endfield_handlerfunc func; + func *end; + if (!s->handler) return true; + end = (func *)s->handler->table[UPB_ENDSTR_SELECTOR].func; + + if (!end) return true; + return end(s->closure, + upb_handlerattr_handlerdata( + &s->handler->table[UPB_ENDSTR_SELECTOR].attr)); +} + +UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len, + upb_bytessink *sink) { + void *subc; + bool ret; + upb_bufhandle handle; + upb_bufhandle_init(&handle); + upb_bufhandle_setbuf(&handle, buf, 0); + ret = upb_bytessink_start(sink, len, &subc); + if (ret && len != 0) { + ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) >= len); + } + if (ret) { + ret = upb_bytessink_end(sink); + } + upb_bufhandle_uninit(&handle); + return ret; +} + +#define PUTVAL(type, ctype) \ + UPB_INLINE bool upb_sink_put##type(upb_sink *s, upb_selector_t sel, \ + ctype val) { \ + typedef upb_##type##_handlerfunc functype; \ + functype *func; \ + const void *hd; \ + if (!s->handlers) return true; \ + func = (functype *)upb_handlers_gethandler(s->handlers, sel); \ + if (!func) return true; \ + hd = upb_handlers_gethandlerdata(s->handlers, sel); \ + return func(s->closure, hd, val); \ + } + +PUTVAL(int32, int32_t) +PUTVAL(int64, int64_t) +PUTVAL(uint32, uint32_t) +PUTVAL(uint64, uint64_t) +PUTVAL(float, float) +PUTVAL(double, double) +PUTVAL(bool, bool) +#undef PUTVAL + +UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) { + s->handlers = h; + s->closure = c; +} + +UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, + const char *buf, size_t n, + const upb_bufhandle *handle) { + typedef upb_string_handlerfunc func; + func *handler; + const void *hd; + if (!s->handlers) return n; + handler = (func *)upb_handlers_gethandler(s->handlers, sel); + + if (!handler) return n; + hd = upb_handlers_gethandlerdata(s->handlers, sel); + return handler(s->closure, hd, buf, n, handle); +} + +UPB_INLINE bool upb_sink_startmsg(upb_sink *s) { + typedef upb_startmsg_handlerfunc func; + func *startmsg; + const void *hd; + if (!s->handlers) return true; + startmsg = (func*)upb_handlers_gethandler(s->handlers, UPB_STARTMSG_SELECTOR); + + if (!startmsg) return true; + hd = upb_handlers_gethandlerdata(s->handlers, UPB_STARTMSG_SELECTOR); + return startmsg(s->closure, hd); +} + +UPB_INLINE bool upb_sink_endmsg(upb_sink *s, upb_status *status) { + typedef upb_endmsg_handlerfunc func; + func *endmsg; + const void *hd; + if (!s->handlers) return true; + endmsg = (func *)upb_handlers_gethandler(s->handlers, UPB_ENDMSG_SELECTOR); + + if (!endmsg) return true; + hd = upb_handlers_gethandlerdata(s->handlers, UPB_ENDMSG_SELECTOR); + return endmsg(s->closure, hd, status); +} + +UPB_INLINE bool upb_sink_startseq(upb_sink *s, upb_selector_t sel, + upb_sink *sub) { + typedef upb_startfield_handlerfunc func; + func *startseq; + const void *hd; + sub->closure = s->closure; + sub->handlers = s->handlers; + if (!s->handlers) return true; + startseq = (func*)upb_handlers_gethandler(s->handlers, sel); + + if (!startseq) return true; + hd = upb_handlers_gethandlerdata(s->handlers, sel); + sub->closure = startseq(s->closure, hd); + return sub->closure ? true : false; +} + +UPB_INLINE bool upb_sink_endseq(upb_sink *s, upb_selector_t sel) { + typedef upb_endfield_handlerfunc func; + func *endseq; + const void *hd; + if (!s->handlers) return true; + endseq = (func*)upb_handlers_gethandler(s->handlers, sel); + + if (!endseq) return true; + hd = upb_handlers_gethandlerdata(s->handlers, sel); + return endseq(s->closure, hd); +} + +UPB_INLINE bool upb_sink_startstr(upb_sink *s, upb_selector_t sel, + size_t size_hint, upb_sink *sub) { + typedef upb_startstr_handlerfunc func; + func *startstr; + const void *hd; + sub->closure = s->closure; + sub->handlers = s->handlers; + if (!s->handlers) return true; + startstr = (func*)upb_handlers_gethandler(s->handlers, sel); + + if (!startstr) return true; + hd = upb_handlers_gethandlerdata(s->handlers, sel); + sub->closure = startstr(s->closure, hd, size_hint); + return sub->closure ? true : false; +} + +UPB_INLINE bool upb_sink_endstr(upb_sink *s, upb_selector_t sel) { + typedef upb_endfield_handlerfunc func; + func *endstr; + const void *hd; + if (!s->handlers) return true; + endstr = (func*)upb_handlers_gethandler(s->handlers, sel); + + if (!endstr) return true; + hd = upb_handlers_gethandlerdata(s->handlers, sel); + return endstr(s->closure, hd); +} + +UPB_INLINE bool upb_sink_startsubmsg(upb_sink *s, upb_selector_t sel, + upb_sink *sub) { + typedef upb_startfield_handlerfunc func; + func *startsubmsg; + const void *hd; + sub->closure = s->closure; + if (!s->handlers) { + sub->handlers = NULL; + return true; + } + sub->handlers = upb_handlers_getsubhandlers_sel(s->handlers, sel); + startsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel); + + if (!startsubmsg) return true; + hd = upb_handlers_gethandlerdata(s->handlers, sel); + sub->closure = startsubmsg(s->closure, hd); + return sub->closure ? true : false; +} + +UPB_INLINE bool upb_sink_endsubmsg(upb_sink *s, upb_selector_t sel) { + typedef upb_endfield_handlerfunc func; + func *endsubmsg; + const void *hd; + if (!s->handlers) return true; + endsubmsg = (func*)upb_handlers_gethandler(s->handlers, sel); + + if (!endsubmsg) return s->closure; + hd = upb_handlers_gethandlerdata(s->handlers, sel); + return endsubmsg(s->closure, hd); +} + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upb { + +template Sink::Sink(const Handlers* handlers, T* closure) { + upb_sink_reset(this, handlers, closure); +} +template +inline void Sink::Reset(const Handlers* handlers, T* closure) { + upb_sink_reset(this, handlers, closure); +} +inline bool Sink::StartMessage() { + return upb_sink_startmsg(this); +} +inline bool Sink::EndMessage(Status* status) { + return upb_sink_endmsg(this, status); +} +inline bool Sink::PutInt32(Handlers::Selector sel, int32_t val) { + return upb_sink_putint32(this, sel, val); +} +inline bool Sink::PutInt64(Handlers::Selector sel, int64_t val) { + return upb_sink_putint64(this, sel, val); +} +inline bool Sink::PutUInt32(Handlers::Selector sel, uint32_t val) { + return upb_sink_putuint32(this, sel, val); +} +inline bool Sink::PutUInt64(Handlers::Selector sel, uint64_t val) { + return upb_sink_putuint64(this, sel, val); +} +inline bool Sink::PutFloat(Handlers::Selector sel, float val) { + return upb_sink_putfloat(this, sel, val); +} +inline bool Sink::PutDouble(Handlers::Selector sel, double val) { + return upb_sink_putdouble(this, sel, val); +} +inline bool Sink::PutBool(Handlers::Selector sel, bool val) { + return upb_sink_putbool(this, sel, val); +} +inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint, + Sink *sub) { + return upb_sink_startstr(this, sel, size_hint, sub); +} +inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf, + size_t len, const BufferHandle* handle) { + return upb_sink_putstring(this, sel, buf, len, handle); +} +inline bool Sink::EndString(Handlers::Selector sel) { + return upb_sink_endstr(this, sel); +} +inline bool Sink::StartSubMessage(Handlers::Selector sel, Sink* sub) { + return upb_sink_startsubmsg(this, sel, sub); +} +inline bool Sink::EndSubMessage(Handlers::Selector sel) { + return upb_sink_endsubmsg(this, sel); +} +inline bool Sink::StartSequence(Handlers::Selector sel, Sink* sub) { + return upb_sink_startseq(this, sel, sub); +} +inline bool Sink::EndSequence(Handlers::Selector sel) { + return upb_sink_endseq(this, sel); +} + +template +BytesSink::BytesSink(const BytesHandler* handler, T* closure) { + Reset(handler, closure); +} + +template +void BytesSink::Reset(const BytesHandler *handler, T *closure) { + upb_bytessink_reset(this, handler, closure); +} +inline bool BytesSink::Start(size_t size_hint, void **subc) { + return upb_bytessink_start(this, size_hint, subc); +} +inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len, + const BufferHandle *handle) { + return upb_bytessink_putbuf(this, subc, buf, len, handle); +} +inline bool BytesSink::End() { + return upb_bytessink_end(this); +} + +inline bool BufferSource::PutBuffer(const char *buf, size_t len, + BytesSink *sink) { + return upb_bufsrc_putbuf(buf, len, sink); +} + +} /* namespace upb */ +#endif + +#endif +/* +** For handlers that do very tiny, very simple operations, the function call +** overhead of calling a handler can be significant. This file allows the +** user to define handlers that do something very simple like store the value +** to memory and/or set a hasbit. JIT compilers can then special-case these +** handlers and emit specialized code for them instead of actually calling the +** handler. +** +** The functionality is very simple/limited right now but may expand to be able +** to call another function. +*/ + +#ifndef UPB_SHIM_H +#define UPB_SHIM_H + + +typedef struct { + size_t offset; + int32_t hasbit; +} upb_shim_data; + +#ifdef __cplusplus + +namespace upb { + +struct Shim { + typedef upb_shim_data Data; + + /* Sets a handler for the given field that writes the value to the given + * offset and, if hasbit >= 0, sets a bit at the given bit offset. Returns + * true if the handler was set successfully. */ + static bool Set(Handlers *h, const FieldDef *f, size_t ofs, int32_t hasbit); + + /* If this handler is a shim, returns the corresponding upb::Shim::Data and + * stores the type in "type". Otherwise returns NULL. */ + static const Data* GetData(const Handlers* h, Handlers::Selector s, + FieldDef::Type* type); +}; + +} /* namespace upb */ + +#endif + +UPB_BEGIN_EXTERN_C + +/* C API. */ +bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, + int32_t hasbit); +const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s, + upb_fieldtype_t *type); + +UPB_END_EXTERN_C + +#ifdef __cplusplus +/* C++ Wrappers. */ +namespace upb { +inline bool Shim::Set(Handlers* h, const FieldDef* f, size_t ofs, + int32_t hasbit) { + return upb_shim_set(h, f, ofs, hasbit); +} +inline const Shim::Data* Shim::GetData(const Handlers* h, Handlers::Selector s, + FieldDef::Type* type) { + return upb_shim_getdata(h, s, type); +} +} /* namespace upb */ +#endif + +#endif /* UPB_SHIM_H */ +/* +** upb::SymbolTable (upb_symtab) +** +** A symtab (symbol table) stores a name->def map of upb_defs. Clients could +** always create such tables themselves, but upb_symtab has logic for resolving +** symbolic references, and in particular, for keeping a whole set of consistent +** defs when replacing some subset of those defs. This logic is nontrivial. +** +** This is a mixed C/C++ interface that offers a full API to both languages. +** See the top-level README for more information. +*/ + +#ifndef UPB_SYMTAB_H_ +#define UPB_SYMTAB_H_ + + +#ifdef __cplusplus +#include +namespace upb { class SymbolTable; } +#endif + +UPB_DECLARE_DERIVED_TYPE(upb::SymbolTable, upb::RefCounted, + upb_symtab, upb_refcounted) + +typedef struct { + UPB_PRIVATE_FOR_CPP + upb_strtable_iter iter; + upb_deftype_t type; +} upb_symtab_iter; + +#ifdef __cplusplus + +/* Non-const methods in upb::SymbolTable are NOT thread-safe. */ +class upb::SymbolTable { + public: + /* Returns a new symbol table with a single ref owned by "owner." + * Returns NULL if memory allocation failed. */ + static reffed_ptr New(); + + /* Include RefCounted base methods. */ + UPB_REFCOUNTED_CPPMETHODS + + /* For all lookup functions, the returned pointer is not owned by the + * caller; it may be invalidated by any non-const call or unref of the + * SymbolTable! To protect against this, take a ref if desired. */ + + /* Freezes the symbol table: prevents further modification of it. + * After the Freeze() operation is successful, the SymbolTable must only be + * accessed via a const pointer. + * + * Unlike with upb::MessageDef/upb::EnumDef/etc, freezing a SymbolTable is not + * a necessary step in using a SymbolTable. If you have no need for it to be + * immutable, there is no need to freeze it ever. However sometimes it is + * useful, and SymbolTables that are statically compiled into the binary are + * always frozen by nature. */ + void Freeze(); + + /* Resolves the given symbol using the rules described in descriptor.proto, + * namely: + * + * If the name starts with a '.', it is fully-qualified. Otherwise, + * C++-like scoping rules are used to find the type (i.e. first the nested + * types within this message are searched, then within the parent, on up + * to the root namespace). + * + * If not found, returns NULL. */ + const Def* Resolve(const char* base, const char* sym) const; + + /* Finds an entry in the symbol table with this exact name. If not found, + * returns NULL. */ + const Def* Lookup(const char *sym) const; + const MessageDef* LookupMessage(const char *sym) const; + const EnumDef* LookupEnum(const char *sym) const; + + /* TODO: introduce a C++ iterator, but make it nice and templated so that if + * you ask for an iterator of MessageDef the iterated elements are strongly + * typed as MessageDef*. */ + + /* Adds the given mutable defs to the symtab, resolving all symbols + * (including enum default values) and finalizing the defs. Only one def per + * name may be in the list, but defs can replace existing defs in the symtab. + * All defs must have a name -- anonymous defs are not allowed. Anonymous + * defs can still be frozen by calling upb_def_freeze() directly. + * + * Any existing defs that can reach defs that are being replaced will + * themselves be replaced also, so that the resulting set of defs is fully + * consistent. + * + * This logic implemented in this method is a convenience; ultimately it + * calls some combination of upb_fielddef_setsubdef(), upb_def_dup(), and + * upb_freeze(), any of which the client could call themself. However, since + * the logic for doing so is nontrivial, we provide it here. + * + * The entire operation either succeeds or fails. If the operation fails, + * the symtab is unchanged, false is returned, and status indicates the + * error. The caller passes a ref on all defs to the symtab (even if the + * operation fails). + * + * TODO(haberman): currently failure will leave the symtab unchanged, but may + * leave the defs themselves partially resolved. Does this matter? If so we + * could do a prepass that ensures that all symbols are resolvable and bail + * if not, so we don't mutate anything until we know the operation will + * succeed. + * + * TODO(haberman): since the defs must be mutable, refining a frozen def + * requires making mutable copies of the entire tree. This is wasteful if + * only a few messages are changing. We may want to add a way of adding a + * tree of frozen defs to the symtab (perhaps an alternate constructor where + * you pass the root of the tree?) */ + bool Add(Def*const* defs, int n, void* ref_donor, upb_status* status); + + bool Add(const std::vector& defs, void *owner, Status* status) { + return Add((Def*const*)&defs[0], defs.size(), owner, status); + } + + private: + UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable) +}; + +#endif /* __cplusplus */ + +UPB_BEGIN_EXTERN_C + +/* Native C API. */ + +/* Include refcounted methods like upb_symtab_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_symtab, upb_symtab_upcast) + +upb_symtab *upb_symtab_new(const void *owner); +void upb_symtab_freeze(upb_symtab *s); +const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, + const char *sym); +const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym); +const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym); +const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym); +bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, + upb_status *status); + +/* upb_symtab_iter i; + * for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i); + * upb_symtab_next(&i)) { + * const upb_def *def = upb_symtab_iter_def(&i); + * // ... + * } + * + * For C we don't have separate iterators for const and non-const. + * It is the caller's responsibility to cast the upb_fielddef* to + * const if the upb_msgdef* is const. */ +void upb_symtab_begin(upb_symtab_iter *iter, const upb_symtab *s, + upb_deftype_t type); +void upb_symtab_next(upb_symtab_iter *iter); +bool upb_symtab_done(const upb_symtab_iter *iter); +const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter); + +UPB_END_EXTERN_C + +#ifdef __cplusplus +/* C++ inline wrappers. */ +namespace upb { +inline reffed_ptr SymbolTable::New() { + upb_symtab *s = upb_symtab_new(&s); + return reffed_ptr(s, &s); +} + +inline void SymbolTable::Freeze() { + return upb_symtab_freeze(this); +} +inline const Def *SymbolTable::Resolve(const char *base, + const char *sym) const { + return upb_symtab_resolve(this, base, sym); +} +inline const Def* SymbolTable::Lookup(const char *sym) const { + return upb_symtab_lookup(this, sym); +} +inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const { + return upb_symtab_lookupmsg(this, sym); +} +inline bool SymbolTable::Add( + Def*const* defs, int n, void* ref_donor, upb_status* status) { + return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status); +} +} /* namespace upb */ +#endif + +#endif /* UPB_SYMTAB_H_ */ +/* +** upb::descriptor::Reader (upb_descreader) +** +** Provides a way of building upb::Defs from data in descriptor.proto format. +*/ + +#ifndef UPB_DESCRIPTOR_H +#define UPB_DESCRIPTOR_H + + +#ifdef __cplusplus +namespace upb { +namespace descriptor { +class Reader; +} /* namespace descriptor */ +} /* namespace upb */ +#endif + +UPB_DECLARE_TYPE(upb::descriptor::Reader, upb_descreader) + +#ifdef __cplusplus + +/* Class that receives descriptor data according to the descriptor.proto schema + * and use it to build upb::Defs corresponding to that schema. */ +class upb::descriptor::Reader { + public: + /* These handlers must have come from NewHandlers() and must outlive the + * Reader. + * + * TODO: generate the handlers statically (like we do with the + * descriptor.proto defs) so that there is no need to pass this parameter (or + * to build/memory-manage the handlers at runtime at all). Unfortunately this + * is a bit tricky to implement for Handlers, but necessary to simplify this + * interface. */ + static Reader* Create(Environment* env, const Handlers* handlers); + + /* The reader's input; this is where descriptor.proto data should be sent. */ + Sink* input(); + + /* Returns an array of all defs that have been parsed, and transfers ownership + * of them to "owner". The number of defs is stored in *n. Ownership of the + * returned array is retained and is invalidated by any other call into + * Reader. + * + * These defs are not frozen or resolved; they are ready to be added to a + * symtab. */ + upb::Def** GetDefs(void* owner, int* n); + + /* Builds and returns handlers for the reader, owned by "owner." */ + static Handlers* NewHandlers(const void* owner); + + private: + UPB_DISALLOW_POD_OPS(Reader, upb::descriptor::Reader) +}; + +#endif + +UPB_BEGIN_EXTERN_C + +/* C API. */ +upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h); +upb_sink *upb_descreader_input(upb_descreader *r); +upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n); +const upb_handlers *upb_descreader_newhandlers(const void *owner); + +UPB_END_EXTERN_C + +#ifdef __cplusplus +/* C++ implementation details. ************************************************/ +namespace upb { +namespace descriptor { +inline Reader* Reader::Create(Environment* e, const Handlers *h) { + return upb_descreader_create(e, h); +} +inline Sink* Reader::input() { return upb_descreader_input(this); } +inline upb::Def** Reader::GetDefs(void* owner, int* n) { + return upb_descreader_getdefs(this, owner, n); +} +} /* namespace descriptor */ +} /* namespace upb */ +#endif + +#endif /* UPB_DESCRIPTOR_H */ +/* This file contains accessors for a set of compiled-in defs. + * Note that unlike Google's protobuf, it does *not* define + * generated classes or any other kind of data structure for + * actually storing protobufs. It only contains *defs* which + * let you reflect over a protobuf *schema*. + */ +/* This file was generated by upbc (the upb compiler). + * Do not edit -- your changes will be discarded when the file is + * regenerated. */ + +#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_ +#define GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_ + + +#ifdef __cplusplus +UPB_BEGIN_EXTERN_C +#endif + +/* Enums */ + +typedef enum { + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_OPTIONAL = 1, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED = 2, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED = 3 +} google_protobuf_FieldDescriptorProto_Label; + +typedef enum { + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_DOUBLE = 1, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FLOAT = 2, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT64 = 3, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT64 = 4, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 = 5, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED64 = 6, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED32 = 7, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BOOL = 8, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_STRING = 9, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_GROUP = 10, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_MESSAGE = 11, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BYTES = 12, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT32 = 13, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ENUM = 14, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED32 = 15, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED64 = 16, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT32 = 17, + GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT64 = 18 +} google_protobuf_FieldDescriptorProto_Type; + +typedef enum { + GOOGLE_PROTOBUF_FIELDOPTIONS_STRING = 0, + GOOGLE_PROTOBUF_FIELDOPTIONS_CORD = 1, + GOOGLE_PROTOBUF_FIELDOPTIONS_STRING_PIECE = 2 +} google_protobuf_FieldOptions_CType; + +typedef enum { + GOOGLE_PROTOBUF_FILEOPTIONS_SPEED = 1, + GOOGLE_PROTOBUF_FILEOPTIONS_CODE_SIZE = 2, + GOOGLE_PROTOBUF_FILEOPTIONS_LITE_RUNTIME = 3 +} google_protobuf_FileOptions_OptimizeMode; + +/* Selectors */ + +/* google.protobuf.DescriptorProto */ +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 3 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 4 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 5 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 6 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 8 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 9 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 10 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 11 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 12 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 13 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 14 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 15 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 16 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 17 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 18 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 19 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 20 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 21 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 22 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 23 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 24 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 25 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 26 + +/* google.protobuf.DescriptorProto.ExtensionRange */ +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2 +#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3 + +/* google.protobuf.EnumDescriptorProto */ +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 4 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 5 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 6 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 8 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 9 +#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 10 + +/* google.protobuf.EnumOptions */ +#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_ALLOW_ALIAS_BOOL 6 + +/* google.protobuf.EnumValueDescriptorProto */ +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 4 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 5 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 6 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 7 + +/* google.protobuf.EnumValueOptions */ +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 + +/* google.protobuf.FieldDescriptorProto */ +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 4 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 5 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 6 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 7 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 8 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 9 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 10 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 11 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 12 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 13 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 14 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 15 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 16 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 17 +#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 18 + +/* google.protobuf.FieldOptions */ +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 6 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 7 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 8 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_LAZY_BOOL 9 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STRING 10 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_STARTSTR 11 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_EXPERIMENTAL_MAP_KEY_ENDSTR 12 +#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_WEAK_BOOL 13 + +/* google.protobuf.FileDescriptorProto */ +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 3 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 4 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 5 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 7 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 8 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 9 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 10 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 11 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 12 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 13 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 14 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 15 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 16 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 17 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 18 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 19 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 20 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 21 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 22 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 23 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 24 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 25 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 26 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 27 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 28 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 29 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 30 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 31 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 32 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_STARTSEQ 33 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_ENDSEQ 34 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_INT32 35 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_STARTSEQ 36 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_ENDSEQ 37 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_INT32 38 + +/* google.protobuf.FileDescriptorSet */ +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5 + +/* google.protobuf.FileOptions */ +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 6 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 7 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 8 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 9 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 10 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 11 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 12 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 13 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STRING 14 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STARTSTR 15 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_ENDSTR 16 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 17 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 18 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 19 +#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 20 + +/* google.protobuf.MessageOptions */ +#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 +#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 6 +#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 7 + +/* google.protobuf.MethodDescriptorProto */ +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 4 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 5 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 6 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 7 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 8 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 9 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 10 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 11 +#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 12 + +/* google.protobuf.MethodOptions */ +#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 + +/* google.protobuf.ServiceDescriptorProto */ +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 4 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 5 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 6 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 8 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 9 +#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 10 + +/* google.protobuf.ServiceOptions */ +#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 + +/* google.protobuf.SourceCodeInfo */ +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5 + +/* google.protobuf.SourceCodeInfo.Location */ +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_STARTSEQ 2 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 3 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 4 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 5 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 6 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 7 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STRING 8 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STARTSTR 9 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_ENDSTR 10 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STRING 11 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STARTSTR 12 +#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_ENDSTR 13 + +/* google.protobuf.UninterpretedOption */ +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 2 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 3 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 4 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 6 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 7 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 8 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 9 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 10 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 11 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 12 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 13 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 14 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 15 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 16 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 17 + +/* google.protobuf.UninterpretedOption.NamePart */ +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4 +#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5 + +const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner); + +/* MessageDefs */ +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ExtensionRange"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumOptions(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumOptions"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueDescriptorProto"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueOptions"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldDescriptorProto"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldOptions(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldOptions"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorProto"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorSet"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileOptions(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileOptions"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MessageOptions(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MessageOptions"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodDescriptorProto"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodOptions(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodOptions"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceDescriptorProto"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceOptions(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceOptions"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo.Location"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption"); + assert(m); + return m; +} +UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart(const upb_symtab *s) { + const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption.NamePart"); + assert(m); + return m; +} + + +/* EnumDefs */ +UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label(const upb_symtab *s) { + const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Label"); + assert(e); + return e; +} +UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type(const upb_symtab *s) { + const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Type"); + assert(e); + return e; +} +UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType(const upb_symtab *s) { + const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldOptions.CType"); + assert(e); + return e; +} +UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode(const upb_symtab *s) { + const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FileOptions.OptimizeMode"); + assert(e); + return e; +} + +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension_range(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_field(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_nested_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 7); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_allow_alias(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueOptions(s), 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_default_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 7); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_extendee(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_label(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_ctype(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_experimental_map_key(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 9); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_lazy(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_packed(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_weak(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 7); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_message_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_public_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_service(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_source_code_info(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 9); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_weak_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 11); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_file(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorSet(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_cc_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 16); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_go_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 11); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 20); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 17); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_multiple_files(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_outer_classname(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_optimize_for(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 9); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_py_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 18); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_message_set_wire_format(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_input_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_output_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodOptions(s), 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_method(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceOptions(s), 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_path(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_span(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_location(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_aggregate_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_double_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_identifier_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_negative_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_positive_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_string_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 7); } + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upbdefs { +namespace google { +namespace protobuf { +namespace descriptor { +inline upb::reffed_ptr SymbolTable() { + const upb::SymbolTable* s = upbdefs_google_protobuf_descriptor(&s); + return upb::reffed_ptr(s, &s); +} +} /* namespace descriptor */ +} /* namespace protobuf */ +} /* namespace google */ + +#define RETURN_REFFED(type, func) \ + const type* obj = func(upbdefs::google::protobuf::descriptor::SymbolTable().get()); \ + return upb::reffed_ptr(obj); + +namespace google { +namespace protobuf { +namespace DescriptorProto { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto) } +inline upb::reffed_ptr enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_enum_type) } +inline upb::reffed_ptr extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension) } +inline upb::reffed_ptr extension_range() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension_range) } +inline upb::reffed_ptr field() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_field) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_name) } +inline upb::reffed_ptr nested_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_nested_type) } +inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_options) } +} /* namespace DescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace DescriptorProto { +namespace ExtensionRange { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange) } +inline upb::reffed_ptr end() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end) } +inline upb::reffed_ptr start() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start) } +} /* namespace ExtensionRange */ +} /* namespace DescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace EnumDescriptorProto { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumDescriptorProto) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_name) } +inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_options) } +inline upb::reffed_ptr value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_value) } +} /* namespace EnumDescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace EnumOptions { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumOptions) } +inline upb::reffed_ptr allow_alias() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_allow_alias) } +inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_uninterpreted_option) } +} /* namespace EnumOptions */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace EnumValueDescriptorProto { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueDescriptorProto) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_name) } +inline upb::reffed_ptr number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_number) } +inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_options) } +} /* namespace EnumValueDescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace EnumValueOptions { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueOptions) } +inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option) } +} /* namespace EnumValueOptions */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace FieldDescriptorProto { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldDescriptorProto) } +inline upb::reffed_ptr default_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_default_value) } +inline upb::reffed_ptr extendee() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_extendee) } +inline upb::reffed_ptr label() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_label) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_name) } +inline upb::reffed_ptr number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_number) } +inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_options) } +inline upb::reffed_ptr type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type) } +inline upb::reffed_ptr type_name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type_name) } +inline upb::reffed_ptr Label() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Label) } +inline upb::reffed_ptr Type() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Type) } +} /* namespace FieldDescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace FieldOptions { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldOptions) } +inline upb::reffed_ptr ctype() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_ctype) } +inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_deprecated) } +inline upb::reffed_ptr experimental_map_key() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_experimental_map_key) } +inline upb::reffed_ptr lazy() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_lazy) } +inline upb::reffed_ptr packed() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_packed) } +inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_uninterpreted_option) } +inline upb::reffed_ptr weak() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_weak) } +inline upb::reffed_ptr CType() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldOptions_CType) } +} /* namespace FieldOptions */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace FileDescriptorProto { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorProto) } +inline upb::reffed_ptr dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_dependency) } +inline upb::reffed_ptr enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_enum_type) } +inline upb::reffed_ptr extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_extension) } +inline upb::reffed_ptr message_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_message_type) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_name) } +inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_options) } +inline upb::reffed_ptr package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_package) } +inline upb::reffed_ptr public_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_public_dependency) } +inline upb::reffed_ptr service() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_service) } +inline upb::reffed_ptr source_code_info() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_source_code_info) } +inline upb::reffed_ptr weak_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_weak_dependency) } +} /* namespace FileDescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace FileDescriptorSet { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorSet) } +inline upb::reffed_ptr file() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorSet_file) } +} /* namespace FileDescriptorSet */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace FileOptions { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileOptions) } +inline upb::reffed_ptr cc_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_cc_generic_services) } +inline upb::reffed_ptr go_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_go_package) } +inline upb::reffed_ptr java_generate_equals_and_hash() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash) } +inline upb::reffed_ptr java_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generic_services) } +inline upb::reffed_ptr java_multiple_files() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_multiple_files) } +inline upb::reffed_ptr java_outer_classname() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_outer_classname) } +inline upb::reffed_ptr java_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_package) } +inline upb::reffed_ptr optimize_for() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_optimize_for) } +inline upb::reffed_ptr py_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_py_generic_services) } +inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_uninterpreted_option) } +inline upb::reffed_ptr OptimizeMode() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FileOptions_OptimizeMode) } +} /* namespace FileOptions */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace MessageOptions { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MessageOptions) } +inline upb::reffed_ptr message_set_wire_format() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_message_set_wire_format) } +inline upb::reffed_ptr no_standard_descriptor_accessor() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor) } +inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_uninterpreted_option) } +} /* namespace MessageOptions */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace MethodDescriptorProto { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodDescriptorProto) } +inline upb::reffed_ptr input_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_input_type) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_name) } +inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_options) } +inline upb::reffed_ptr output_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_output_type) } +} /* namespace MethodDescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace MethodOptions { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodOptions) } +inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodOptions_uninterpreted_option) } +} /* namespace MethodOptions */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace ServiceDescriptorProto { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceDescriptorProto) } +inline upb::reffed_ptr method() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_method) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_name) } +inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_options) } +} /* namespace ServiceDescriptorProto */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace ServiceOptions { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceOptions) } +inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceOptions_uninterpreted_option) } +} /* namespace ServiceOptions */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace SourceCodeInfo { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo) } +inline upb::reffed_ptr location() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_location) } +} /* namespace SourceCodeInfo */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace SourceCodeInfo { +namespace Location { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo_Location) } +inline upb::reffed_ptr leading_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments) } +inline upb::reffed_ptr path() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_path) } +inline upb::reffed_ptr span() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_span) } +inline upb::reffed_ptr trailing_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments) } +} /* namespace Location */ +} /* namespace SourceCodeInfo */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace UninterpretedOption { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption) } +inline upb::reffed_ptr aggregate_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_aggregate_value) } +inline upb::reffed_ptr double_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_double_value) } +inline upb::reffed_ptr identifier_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_identifier_value) } +inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_name) } +inline upb::reffed_ptr negative_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_negative_int_value) } +inline upb::reffed_ptr positive_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_positive_int_value) } +inline upb::reffed_ptr string_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_string_value) } +} /* namespace UninterpretedOption */ +} /* namespace protobuf */ +} /* namespace google */ + +namespace google { +namespace protobuf { +namespace UninterpretedOption { +namespace NamePart { +inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption_NamePart) } +inline upb::reffed_ptr is_extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension) } +inline upb::reffed_ptr name_part() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part) } +} /* namespace NamePart */ +} /* namespace UninterpretedOption */ +} /* namespace protobuf */ +} /* namespace google */ + +} /* namespace upbdefs */ + + +#undef RETURN_REFFED +#endif /* __cplusplus */ + +#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_ */ +/* +** Internal-only definitions for the decoder. +*/ + +#ifndef UPB_DECODER_INT_H_ +#define UPB_DECODER_INT_H_ + +#include +/* +** upb::pb::Decoder +** +** A high performance, streaming, resumable decoder for the binary protobuf +** format. +** +** This interface works the same regardless of what decoder backend is being +** used. A client of this class does not need to know whether decoding is using +** a JITted decoder (DynASM, LLVM, etc) or an interpreted decoder. By default, +** it will always use the fastest available decoder. However, you can call +** set_allow_jit(false) to disable any JIT decoder that might be available. +** This is primarily useful for testing purposes. +*/ + +#ifndef UPB_DECODER_H_ +#define UPB_DECODER_H_ + + +#ifdef __cplusplus +namespace upb { +namespace pb { +class CodeCache; +class Decoder; +class DecoderMethod; +class DecoderMethodOptions; +} /* namespace pb */ +} /* namespace upb */ +#endif + +UPB_DECLARE_TYPE(upb::pb::CodeCache, upb_pbcodecache) +UPB_DECLARE_TYPE(upb::pb::Decoder, upb_pbdecoder) +UPB_DECLARE_TYPE(upb::pb::DecoderMethodOptions, upb_pbdecodermethodopts) + +UPB_DECLARE_DERIVED_TYPE(upb::pb::DecoderMethod, upb::RefCounted, + upb_pbdecodermethod, upb_refcounted) + +#ifdef __cplusplus + +/* The parameters one uses to construct a DecoderMethod. + * TODO(haberman): move allowjit here? Seems more convenient for users. + * TODO(haberman): move this to be heap allocated for ABI stability. */ +class upb::pb::DecoderMethodOptions { + public: + /* Parameter represents the destination handlers that this method will push + * to. */ + explicit DecoderMethodOptions(const Handlers* dest_handlers); + + /* Should the decoder push submessages to lazy handlers for fields that have + * them? The caller should set this iff the lazy handlers expect data that is + * in protobuf binary format and the caller wishes to lazy parse it. */ + void set_lazy(bool lazy); +#else +struct upb_pbdecodermethodopts { +#endif + const upb_handlers *handlers; + bool lazy; +}; + +#ifdef __cplusplus + +/* Represents the code to parse a protobuf according to a destination + * Handlers. */ +class upb::pb::DecoderMethod { + public: + /* Include base methods from upb::ReferenceCounted. */ + UPB_REFCOUNTED_CPPMETHODS + + /* The destination handlers that are statically bound to this method. + * This method is only capable of outputting to a sink that uses these + * handlers. */ + const Handlers* dest_handlers() const; + + /* The input handlers for this decoder method. */ + const BytesHandler* input_handler() const; + + /* Whether this method is native. */ + bool is_native() const; + + /* Convenience method for generating a DecoderMethod without explicitly + * creating a CodeCache. */ + static reffed_ptr New(const DecoderMethodOptions& opts); + + private: + UPB_DISALLOW_POD_OPS(DecoderMethod, upb::pb::DecoderMethod) +}; + +#endif + +/* Preallocation hint: decoder won't allocate more bytes than this when first + * constructed. This hint may be an overestimate for some build configurations. + * But if the decoder library is upgraded without recompiling the application, + * it may be an underestimate. */ +#define UPB_PB_DECODER_SIZE 4408 + +#ifdef __cplusplus + +/* A Decoder receives binary protobuf data on its input sink and pushes the + * decoded data to its output sink. */ +class upb::pb::Decoder { + public: + /* Constructs a decoder instance for the given method, which must outlive this + * decoder. Any errors during parsing will be set on the given status, which + * must also outlive this decoder. + * + * The sink must match the given method. */ + static Decoder* Create(Environment* env, const DecoderMethod* method, + Sink* output); + + /* Returns the DecoderMethod this decoder is parsing from. */ + const DecoderMethod* method() const; + + /* The sink on which this decoder receives input. */ + BytesSink* input(); + + /* Returns number of bytes successfully parsed. + * + * This can be useful for determining the stream position where an error + * occurred. + * + * This value may not be up-to-date when called from inside a parsing + * callback. */ + uint64_t BytesParsed() const; + + /* Gets/sets the parsing nexting limit. If the total number of nested + * submessages and repeated fields hits this limit, parsing will fail. This + * is a resource limit that controls the amount of memory used by the parsing + * stack. + * + * Setting the limit will fail if the parser is currently suspended at a depth + * greater than this, or if memory allocation of the stack fails. */ + size_t max_nesting() const; + bool set_max_nesting(size_t max); + + void Reset(); + + static const size_t kSize = UPB_PB_DECODER_SIZE; + + private: + UPB_DISALLOW_POD_OPS(Decoder, upb::pb::Decoder) +}; + +#endif /* __cplusplus */ + +#ifdef __cplusplus + +/* A class for caching protobuf processing code, whether bytecode for the + * interpreted decoder or machine code for the JIT. + * + * This class is not thread-safe. + * + * TODO(haberman): move this to be heap allocated for ABI stability. */ +class upb::pb::CodeCache { + public: + CodeCache(); + ~CodeCache(); + + /* Whether the cache is allowed to generate machine code. Defaults to true. + * There is no real reason to turn it off except for testing or if you are + * having a specific problem with the JIT. + * + * Note that allow_jit = true does not *guarantee* that the code will be JIT + * compiled. If this platform is not supported or the JIT was not compiled + * in, the code may still be interpreted. */ + bool allow_jit() const; + + /* This may only be called when the object is first constructed, and prior to + * any code generation, otherwise returns false and does nothing. */ + bool set_allow_jit(bool allow); + + /* Returns a DecoderMethod that can push data to the given handlers. + * If a suitable method already exists, it will be returned from the cache. + * + * Specifying the destination handlers here allows the DecoderMethod to be + * statically bound to the destination handlers if possible, which can allow + * more efficient decoding. However the returned method may or may not + * actually be statically bound. But in all cases, the returned method can + * push data to the given handlers. */ + const DecoderMethod *GetDecoderMethod(const DecoderMethodOptions& opts); + + /* If/when someone needs to explicitly create a dynamically-bound + * DecoderMethod*, we can add a method to get it here. */ + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(CodeCache) +#else +struct upb_pbcodecache { +#endif + bool allow_jit_; + + /* Array of mgroups. */ + upb_inttable groups; +}; + +UPB_BEGIN_EXTERN_C + +upb_pbdecoder *upb_pbdecoder_create(upb_env *e, + const upb_pbdecodermethod *method, + upb_sink *output); +const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d); +upb_bytessink *upb_pbdecoder_input(upb_pbdecoder *d); +uint64_t upb_pbdecoder_bytesparsed(const upb_pbdecoder *d); +size_t upb_pbdecoder_maxnesting(const upb_pbdecoder *d); +bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max); +void upb_pbdecoder_reset(upb_pbdecoder *d); + +void upb_pbdecodermethodopts_init(upb_pbdecodermethodopts *opts, + const upb_handlers *h); +void upb_pbdecodermethodopts_setlazy(upb_pbdecodermethodopts *opts, bool lazy); + + +/* Include refcounted methods like upb_pbdecodermethod_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_pbdecodermethod, upb_pbdecodermethod_upcast) + +const upb_handlers *upb_pbdecodermethod_desthandlers( + const upb_pbdecodermethod *m); +const upb_byteshandler *upb_pbdecodermethod_inputhandler( + const upb_pbdecodermethod *m); +bool upb_pbdecodermethod_isnative(const upb_pbdecodermethod *m); +const upb_pbdecodermethod *upb_pbdecodermethod_new( + const upb_pbdecodermethodopts *opts, const void *owner); + +void upb_pbcodecache_init(upb_pbcodecache *c); +void upb_pbcodecache_uninit(upb_pbcodecache *c); +bool upb_pbcodecache_allowjit(const upb_pbcodecache *c); +bool upb_pbcodecache_setallowjit(upb_pbcodecache *c, bool allow); +const upb_pbdecodermethod *upb_pbcodecache_getdecodermethod( + upb_pbcodecache *c, const upb_pbdecodermethodopts *opts); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upb { + +namespace pb { + +/* static */ +inline Decoder* Decoder::Create(Environment* env, const DecoderMethod* m, + Sink* sink) { + return upb_pbdecoder_create(env, m, sink); +} +inline const DecoderMethod* Decoder::method() const { + return upb_pbdecoder_method(this); +} +inline BytesSink* Decoder::input() { + return upb_pbdecoder_input(this); +} +inline uint64_t Decoder::BytesParsed() const { + return upb_pbdecoder_bytesparsed(this); +} +inline size_t Decoder::max_nesting() const { + return upb_pbdecoder_maxnesting(this); +} +inline bool Decoder::set_max_nesting(size_t max) { + return upb_pbdecoder_setmaxnesting(this, max); +} +inline void Decoder::Reset() { upb_pbdecoder_reset(this); } + +inline DecoderMethodOptions::DecoderMethodOptions(const Handlers* h) { + upb_pbdecodermethodopts_init(this, h); +} +inline void DecoderMethodOptions::set_lazy(bool lazy) { + upb_pbdecodermethodopts_setlazy(this, lazy); +} + +inline const Handlers* DecoderMethod::dest_handlers() const { + return upb_pbdecodermethod_desthandlers(this); +} +inline const BytesHandler* DecoderMethod::input_handler() const { + return upb_pbdecodermethod_inputhandler(this); +} +inline bool DecoderMethod::is_native() const { + return upb_pbdecodermethod_isnative(this); +} +/* static */ +inline reffed_ptr DecoderMethod::New( + const DecoderMethodOptions &opts) { + const upb_pbdecodermethod *m = upb_pbdecodermethod_new(&opts, &m); + return reffed_ptr(m, &m); +} + +inline CodeCache::CodeCache() { + upb_pbcodecache_init(this); +} +inline CodeCache::~CodeCache() { + upb_pbcodecache_uninit(this); +} +inline bool CodeCache::allow_jit() const { + return upb_pbcodecache_allowjit(this); +} +inline bool CodeCache::set_allow_jit(bool allow) { + return upb_pbcodecache_setallowjit(this, allow); +} +inline const DecoderMethod *CodeCache::GetDecoderMethod( + const DecoderMethodOptions& opts) { + return upb_pbcodecache_getdecodermethod(this, &opts); +} + +} /* namespace pb */ +} /* namespace upb */ + +#endif /* __cplusplus */ + +#endif /* UPB_DECODER_H_ */ + +/* C++ names are not actually used since this type isn't exposed to users. */ +#ifdef __cplusplus +namespace upb { +namespace pb { +class MessageGroup; +} /* namespace pb */ +} /* namespace upb */ +#endif +UPB_DECLARE_DERIVED_TYPE(upb::pb::MessageGroup, upb::RefCounted, + mgroup, upb_refcounted) + +/* Opcode definitions. The canonical meaning of each opcode is its + * implementation in the interpreter (the JIT is written to match this). + * + * All instructions have the opcode in the low byte. + * Instruction format for most instructions is: + * + * +-------------------+--------+ + * | arg (24) | op (8) | + * +-------------------+--------+ + * + * Exceptions are indicated below. A few opcodes are multi-word. */ +typedef enum { + /* Opcodes 1-8, 13, 15-18 parse their respective descriptor types. + * Arg for all of these is the upb selector for this field. */ +#define T(type) OP_PARSE_ ## type = UPB_DESCRIPTOR_TYPE_ ## type + T(DOUBLE), T(FLOAT), T(INT64), T(UINT64), T(INT32), T(FIXED64), T(FIXED32), + T(BOOL), T(UINT32), T(SFIXED32), T(SFIXED64), T(SINT32), T(SINT64), +#undef T + OP_STARTMSG = 9, /* No arg. */ + OP_ENDMSG = 10, /* No arg. */ + OP_STARTSEQ = 11, + OP_ENDSEQ = 12, + OP_STARTSUBMSG = 14, + OP_ENDSUBMSG = 19, + OP_STARTSTR = 20, + OP_STRING = 21, + OP_ENDSTR = 22, + + OP_PUSHTAGDELIM = 23, /* No arg. */ + OP_PUSHLENDELIM = 24, /* No arg. */ + OP_POP = 25, /* No arg. */ + OP_SETDELIM = 26, /* No arg. */ + OP_SETBIGGROUPNUM = 27, /* two words: + * | unused (24) | opc (8) | + * | groupnum (32) | */ + OP_CHECKDELIM = 28, + OP_CALL = 29, + OP_RET = 30, + OP_BRANCH = 31, + + /* Different opcodes depending on how many bytes expected. */ + OP_TAG1 = 32, /* | match tag (16) | jump target (8) | opc (8) | */ + OP_TAG2 = 33, /* | match tag (16) | jump target (8) | opc (8) | */ + OP_TAGN = 34, /* three words: */ + /* | unused (16) | jump target(8) | opc (8) | */ + /* | match tag 1 (32) | */ + /* | match tag 2 (32) | */ + + OP_SETDISPATCH = 35, /* N words: */ + /* | unused (24) | opc | */ + /* | upb_inttable* (32 or 64) | */ + + OP_DISPATCH = 36, /* No arg. */ + + OP_HALT = 37 /* No arg. */ +} opcode; + +#define OP_MAX OP_HALT + +UPB_INLINE opcode getop(uint32_t instr) { return instr & 0xff; } + +/* Method group; represents a set of decoder methods that had their code + * emitted together, and must therefore be freed together. Immutable once + * created. It is possible we may want to expose this to users at some point. + * + * Overall ownership of Decoder objects looks like this: + * + * +----------+ + * | | <---> DecoderMethod + * | method | + * CodeCache ---> | group | <---> DecoderMethod + * | | + * | (mgroup) | <---> DecoderMethod + * +----------+ + */ +struct mgroup { + upb_refcounted base; + + /* Maps upb_msgdef/upb_handlers -> upb_pbdecodermethod. We own refs on the + * methods. */ + upb_inttable methods; + + /* When we add the ability to link to previously existing mgroups, we'll + * need an array of mgroups we reference here, and own refs on them. */ + + /* The bytecode for our methods, if any exists. Owned by us. */ + uint32_t *bytecode; + uint32_t *bytecode_end; + +#ifdef UPB_USE_JIT_X64 + /* JIT-generated machine code, if any. */ + upb_string_handlerfunc *jit_code; + /* The size of the jit_code (required to munmap()). */ + size_t jit_size; + char *debug_info; + void *dl; +#endif +}; + +/* The maximum that any submessages can be nested. Matches proto2's limit. + * This specifies the size of the decoder's statically-sized array and therefore + * setting it high will cause the upb::pb::Decoder object to be larger. + * + * If necessary we can add a runtime-settable property to Decoder that allow + * this to be larger than the compile-time setting, but this would add + * complexity, particularly since we would have to decide how/if to give users + * the ability to set a custom memory allocation function. */ +#define UPB_DECODER_MAX_NESTING 64 + +/* Internal-only struct used by the decoder. */ +typedef struct { + /* Space optimization note: we store two pointers here that the JIT + * doesn't need at all; the upb_handlers* inside the sink and + * the dispatch table pointer. We can optimze so that the JIT uses + * smaller stack frames than the interpreter. The only thing we need + * to guarantee is that the fallback routines can find end_ofs. */ + upb_sink sink; + + /* The absolute stream offset of the end-of-frame delimiter. + * Non-delimited frames (groups and non-packed repeated fields) reuse the + * delimiter of their parent, even though the frame may not end there. + * + * NOTE: the JIT stores a slightly different value here for non-top frames. + * It stores the value relative to the end of the enclosed message. But the + * top frame is still stored the same way, which is important for ensuring + * that calls from the JIT into C work correctly. */ + uint64_t end_ofs; + const uint32_t *base; + + /* 0 indicates a length-delimited field. + * A positive number indicates a known group. + * A negative number indicates an unknown group. */ + int32_t groupnum; + upb_inttable *dispatch; /* Not used by the JIT. */ +} upb_pbdecoder_frame; + +struct upb_pbdecodermethod { + upb_refcounted base; + + /* While compiling, the base is relative in "ofs", after compiling it is + * absolute in "ptr". */ + union { + uint32_t ofs; /* PC offset of method. */ + void *ptr; /* Pointer to bytecode or machine code for this method. */ + } code_base; + + /* The decoder method group to which this method belongs. We own a ref. + * Owning a ref on the entire group is more coarse-grained than is strictly + * necessary; all we truly require is that methods we directly reference + * outlive us, while the group could contain many other messages we don't + * require. But the group represents the messages that were + * allocated+compiled together, so it makes the most sense to free them + * together also. */ + const upb_refcounted *group; + + /* Whether this method is native code or bytecode. */ + bool is_native_; + + /* The handler one calls to invoke this method. */ + upb_byteshandler input_handler_; + + /* The destination handlers this method is bound to. We own a ref. */ + const upb_handlers *dest_handlers_; + + /* Dispatch table -- used by both bytecode decoder and JIT when encountering a + * field number that wasn't the one we were expecting to see. See + * decoder.int.h for the layout of this table. */ + upb_inttable dispatch; +}; + +struct upb_pbdecoder { + upb_env *env; + + /* Our input sink. */ + upb_bytessink input_; + + /* The decoder method we are parsing with (owned). */ + const upb_pbdecodermethod *method_; + + size_t call_len; + const uint32_t *pc, *last; + + /* Current input buffer and its stream offset. */ + const char *buf, *ptr, *end, *checkpoint; + + /* End of the delimited region, relative to ptr, NULL if not in this buf. */ + const char *delim_end; + + /* End of the delimited region, relative to ptr, end if not in this buf. */ + const char *data_end; + + /* Overall stream offset of "buf." */ + uint64_t bufstart_ofs; + + /* Buffer for residual bytes not parsed from the previous buffer. + * The maximum number of residual bytes we require is 12; a five-byte + * unknown tag plus an eight-byte value, less one because the value + * is only a partial value. */ + char residual[12]; + char *residual_end; + + /* Bytes of data that should be discarded from the input beore we start + * parsing again. We set this when we internally determine that we can + * safely skip the next N bytes, but this region extends past the current + * user buffer. */ + size_t skip; + + /* Stores the user buffer passed to our decode function. */ + const char *buf_param; + size_t size_param; + const upb_bufhandle *handle; + + /* Our internal stack. */ + upb_pbdecoder_frame *stack, *top, *limit; + const uint32_t **callstack; + size_t stack_size; + + upb_status *status; + +#ifdef UPB_USE_JIT_X64 + /* Used momentarily by the generated code to store a value while a user + * function is called. */ + uint32_t tmp_len; + + const void *saved_rsp; +#endif +}; + +/* Decoder entry points; used as handlers. */ +void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint); +void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint); +size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, + size_t size, const upb_bufhandle *handle); +bool upb_pbdecoder_end(void *closure, const void *handler_data); + +/* Decoder-internal functions that the JIT calls to handle fallback paths. */ +int32_t upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, + size_t size, const upb_bufhandle *handle); +size_t upb_pbdecoder_suspend(upb_pbdecoder *d); +int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, int32_t fieldnum, + uint8_t wire_type); +int32_t upb_pbdecoder_checktag_slow(upb_pbdecoder *d, uint64_t expected); +int32_t upb_pbdecoder_decode_varint_slow(upb_pbdecoder *d, uint64_t *u64); +int32_t upb_pbdecoder_decode_f32(upb_pbdecoder *d, uint32_t *u32); +int32_t upb_pbdecoder_decode_f64(upb_pbdecoder *d, uint64_t *u64); +void upb_pbdecoder_seterr(upb_pbdecoder *d, const char *msg); + +/* Error messages that are shared between the bytecode and JIT decoders. */ +extern const char *kPbDecoderStackOverflow; +extern const char *kPbDecoderSubmessageTooLong; + +/* Access to decoderplan members needed by the decoder. */ +const char *upb_pbdecoder_getopname(unsigned int op); + +/* JIT codegen entry point. */ +void upb_pbdecoder_jit(mgroup *group); +void upb_pbdecoder_freejit(mgroup *group); +UPB_REFCOUNTED_CMETHODS(mgroup, mgroup_upcast) + +/* A special label that means "do field dispatch for this message and branch to + * wherever that takes you." */ +#define LABEL_DISPATCH 0 + +/* A special slot in the dispatch table that stores the epilogue (ENDMSG and/or + * RET) for branching to when we find an appropriate ENDGROUP tag. */ +#define DISPATCH_ENDMSG 0 + +/* It's important to use this invalid wire type instead of 0 (which is a valid + * wire type). */ +#define NO_WIRE_TYPE 0xff + +/* The dispatch table layout is: + * [field number] -> [ 48-bit offset ][ 8-bit wt2 ][ 8-bit wt1 ] + * + * If wt1 matches, jump to the 48-bit offset. If wt2 matches, lookup + * (UPB_MAX_FIELDNUMBER + fieldnum) and jump there. + * + * We need two wire types because of packed/non-packed compatibility. A + * primitive repeated field can use either wire type and be valid. While we + * could key the table on fieldnum+wiretype, the table would be 8x sparser. + * + * Storing two wire types in the primary value allows us to quickly rule out + * the second wire type without needing to do a separate lookup (this case is + * less common than an unknown field). */ +UPB_INLINE uint64_t upb_pbdecoder_packdispatch(uint64_t ofs, uint8_t wt1, + uint8_t wt2) { + return (ofs << 16) | (wt2 << 8) | wt1; +} + +UPB_INLINE void upb_pbdecoder_unpackdispatch(uint64_t dispatch, uint64_t *ofs, + uint8_t *wt1, uint8_t *wt2) { + *wt1 = (uint8_t)dispatch; + *wt2 = (uint8_t)(dispatch >> 8); + *ofs = dispatch >> 16; +} + +/* All of the functions in decoder.c that return int32_t return values according + * to the following scheme: + * 1. negative values indicate a return code from the following list. + * 2. positive values indicate that error or end of buffer was hit, and + * that the decode function should immediately return the given value + * (the decoder state has already been suspended and is ready to be + * resumed). */ +#define DECODE_OK -1 +#define DECODE_MISMATCH -2 /* Used only from checktag_slow(). */ +#define DECODE_ENDGROUP -3 /* Used only from checkunknown(). */ + +#define CHECK_RETURN(x) { int32_t ret = x; if (ret >= 0) return ret; } + +#endif /* UPB_DECODER_INT_H_ */ +/* +** A number of routines for varint manipulation (we keep them all around to +** have multiple approaches available for benchmarking). +*/ + +#ifndef UPB_VARINT_DECODER_H_ +#define UPB_VARINT_DECODER_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* A list of types as they are encoded on-the-wire. */ +typedef enum { + UPB_WIRE_TYPE_VARINT = 0, + UPB_WIRE_TYPE_64BIT = 1, + UPB_WIRE_TYPE_DELIMITED = 2, + UPB_WIRE_TYPE_START_GROUP = 3, + UPB_WIRE_TYPE_END_GROUP = 4, + UPB_WIRE_TYPE_32BIT = 5 +} upb_wiretype_t; + +#define UPB_MAX_WIRE_TYPE 5 + +/* The maximum number of bytes that it takes to encode a 64-bit varint. + * Note that with a better encoding this could be 9 (TODO: write up a + * wiki document about this). */ +#define UPB_PB_VARINT_MAX_LEN 10 + +/* Array of the "native" (ie. non-packed-repeated) wire type for the given a + * descriptor type (upb_descriptortype_t). */ +extern const uint8_t upb_pb_native_wire_types[]; + +/* Zig-zag encoding/decoding **************************************************/ + +UPB_INLINE int32_t upb_zzdec_32(uint32_t n) { + return (n >> 1) ^ -(int32_t)(n & 1); +} +UPB_INLINE int64_t upb_zzdec_64(uint64_t n) { + return (n >> 1) ^ -(int64_t)(n & 1); +} +UPB_INLINE uint32_t upb_zzenc_32(int32_t n) { return (n << 1) ^ (n >> 31); } +UPB_INLINE uint64_t upb_zzenc_64(int64_t n) { return (n << 1) ^ (n >> 63); } + +/* Decoding *******************************************************************/ + +/* All decoding functions return this struct by value. */ +typedef struct { + const char *p; /* NULL if the varint was unterminated. */ + uint64_t val; +} upb_decoderet; + +UPB_INLINE upb_decoderet upb_decoderet_make(const char *p, uint64_t val) { + upb_decoderet ret; + ret.p = p; + ret.val = val; + return ret; +} + +/* Four functions for decoding a varint of at most eight bytes. They are all + * functionally identical, but are implemented in different ways and likely have + * different performance profiles. We keep them around for performance testing. + * + * Note that these functions may not read byte-by-byte, so they must not be used + * unless there are at least eight bytes left in the buffer! */ +upb_decoderet upb_vdecode_max8_branch32(upb_decoderet r); +upb_decoderet upb_vdecode_max8_branch64(upb_decoderet r); +upb_decoderet upb_vdecode_max8_wright(upb_decoderet r); +upb_decoderet upb_vdecode_max8_massimino(upb_decoderet r); + +/* Template for a function that checks the first two bytes with branching + * and dispatches 2-10 bytes with a separate function. Note that this may read + * up to 10 bytes, so it must not be used unless there are at least ten bytes + * left in the buffer! */ +#define UPB_VARINT_DECODER_CHECK2(name, decode_max8_function) \ +UPB_INLINE upb_decoderet upb_vdecode_check2_ ## name(const char *_p) { \ + uint8_t *p = (uint8_t*)_p; \ + upb_decoderet r; \ + if ((*p & 0x80) == 0) { \ + /* Common case: one-byte varint. */ \ + return upb_decoderet_make(_p + 1, *p & 0x7fU); \ + } \ + r = upb_decoderet_make(_p + 2, (*p & 0x7fU) | ((*(p + 1) & 0x7fU) << 7)); \ + if ((*(p + 1) & 0x80) == 0) { \ + /* Two-byte varint. */ \ + return r; \ + } \ + /* Longer varint, fallback to out-of-line function. */ \ + return decode_max8_function(r); \ +} + +UPB_VARINT_DECODER_CHECK2(branch32, upb_vdecode_max8_branch32) +UPB_VARINT_DECODER_CHECK2(branch64, upb_vdecode_max8_branch64) +UPB_VARINT_DECODER_CHECK2(wright, upb_vdecode_max8_wright) +UPB_VARINT_DECODER_CHECK2(massimino, upb_vdecode_max8_massimino) +#undef UPB_VARINT_DECODER_CHECK2 + +/* Our canonical functions for decoding varints, based on the currently + * favored best-performing implementations. */ +UPB_INLINE upb_decoderet upb_vdecode_fast(const char *p) { + if (sizeof(long) == 8) + return upb_vdecode_check2_branch64(p); + else + return upb_vdecode_check2_branch32(p); +} + +UPB_INLINE upb_decoderet upb_vdecode_max8_fast(upb_decoderet r) { + return upb_vdecode_max8_massimino(r); +} + + +/* Encoding *******************************************************************/ + +UPB_INLINE int upb_value_size(uint64_t val) { +#ifdef __GNUC__ + int high_bit = 63 - __builtin_clzll(val); /* 0-based, undef if val == 0. */ +#else + int high_bit = 0; + uint64_t tmp = val; + while(tmp >>= 1) high_bit++; +#endif + return val == 0 ? 1 : high_bit / 8 + 1; +} + +/* Encodes a 64-bit varint into buf (which must be >=UPB_PB_VARINT_MAX_LEN + * bytes long), returning how many bytes were used. + * + * TODO: benchmark and optimize if necessary. */ +UPB_INLINE size_t upb_vencode64(uint64_t val, char *buf) { + size_t i; + if (val == 0) { buf[0] = 0; return 1; } + i = 0; + while (val) { + uint8_t byte = val & 0x7fU; + val >>= 7; + if (val) byte |= 0x80U; + buf[i++] = byte; + } + return i; +} + +UPB_INLINE size_t upb_varint_size(uint64_t val) { + char buf[UPB_PB_VARINT_MAX_LEN]; + return upb_vencode64(val, buf); +} + +/* Encodes a 32-bit varint, *not* sign-extended. */ +UPB_INLINE uint64_t upb_vencode32(uint32_t val) { + char buf[UPB_PB_VARINT_MAX_LEN]; + size_t bytes = upb_vencode64(val, buf); + uint64_t ret = 0; + assert(bytes <= 5); + memcpy(&ret, buf, bytes); + assert(ret <= 0xffffffffffU); + return ret; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_VARINT_DECODER_H_ */ +/* +** upb::pb::Encoder (upb_pb_encoder) +** +** Implements a set of upb_handlers that write protobuf data to the binary wire +** format. +** +** This encoder implementation does not have any access to any out-of-band or +** precomputed lengths for submessages, so it must buffer submessages internally +** before it can emit the first byte. +*/ + +#ifndef UPB_ENCODER_H_ +#define UPB_ENCODER_H_ + + +#ifdef __cplusplus +namespace upb { +namespace pb { +class Encoder; +} /* namespace pb */ +} /* namespace upb */ +#endif + +UPB_DECLARE_TYPE(upb::pb::Encoder, upb_pb_encoder) + +#define UPB_PBENCODER_MAX_NESTING 100 + +/* upb::pb::Encoder ***********************************************************/ + +/* Preallocation hint: decoder won't allocate more bytes than this when first + * constructed. This hint may be an overestimate for some build configurations. + * But if the decoder library is upgraded without recompiling the application, + * it may be an underestimate. */ +#define UPB_PB_ENCODER_SIZE 768 + +#ifdef __cplusplus + +class upb::pb::Encoder { + public: + /* Creates a new encoder in the given environment. The Handlers must have + * come from NewHandlers() below. */ + static Encoder* Create(Environment* env, const Handlers* handlers, + BytesSink* output); + + /* The input to the encoder. */ + Sink* input(); + + /* Creates a new set of handlers for this MessageDef. */ + static reffed_ptr NewHandlers(const MessageDef* msg); + + static const size_t kSize = UPB_PB_ENCODER_SIZE; + + private: + UPB_DISALLOW_POD_OPS(Encoder, upb::pb::Encoder) +}; + +#endif + +UPB_BEGIN_EXTERN_C + +const upb_handlers *upb_pb_encoder_newhandlers(const upb_msgdef *m, + const void *owner); +upb_sink *upb_pb_encoder_input(upb_pb_encoder *p); +upb_pb_encoder* upb_pb_encoder_create(upb_env* e, const upb_handlers* h, + upb_bytessink* output); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upb { +namespace pb { +inline Encoder* Encoder::Create(Environment* env, const Handlers* handlers, + BytesSink* output) { + return upb_pb_encoder_create(env, handlers, output); +} +inline Sink* Encoder::input() { + return upb_pb_encoder_input(this); +} +inline reffed_ptr Encoder::NewHandlers( + const upb::MessageDef *md) { + const Handlers* h = upb_pb_encoder_newhandlers(md, &h); + return reffed_ptr(h, &h); +} +} /* namespace pb */ +} /* namespace upb */ + +#endif + +#endif /* UPB_ENCODER_H_ */ +/* +** upb's core components like upb_decoder and upb_msg are carefully designed to +** avoid depending on each other for maximum orthogonality. In other words, +** you can use a upb_decoder to decode into *any* kind of structure; upb_msg is +** just one such structure. A upb_msg can be serialized/deserialized into any +** format, protobuf binary format is just one such format. +** +** However, for convenience we provide functions here for doing common +** operations like deserializing protobuf binary format into a upb_msg. The +** compromise is that this file drags in almost all of upb as a dependency, +** which could be undesirable if you're trying to use a trimmed-down build of +** upb. +** +** While these routines are convenient, they do not reuse any encoding/decoding +** state. For example, if a decoder is JIT-based, it will be re-JITted every +** time these functions are called. For this reason, if you are parsing lots +** of data and efficiency is an issue, these may not be the best functions to +** use (though they are useful for prototyping, before optimizing). +*/ + +#ifndef UPB_GLUE_H +#define UPB_GLUE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Loads all defs from the given protobuf binary descriptor, setting default + * accessors and a default layout on all messages. The caller owns the + * returned array of defs, which will be of length *n. On error NULL is + * returned and status is set (if non-NULL). */ +upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, + void *owner, upb_status *status); + +/* Like the previous but also adds the loaded defs to the given symtab. */ +bool upb_load_descriptor_into_symtab(upb_symtab *symtab, const char *str, + size_t len, upb_status *status); + +/* Like the previous but also reads the descriptor from the given filename. */ +bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname, + upb_status *status); + +/* Reads the given filename into a character string, returning NULL if there + * was an error. */ +char *upb_readfile(const char *filename, size_t *len); + +#ifdef __cplusplus +} /* extern "C" */ + +namespace upb { + +/* All routines that load descriptors expect the descriptor to be a + * FileDescriptorSet. */ +inline bool LoadDescriptorFileIntoSymtab(SymbolTable* s, const char *fname, + Status* status) { + return upb_load_descriptor_file_into_symtab(s, fname, status); +} + +inline bool LoadDescriptorIntoSymtab(SymbolTable* s, const char* str, + size_t len, Status* status) { + return upb_load_descriptor_into_symtab(s, str, len, status); +} + +/* Templated so it can accept both string and std::string. */ +template +bool LoadDescriptorIntoSymtab(SymbolTable* s, const T& desc, Status* status) { + return upb_load_descriptor_into_symtab(s, desc.c_str(), desc.size(), status); +} + +} /* namespace upb */ + +#endif + +#endif /* UPB_GLUE_H */ +/* +** upb::pb::TextPrinter (upb_textprinter) +** +** Handlers for writing to protobuf text format. +*/ + +#ifndef UPB_TEXT_H_ +#define UPB_TEXT_H_ + + +#ifdef __cplusplus +namespace upb { +namespace pb { +class TextPrinter; +} /* namespace pb */ +} /* namespace upb */ +#endif + +UPB_DECLARE_TYPE(upb::pb::TextPrinter, upb_textprinter) + +#ifdef __cplusplus + +class upb::pb::TextPrinter { + public: + /* The given handlers must have come from NewHandlers(). It must outlive the + * TextPrinter. */ + static TextPrinter *Create(Environment *env, const upb::Handlers *handlers, + BytesSink *output); + + void SetSingleLineMode(bool single_line); + + Sink* input(); + + /* If handler caching becomes a requirement we can add a code cache as in + * decoder.h */ + static reffed_ptr NewHandlers(const MessageDef* md); +}; + +#endif + +UPB_BEGIN_EXTERN_C + +/* C API. */ +upb_textprinter *upb_textprinter_create(upb_env *env, const upb_handlers *h, + upb_bytessink *output); +void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line); +upb_sink *upb_textprinter_input(upb_textprinter *p); + +const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, + const void *owner); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upb { +namespace pb { +inline TextPrinter *TextPrinter::Create(Environment *env, + const upb::Handlers *handlers, + BytesSink *output) { + return upb_textprinter_create(env, handlers, output); +} +inline void TextPrinter::SetSingleLineMode(bool single_line) { + upb_textprinter_setsingleline(this, single_line); +} +inline Sink* TextPrinter::input() { + return upb_textprinter_input(this); +} +inline reffed_ptr TextPrinter::NewHandlers( + const MessageDef *md) { + const Handlers* h = upb_textprinter_newhandlers(md, &h); + return reffed_ptr(h, &h); +} +} /* namespace pb */ +} /* namespace upb */ + +#endif + +#endif /* UPB_TEXT_H_ */ +/* +** upb::json::Parser (upb_json_parser) +** +** Parses JSON according to a specific schema. +** Support for parsing arbitrary JSON (schema-less) will be added later. +*/ + +#ifndef UPB_JSON_PARSER_H_ +#define UPB_JSON_PARSER_H_ + + +#ifdef __cplusplus +namespace upb { +namespace json { +class Parser; +} /* namespace json */ +} /* namespace upb */ +#endif + +UPB_DECLARE_TYPE(upb::json::Parser, upb_json_parser) + +/* upb::json::Parser **********************************************************/ + +/* Preallocation hint: parser won't allocate more bytes than this when first + * constructed. This hint may be an overestimate for some build configurations. + * But if the parser library is upgraded without recompiling the application, + * it may be an underestimate. */ +#define UPB_JSON_PARSER_SIZE 3704 + +#ifdef __cplusplus + +/* Parses an incoming BytesStream, pushing the results to the destination + * sink. */ +class upb::json::Parser { + public: + static Parser* Create(Environment* env, Sink* output); + + BytesSink* input(); + + private: + UPB_DISALLOW_POD_OPS(Parser, upb::json::Parser) +}; + +#endif + +UPB_BEGIN_EXTERN_C + +upb_json_parser *upb_json_parser_create(upb_env *e, upb_sink *output); +upb_bytessink *upb_json_parser_input(upb_json_parser *p); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upb { +namespace json { +inline Parser* Parser::Create(Environment* env, Sink* output) { + return upb_json_parser_create(env, output); +} +inline BytesSink* Parser::input() { + return upb_json_parser_input(this); +} +} /* namespace json */ +} /* namespace upb */ + +#endif + + +#endif /* UPB_JSON_PARSER_H_ */ +/* +** upb::json::Printer +** +** Handlers that emit JSON according to a specific protobuf schema. +*/ + +#ifndef UPB_JSON_TYPED_PRINTER_H_ +#define UPB_JSON_TYPED_PRINTER_H_ + + +#ifdef __cplusplus +namespace upb { +namespace json { +class Printer; +} /* namespace json */ +} /* namespace upb */ +#endif + +UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer) + + +/* upb::json::Printer *********************************************************/ + +#define UPB_JSON_PRINTER_SIZE 168 + +#ifdef __cplusplus + +/* Prints an incoming stream of data to a BytesSink in JSON format. */ +class upb::json::Printer { + public: + static Printer* Create(Environment* env, const upb::Handlers* handlers, + BytesSink* output); + + /* The input to the printer. */ + Sink* input(); + + /* Returns handlers for printing according to the specified schema. */ + static reffed_ptr NewHandlers(const upb::MessageDef* md); + + static const size_t kSize = UPB_JSON_PRINTER_SIZE; + + private: + UPB_DISALLOW_POD_OPS(Printer, upb::json::Printer) +}; + +#endif + +UPB_BEGIN_EXTERN_C + +/* Native C API. */ +upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h, + upb_bytessink *output); +upb_sink *upb_json_printer_input(upb_json_printer *p); +const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md, + const void *owner); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +namespace upb { +namespace json { +inline Printer* Printer::Create(Environment* env, const upb::Handlers* handlers, + BytesSink* output) { + return upb_json_printer_create(env, handlers, output); +} +inline Sink* Printer::input() { return upb_json_printer_input(this); } +inline reffed_ptr Printer::NewHandlers( + const upb::MessageDef *md) { + const Handlers* h = upb_json_printer_newhandlers(md, &h); + return reffed_ptr(h, &h); +} +} /* namespace json */ +} /* namespace upb */ + +#endif + +#endif /* UPB_JSON_TYPED_PRINTER_H_ */ diff --git a/python/google/protobuf/internal/descriptor_database_test.py b/python/google/protobuf/internal/descriptor_database_test.py index 1baff7d1..5225a458 100644 --- a/python/google/protobuf/internal/descriptor_database_test.py +++ b/python/google/protobuf/internal/descriptor_database_test.py @@ -35,9 +35,10 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import descriptor_pb2 from google.protobuf.internal import factory_test2_pb2 from google.protobuf import descriptor_database diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py index f1d6bf99..4b1811d8 100644 --- a/python/google/protobuf/internal/descriptor_pool_test.py +++ b/python/google/protobuf/internal/descriptor_pool_test.py @@ -35,11 +35,13 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' import os +import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_import_public_pb2 from google.protobuf import unittest_pb2 @@ -49,7 +51,6 @@ from google.protobuf.internal import descriptor_pool_test1_pb2 from google.protobuf.internal import descriptor_pool_test2_pb2 from google.protobuf.internal import factory_test1_pb2 from google.protobuf.internal import factory_test2_pb2 -from google.protobuf.internal import test_util from google.protobuf import descriptor from google.protobuf import descriptor_database from google.protobuf import descriptor_pool @@ -350,7 +351,7 @@ class DescriptorPoolTest(unittest.TestCase): @unittest.skipIf(api_implementation.Type() != 'cpp', - 'explicit tests of the C++ implementation') + 'explicit tests of the C++ implementation') class CppDescriptorPoolTest(DescriptorPoolTest): # TODO(amauryfa): remove when descriptor_pool.DescriptorPool() creates true # C++ descriptor pool object for C++ implementation. @@ -555,7 +556,7 @@ class AddDescriptorTest(unittest.TestCase): prefix + 'protobuf_unittest.TestAllTypes.NestedMessage').name) @unittest.skipIf(api_implementation.Type() == 'cpp', - 'With the cpp implementation, Add() must be called first') + 'With the cpp implementation, Add() must be called first') def testMessage(self): self._TestMessage('') self._TestMessage('.') @@ -591,13 +592,13 @@ class AddDescriptorTest(unittest.TestCase): prefix + 'protobuf_unittest.TestAllTypes.NestedEnum').name) @unittest.skipIf(api_implementation.Type() == 'cpp', - 'With the cpp implementation, Add() must be called first') + 'With the cpp implementation, Add() must be called first') def testEnum(self): self._TestEnum('') self._TestEnum('.') @unittest.skipIf(api_implementation.Type() == 'cpp', - 'With the cpp implementation, Add() must be called first') + 'With the cpp implementation, Add() must be called first') def testFile(self): pool = descriptor_pool.DescriptorPool() pool.AddFileDescriptor(unittest_pb2.DESCRIPTOR) diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py index fee09a56..b8e75553 100755 --- a/python/google/protobuf/internal/descriptor_test.py +++ b/python/google/protobuf/internal/descriptor_test.py @@ -37,9 +37,10 @@ __author__ = 'robinson@google.com (Will Robinson)' import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_custom_options_pb2 from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_pb2 @@ -596,7 +597,7 @@ class DescriptorCopyToProtoTest(unittest.TestCase): """ self._InternalTestCopyToProto( - unittest_pb2._FOREIGNENUM, + unittest_pb2.ForeignEnum.DESCRIPTOR, descriptor_pb2.EnumDescriptorProto, TEST_FOREIGN_ENUM_ASCII) diff --git a/python/google/protobuf/internal/generator_test.py b/python/google/protobuf/internal/generator_test.py index 9956da59..83ea5f50 100755 --- a/python/google/protobuf/internal/generator_test.py +++ b/python/google/protobuf/internal/generator_test.py @@ -42,9 +42,10 @@ further ensures that we can use Python protocol message objects as we expect. __author__ = 'robinson@google.com (Will Robinson)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf.internal import test_bad_identifiers_pb2 from google.protobuf import unittest_custom_options_pb2 from google.protobuf import unittest_import_pb2 diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py index 49e96a46..bdc9f49a 100644 --- a/python/google/protobuf/internal/json_format_test.py +++ b/python/google/protobuf/internal/json_format_test.py @@ -39,9 +39,10 @@ import math import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import any_pb2 from google.protobuf import duration_pb2 from google.protobuf import field_mask_pb2 @@ -758,7 +759,7 @@ class JsonFormatTest(JsonFormatBase): 'Can not find message descriptor by type_url: ' 'type.googleapis.com/MessageNotExist.', json_format.Parse, text, message) - # Only last part is to be used. + # Only last part is to be used: b/25630112 text = (r'{"@type": "incorrect.googleapis.com/google.protobuf.Int32Value",' r'"value": 1234}') json_format.Parse(text, message) diff --git a/python/google/protobuf/internal/message_factory_test.py b/python/google/protobuf/internal/message_factory_test.py index 2fbe5ea7..54b1f688 100644 --- a/python/google/protobuf/internal/message_factory_test.py +++ b/python/google/protobuf/internal/message_factory_test.py @@ -35,9 +35,10 @@ __author__ = 'matthewtoia@google.com (Matt Toia)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import descriptor_pb2 from google.protobuf.internal import factory_test1_pb2 from google.protobuf.internal import factory_test2_pb2 diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index d03f2d25..34e74bb3 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -53,14 +53,14 @@ import six import sys try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf.internal import _parameterized from google.protobuf import map_unittest_pb2 from google.protobuf import unittest_pb2 from google.protobuf import unittest_proto3_arena_pb2 -from google.protobuf.internal import any_test_pb2 from google.protobuf.internal import api_implementation from google.protobuf.internal import packed_field_test_pb2 from google.protobuf.internal import test_util @@ -69,6 +69,7 @@ from google.protobuf import message if six.PY3: long = int + # Python pre-2.6 does not have isinf() or isnan() functions, so we have # to provide our own. def isnan(val): @@ -1157,6 +1158,7 @@ class Proto2Test(unittest.TestCase): unittest_pb2.TestAllTypes(repeated_nested_enum='FOO') + # Class to test proto3-only features/behavior (updated field presence & enums) class Proto3Test(unittest.TestCase): @@ -1448,6 +1450,22 @@ class Proto3Test(unittest.TestCase): del msg2.map_int32_foreign_message[222] self.assertFalse(222 in msg2.map_int32_foreign_message) + def testMergeFromBadType(self): + msg = map_unittest_pb2.TestMap() + with self.assertRaisesRegexp( + TypeError, + r'Parameter to MergeFrom\(\) must be instance of same class: expected ' + r'.*TestMap got int\.'): + msg.MergeFrom(1) + + def testCopyFromBadType(self): + msg = map_unittest_pb2.TestMap() + with self.assertRaisesRegexp( + TypeError, + r'Parameter to [A-Za-z]*From\(\) must be instance of same class: ' + r'expected .*TestMap got int\.'): + msg.CopyFrom(1) + def testIntegerMapWithLongs(self): msg = map_unittest_pb2.TestMap() msg.map_int32_int32[long(-123)] = long(-456) @@ -1666,37 +1684,6 @@ class Proto3Test(unittest.TestCase): msg.map_string_foreign_message['foo'].c = 5 self.assertEqual(0, len(msg.FindInitializationErrors())) - def testAnyMessage(self): - # Creates and sets message. - msg = any_test_pb2.TestAny() - msg_descriptor = msg.DESCRIPTOR - all_types = unittest_pb2.TestAllTypes() - all_descriptor = all_types.DESCRIPTOR - all_types.repeated_string.append(u'\u00fc\ua71f') - # Packs to Any. - msg.value.Pack(all_types) - self.assertEqual(msg.value.type_url, - 'type.googleapis.com/%s' % all_descriptor.full_name) - self.assertEqual(msg.value.value, - all_types.SerializeToString()) - # Tests Is() method. - self.assertTrue(msg.value.Is(all_descriptor)) - self.assertFalse(msg.value.Is(msg_descriptor)) - # Unpacks Any. - unpacked_message = unittest_pb2.TestAllTypes() - self.assertTrue(msg.value.Unpack(unpacked_message)) - self.assertEqual(all_types, unpacked_message) - # Unpacks to different type. - self.assertFalse(msg.value.Unpack(msg)) - # Only Any messages have Pack method. - try: - msg.Pack(all_types) - except AttributeError: - pass - else: - raise AttributeError('%s should not have Pack method.' % - msg_descriptor.full_name) - class ValidTypeNamesTest(unittest.TestCase): diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py index 822ad895..880b570d 100644 --- a/python/google/protobuf/internal/proto_builder_test.py +++ b/python/google/protobuf/internal/proto_builder_test.py @@ -36,10 +36,7 @@ try: from collections import OrderedDict except ImportError: from ordereddict import OrderedDict #PY26 -try: - import unittest2 as unittest -except ImportError: - import unittest +import unittest from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pool from google.protobuf import proto_builder diff --git a/python/google/protobuf/internal/reflection_test.py b/python/google/protobuf/internal/reflection_test.py index 752f2f5d..9e61ea0e 100755 --- a/python/google/protobuf/internal/reflection_test.py +++ b/python/google/protobuf/internal/reflection_test.py @@ -42,9 +42,10 @@ import six import struct try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_mset_pb2 from google.protobuf import unittest_pb2 diff --git a/python/google/protobuf/internal/service_reflection_test.py b/python/google/protobuf/internal/service_reflection_test.py index 98614b77..62900b1d 100755 --- a/python/google/protobuf/internal/service_reflection_test.py +++ b/python/google/protobuf/internal/service_reflection_test.py @@ -34,10 +34,12 @@ __author__ = 'petar@google.com (Petar Petrov)' + try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_pb2 from google.protobuf import service_reflection from google.protobuf import service diff --git a/python/google/protobuf/internal/symbol_database_test.py b/python/google/protobuf/internal/symbol_database_test.py index 0cb935a8..c99b426d 100644 --- a/python/google/protobuf/internal/symbol_database_test.py +++ b/python/google/protobuf/internal/symbol_database_test.py @@ -33,9 +33,10 @@ """Tests for google.protobuf.symbol_database.""" try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import unittest_pb2 from google.protobuf import descriptor from google.protobuf import symbol_database diff --git a/python/google/protobuf/internal/test_util.py b/python/google/protobuf/internal/test_util.py index ac88fa81..2c805599 100755 --- a/python/google/protobuf/internal/test_util.py +++ b/python/google/protobuf/internal/test_util.py @@ -38,6 +38,8 @@ __author__ = 'robinson@google.com (Will Robinson)' import os.path +import sys + from google.protobuf import unittest_import_pb2 from google.protobuf import unittest_pb2 from google.protobuf import descriptor_pb2 diff --git a/python/google/protobuf/internal/text_encoding_test.py b/python/google/protobuf/internal/text_encoding_test.py index 338a287b..c7d182c4 100755 --- a/python/google/protobuf/internal/text_encoding_test.py +++ b/python/google/protobuf/internal/text_encoding_test.py @@ -33,9 +33,10 @@ """Tests for google.protobuf.text_encoding.""" try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import text_encoding TEST_VALUES = [ diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py index 0e14556c..8ce0a44f 100755 --- a/python/google/protobuf/internal/text_format_test.py +++ b/python/google/protobuf/internal/text_format_test.py @@ -40,9 +40,10 @@ import six import string try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf.internal import _parameterized from google.protobuf import map_unittest_pb2 @@ -62,7 +63,7 @@ class SimpleTextFormatTests(unittest.TestCase): # expects single characters. Therefore it's an error (in addition to being # non-sensical in the first place) to try to specify a "quote mark" that is # more than one character. - def TestQuoteMarksAreSingleChars(self): + def testQuoteMarksAreSingleChars(self): for quote in text_format._QUOTES: self.assertEqual(1, len(quote)) @@ -314,6 +315,18 @@ class TextFormatTest(TextFormatBase): self.assertEqual(u'one', message.repeated_string[0]) self.assertEqual(u'two', message.repeated_string[1]) + def testParseRepeatedMessageShortFormat(self, message_module): + message = message_module.TestAllTypes() + text = ('repeated_nested_message: [{bb: 100}, {bb: 200}],\n' + 'repeated_nested_message: {bb: 300}\n' + 'repeated_nested_message [{bb: 400}];\n') + text_format.Parse(text, message) + + self.assertEqual(100, message.repeated_nested_message[0].bb) + self.assertEqual(200, message.repeated_nested_message[1].bb) + self.assertEqual(300, message.repeated_nested_message[2].bb) + self.assertEqual(400, message.repeated_nested_message[3].bb) + def testParseEmptyText(self, message_module): message = message_module.TestAllTypes() text = '' @@ -411,6 +424,19 @@ class TextFormatTest(TextFormatBase): text_format.Parse(text_format.MessageToString(m), m2) self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field')) + def testParseMultipleOneof(self, message_module): + m_string = '\n'.join([ + 'oneof_uint32: 11', + 'oneof_string: "foo"']) + m2 = message_module.TestAllTypes() + if message_module is unittest_pb2: + with self.assertRaisesRegexp( + text_format.ParseError, ' is specified along with field '): + text_format.Parse(m_string, m2) + else: + text_format.Parse(m_string, m2) + self.assertEqual('oneof_string', m2.WhichOneof('oneof_field')) + # These are tests that aren't fundamentally specific to proto2, but are at # the moment because of differences between the proto2 and proto3 test schemas. @@ -426,7 +452,8 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): 'text_format_unittest_data_pointy_oneof.txt') def testParseGolden(self): - golden_text = '\n'.join(self.ReadGolden('text_format_unittest_data.txt')) + golden_text = '\n'.join(self.ReadGolden( + 'text_format_unittest_data_oneof_implemented.txt')) parsed_message = unittest_pb2.TestAllTypes() r = text_format.Parse(golden_text, parsed_message) self.assertIs(r, parsed_message) @@ -469,7 +496,7 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): 'optional_nested_message {\n bb: 1\n oo: 0\n}\n') def testMergeLinesGolden(self): - opened = self.ReadGolden('text_format_unittest_data.txt') + opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt') parsed_message = unittest_pb2.TestAllTypes() r = text_format.MergeLines(opened, parsed_message) self.assertIs(r, parsed_message) @@ -479,7 +506,7 @@ class OnlyWorksWithProto2RightNowTests(TextFormatBase): self.assertEqual(message, parsed_message) def testParseLinesGolden(self): - opened = self.ReadGolden('text_format_unittest_data.txt') + opened = self.ReadGolden('text_format_unittest_data_oneof_implemented.txt') parsed_message = unittest_pb2.TestAllTypes() r = text_format.ParseLines(opened, parsed_message) self.assertIs(r, parsed_message) diff --git a/python/google/protobuf/internal/unknown_fields_test.py b/python/google/protobuf/internal/unknown_fields_test.py index 9685b8b4..bb2748e4 100755 --- a/python/google/protobuf/internal/unknown_fields_test.py +++ b/python/google/protobuf/internal/unknown_fields_test.py @@ -36,7 +36,7 @@ __author__ = 'bohdank@google.com (Bohdan Koval)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest from google.protobuf import unittest_mset_pb2 diff --git a/python/google/protobuf/internal/well_known_types_test.py b/python/google/protobuf/internal/well_known_types_test.py index 6acbee22..18329205 100644 --- a/python/google/protobuf/internal/well_known_types_test.py +++ b/python/google/protobuf/internal/well_known_types_test.py @@ -37,7 +37,7 @@ __author__ = 'jieluo@google.com (Jie Luo)' from datetime import datetime try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest diff --git a/python/google/protobuf/internal/wire_format_test.py b/python/google/protobuf/internal/wire_format_test.py index f659d18e..da120f33 100755 --- a/python/google/protobuf/internal/wire_format_test.py +++ b/python/google/protobuf/internal/wire_format_test.py @@ -35,9 +35,10 @@ __author__ = 'robinson@google.com (Will Robinson)' try: - import unittest2 as unittest + import unittest2 as unittest #PY26 except ImportError: import unittest + from google.protobuf import message from google.protobuf.internal import wire_format diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py index 23382bdb..4342755a 100644 --- a/python/google/protobuf/json_format.py +++ b/python/google/protobuf/json_format.py @@ -271,10 +271,8 @@ def _ListValueMessageToJsonObject(message, unused_including_default=False): def _StructMessageToJsonObject(message, unused_including_default=False): """Converts Struct message according to Proto3 JSON Specification.""" fields = message.fields - js = {} - for key in fields.keys(): - js[key] = _ValueMessageToJsonObject(fields[key]) - return js + return {key: _ValueMessageToJsonObject(fields[key]) + for key in fields} def _IsWrapperMessage(message_descriptor): diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc index a875a7be..07550706 100644 --- a/python/google/protobuf/pyext/descriptor.cc +++ b/python/google/protobuf/pyext/descriptor.cc @@ -92,11 +92,10 @@ PyObject* PyString_FromCppString(const string& str) { // TODO(amauryfa): Change the proto2 compiler to remove the assignments, and // remove this hack. bool _CalledFromGeneratedFile(int stacklevel) { - PyThreadState *state = PyThreadState_GET(); - if (state == NULL) { - return false; - } - PyFrameObject* frame = state->frame; +#ifndef PYPY_VERSION + // This check is not critical and is somewhat difficult to implement correctly + // in PyPy. + PyFrameObject* frame = PyEval_GetFrame(); if (frame == NULL) { return false; } @@ -130,6 +129,7 @@ bool _CalledFromGeneratedFile(int stacklevel) { // Filename is not ending with _pb2. return false; } +#endif return true; } diff --git a/python/google/protobuf/pyext/descriptor_database.cc b/python/google/protobuf/pyext/descriptor_database.cc index 514722b4..daa40cc7 100644 --- a/python/google/protobuf/pyext/descriptor_database.cc +++ b/python/google/protobuf/pyext/descriptor_database.cc @@ -64,6 +64,9 @@ static bool GetFileDescriptorProto(PyObject* py_descriptor, } return false; } + if (py_descriptor == Py_None) { + return false; + } const Descriptor* filedescriptor_descriptor = FileDescriptorProto::default_instance().GetDescriptor(); CMessage* message = reinterpret_cast(py_descriptor); diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h index d92cf956..1e7f6f7b 100644 --- a/python/google/protobuf/pyext/extension_dict.h +++ b/python/google/protobuf/pyext/extension_dict.h @@ -48,7 +48,7 @@ class Message; class FieldDescriptor; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/map_container.h b/python/google/protobuf/pyext/map_container.h index ddf94be7..27ee6dbd 100644 --- a/python/google/protobuf/pyext/map_container.h +++ b/python/google/protobuf/pyext/map_container.h @@ -47,7 +47,7 @@ namespace protobuf { class Message; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 60ec9c1b..a8248888 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -1851,8 +1851,12 @@ static PyObject* ToStr(CMessage* self) { PyObject* MergeFrom(CMessage* self, PyObject* arg) { CMessage* other_message; - if (!PyObject_TypeCheck(reinterpret_cast(arg), &CMessage_Type)) { - PyErr_SetString(PyExc_TypeError, "Must be a message"); + if (!PyObject_TypeCheck(arg, &CMessage_Type)) { + PyErr_Format(PyExc_TypeError, + "Parameter to MergeFrom() must be instance of same class: " + "expected %s got %s.", + self->message->GetDescriptor()->full_name().c_str(), + Py_TYPE(arg)->tp_name); return NULL; } @@ -1860,8 +1864,8 @@ PyObject* MergeFrom(CMessage* self, PyObject* arg) { if (other_message->message->GetDescriptor() != self->message->GetDescriptor()) { PyErr_Format(PyExc_TypeError, - "Tried to merge from a message with a different type. " - "to: %s, from: %s", + "Parameter to MergeFrom() must be instance of same class: " + "expected %s got %s.", self->message->GetDescriptor()->full_name().c_str(), other_message->message->GetDescriptor()->full_name().c_str()); return NULL; @@ -1879,8 +1883,12 @@ PyObject* MergeFrom(CMessage* self, PyObject* arg) { static PyObject* CopyFrom(CMessage* self, PyObject* arg) { CMessage* other_message; - if (!PyObject_TypeCheck(reinterpret_cast(arg), &CMessage_Type)) { - PyErr_SetString(PyExc_TypeError, "Must be a message"); + if (!PyObject_TypeCheck(arg, &CMessage_Type)) { + PyErr_Format(PyExc_TypeError, + "Parameter to CopyFrom() must be instance of same class: " + "expected %s got %s.", + self->message->GetDescriptor()->full_name().c_str(), + Py_TYPE(arg)->tp_name); return NULL; } @@ -1893,8 +1901,8 @@ static PyObject* CopyFrom(CMessage* self, PyObject* arg) { if (other_message->message->GetDescriptor() != self->message->GetDescriptor()) { PyErr_Format(PyExc_TypeError, - "Tried to copy from a message with a different type. " - "to: %s, from: %s", + "Parameter to CopyFrom() must be instance of same class: " + "expected %s got %s.", self->message->GetDescriptor()->full_name().c_str(), other_message->message->GetDescriptor()->full_name().c_str()); return NULL; @@ -2132,7 +2140,11 @@ static PyObject* ListFields(CMessage* self) { PyList_SET_ITEM(all_fields.get(), actual_size, t.release()); ++actual_size; } - Py_SIZE(all_fields.get()) = actual_size; + if (actual_size != fields.size() && + (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), NULL) < + 0)) { + return NULL; + } return all_fields.release(); } @@ -2711,7 +2723,7 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) { PyErr_Format(PyExc_AttributeError, "Assignment not allowed " - "(no field \"%s\"in protocol message object).", + "(no field \"%s\" in protocol message object).", PyString_AsString(name)); return -1; } @@ -2728,7 +2740,7 @@ PyTypeObject CMessage_Type = { 0, // tp_getattr 0, // tp_setattr 0, // tp_compare - 0, // tp_repr + (reprfunc)cmessage::ToStr, // tp_repr 0, // tp_as_number 0, // tp_as_sequence 0, // tp_as_mapping diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index cc0012e9..c2b62649 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -53,8 +53,8 @@ class DescriptorPool; class MessageFactory; #ifdef _SHARED_PTR_H -using std::shared_ptr; -using std::string; +using shared_ptr; +using std::std::string; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h index 58d37b02..442ce7e3 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.h +++ b/python/google/protobuf/pyext/repeated_composite_container.h @@ -50,7 +50,7 @@ class FieldDescriptor; class Message; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h index 555e621c..608222e0 100644 --- a/python/google/protobuf/pyext/repeated_scalar_container.h +++ b/python/google/protobuf/pyext/repeated_scalar_container.h @@ -49,7 +49,7 @@ namespace protobuf { class Message; #ifdef _SHARED_PTR_H -using std::shared_ptr; +using shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py index 8d256076..a6f41ca8 100755 --- a/python/google/protobuf/text_format.py +++ b/python/google/protobuf/text_format.py @@ -384,7 +384,7 @@ def _MergeField(tokenizer, field are permitted, e.g., the string "foo: 1 foo: 2" for a required/optional field named "foo". allow_unknown_extension: if True, skip over missing extensions and keep - parsing + parsing. Raises: ParseError: In case of text parsing problems. @@ -442,55 +442,39 @@ def _MergeField(tokenizer, 'Message type "%s" has no field named "%s".' % ( message_descriptor.full_name, name)) - if field and field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - is_map_entry = _IsMapEntry(field) - tokenizer.TryConsume(':') + if field: + if not allow_multiple_scalars and field.containing_oneof: + # Check if there's a different field set in this oneof. + # Note that we ignore the case if the same field was set before, and we + # apply allow_multiple_scalars to non-scalar fields as well. + which_oneof = message.WhichOneof(field.containing_oneof.name) + if which_oneof is not None and which_oneof != field.name: + raise tokenizer.ParseErrorPreviousToken( + 'Field "%s" is specified along with field "%s", another member of ' + 'oneof "%s" for message type "%s".' % ( + field.name, which_oneof, field.containing_oneof.name, + message_descriptor.full_name)) - if tokenizer.TryConsume('<'): - end_token = '>' + if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + tokenizer.TryConsume(':') + merger = _MergeMessageField else: - tokenizer.Consume('{') - end_token = '}' + tokenizer.Consume(':') + merger = _MergeScalarField - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - if field.is_extension: - sub_message = message.Extensions[field].add() - elif is_map_entry: - sub_message = field.message_type._concrete_class() - else: - sub_message = getattr(message, field.name).add() - else: - if field.is_extension: - sub_message = message.Extensions[field] - else: - sub_message = getattr(message, field.name) - sub_message.SetInParent() - - while not tokenizer.TryConsume(end_token): - if tokenizer.AtEnd(): - raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token)) - _MergeField(tokenizer, sub_message, allow_multiple_scalars, - allow_unknown_extension) - - if is_map_entry: - value_cpptype = field.message_type.fields_by_name['value'].cpp_type - if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - value = getattr(message, field.name)[sub_message.key] - value.MergeFrom(sub_message.value) - else: - getattr(message, field.name)[sub_message.key] = sub_message.value - elif field: - tokenizer.Consume(':') - if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and - tokenizer.TryConsume('[')): + if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED + and tokenizer.TryConsume('[')): # Short repeated format, e.g. "foo: [1, 2, 3]" while True: - _MergeScalarField(tokenizer, message, field, allow_multiple_scalars) - if tokenizer.TryConsume(']'): - break + merger(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension) + if tokenizer.TryConsume(']'): break tokenizer.Consume(',') + else: - _MergeScalarField(tokenizer, message, field, allow_multiple_scalars) + merger(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension) + else: # Proto field is unknown. assert allow_unknown_extension _SkipFieldContents(tokenizer) @@ -585,8 +569,64 @@ def _SkipFieldValue(tokenizer): raise ParseError('Invalid field value: ' + tokenizer.token) -def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars): - """Merges a single protocol message scalar field into a message. +def _MergeMessageField(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension): + """Merges a single scalar field into a message. + + Args: + tokenizer: A tokenizer to parse the field value. + message: The message of which field is a member. + field: The descriptor of the field to be merged. + allow_multiple_scalars: Determines if repeated values for a non-repeated + field are permitted, e.g., the string "foo: 1 foo: 2" for a + required/optional field named "foo". + allow_unknown_extension: if True, skip over missing extensions and keep + parsing. + + Raises: + ParseError: In case of text parsing problems. + """ + is_map_entry = _IsMapEntry(field) + + if tokenizer.TryConsume('<'): + end_token = '>' + else: + tokenizer.Consume('{') + end_token = '}' + + if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if field.is_extension: + sub_message = message.Extensions[field].add() + elif is_map_entry: + # pylint: disable=protected-access + sub_message = field.message_type._concrete_class() + else: + sub_message = getattr(message, field.name).add() + else: + if field.is_extension: + sub_message = message.Extensions[field] + else: + sub_message = getattr(message, field.name) + sub_message.SetInParent() + + while not tokenizer.TryConsume(end_token): + if tokenizer.AtEnd(): + raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token,)) + _MergeField(tokenizer, sub_message, allow_multiple_scalars, + allow_unknown_extension) + + if is_map_entry: + value_cpptype = field.message_type.fields_by_name['value'].cpp_type + if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + value = getattr(message, field.name)[sub_message.key] + value.MergeFrom(sub_message.value) + else: + getattr(message, field.name)[sub_message.key] = sub_message.value + + +def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars, + allow_unknown_extension): + """Merges a single scalar field into a message. Args: tokenizer: A tokenizer to parse the field value. @@ -595,11 +635,14 @@ def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars): allow_multiple_scalars: Determines if repeated values for a non-repeated field are permitted, e.g., the string "foo: 1 foo: 2" for a required/optional field named "foo". + allow_unknown_extension: Unused, just here for consistency with + _MergeMessageField. Raises: ParseError: In case of text parsing problems. RuntimeError: On runtime errors. """ + _ = allow_unknown_extension value = None if field.type in (descriptor.FieldDescriptor.TYPE_INT32, diff --git a/src/google/protobuf/any.cc b/src/google/protobuf/any.cc index f3ca06bf..f7b1d310 100644 --- a/src/google/protobuf/any.cc +++ b/src/google/protobuf/any.cc @@ -35,10 +35,15 @@ namespace protobuf { namespace internal { namespace { -string GetTypeUrl(const Descriptor* message) { - return string(kTypeGoogleApisComPrefix) + message->full_name(); +string GetTypeUrl(const Descriptor* message, + const string& type_url_prefix) { + if (!type_url_prefix.empty() && + type_url_prefix[type_url_prefix.size() - 1] == '/') { + return type_url_prefix + message->full_name(); + } else { + return type_url_prefix + "/" + message->full_name(); + } } - } // namespace const char kAnyFullTypeName[] = "google.protobuf.Any"; @@ -50,8 +55,13 @@ AnyMetadata::AnyMetadata(UrlType* type_url, ValueType* value) } void AnyMetadata::PackFrom(const Message& message) { + PackFrom(message, kTypeGoogleApisComPrefix); +} + +void AnyMetadata::PackFrom(const Message& message, + const string& type_url_prefix) { type_url_->SetNoArena(&::google::protobuf::internal::GetEmptyString(), - GetTypeUrl(message.GetDescriptor())); + GetTypeUrl(message.GetDescriptor(), type_url_prefix)); message.SerializeToString(value_->MutableNoArena( &::google::protobuf::internal::GetEmptyStringAlreadyInited())); } @@ -67,30 +77,20 @@ bool AnyMetadata::UnpackTo(Message* message) const { bool AnyMetadata::InternalIs(const Descriptor* descriptor) const { const string type_url = type_url_->GetNoArena( &::google::protobuf::internal::GetEmptyString()); - const string full_name = descriptor->full_name(); - if (type_url.length() < full_name.length()) { - return false; + string full_name; + if (!ParseAnyTypeUrl(type_url, &full_name)) { + return false; } - return (0 == type_url.compare( - type_url.length() - full_name.length(), - full_name.length(), - full_name)); + return full_name == descriptor->full_name(); } bool ParseAnyTypeUrl(const string& type_url, string* full_type_name) { - static const char* prefix[] = { - kTypeGoogleApisComPrefix, - kTypeGoogleProdComPrefix - }; - for (int i = 0; i < 2; i++) { - const int prefix_len = strlen(prefix[i]); - if (strncmp(type_url.c_str(), prefix[i], prefix_len) == 0) { - full_type_name->assign(type_url.data() + prefix_len, - type_url.size() - prefix_len); - return true; - } + size_t pos = type_url.find_last_of("/"); + if (pos == string::npos || pos + 1 == type_url.size()) { + return false; } - return false; + *full_type_name = type_url.substr(pos + 1); + return true; } diff --git a/src/google/protobuf/any.h b/src/google/protobuf/any.h index c8dbef13..04e54166 100644 --- a/src/google/protobuf/any.h +++ b/src/google/protobuf/any.h @@ -50,10 +50,26 @@ class LIBPROTOBUF_EXPORT AnyMetadata { // AnyMetadata does not take ownership of "type_url" and "value". AnyMetadata(UrlType* type_url, ValueType* value); + // Packs a message using the default type URL prefix: "type.googleapis.com". + // The resulted type URL will be "type.googleapis.com/". void PackFrom(const Message& message); + // Packs a message using the given type URL prefix. The type URL will be + // constructed by concatenating the message type's full name to the prefix + // with an optional "/" separator if the prefix doesn't already end up "/". + // For example, both PackFrom(message, "type.googleapis.com") and + // PackFrom(message, "type.googleapis.com/") yield the same result type + // URL: "type.googleapis.com/". + void PackFrom(const Message& message, const string& type_url_prefix); + // Unpacks the payload into the given message. Returns false if the message's + // type doesn't match the type specified in the type URL (i.e., the full + // name after the last "/" of the type URL doesn't match the message's actaul + // full name) or parsing the payload has failed. bool UnpackTo(Message* message) const; + // Checks whether the type specified in the type URL matches the given type. + // A type is consdiered matching if its full name matches the full name after + // the last "/" in the type URL. template bool Is() const { return InternalIs(T::default_instance().GetDescriptor()); diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc index 0bf523b3..e8878ba4 100644 --- a/src/google/protobuf/any.pb.cc +++ b/src/google/protobuf/any.pb.cc @@ -83,9 +83,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fany_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\031google/protobuf/any.proto\022\017google.prot" "obuf\"&\n\003Any\022\020\n\010type_url\030\001 \001(\t\022\r\n\005value\030\002" - " \001(\014BK\n\023com.google.protobufB\010AnyProtoP\001\240" - "\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownType" - "sb\006proto3", 169); + " \001(\014Br\n\023com.google.protobufB\010AnyProtoP\001Z" + "%github.com/golang/protobuf/ptypes/any\240\001" + "\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes" + "b\006proto3", 208); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/any.proto", &protobuf_RegisterTypes); Any::default_instance_ = new Any(); @@ -116,6 +117,11 @@ void Any::PackFrom(const ::google::protobuf::Message& message) { _any_metadata_.PackFrom(message); } +void Any::PackFrom(const ::google::protobuf::Message& message, + const ::std::string& type_url_prefix) { + _any_metadata_.PackFrom(message, type_url_prefix); +} + bool Any::UnpackTo(::google::protobuf::Message* message) const { return _any_metadata_.UnpackTo(message); } diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index 97982ecf..82c70ad9 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -60,6 +60,8 @@ class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message { // implements Any ----------------------------------------------- void PackFrom(const ::google::protobuf::Message& message); + void PackFrom(const ::google::protobuf::Message& message, + const ::std::string& type_url_prefix); bool UnpackTo(::google::protobuf::Message* message) const; template bool Is() const { return _any_metadata_.Is(); diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto index e8a18bc3..47d288c3 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -33,14 +33,43 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/any"; option java_package = "com.google.protobuf"; option java_outer_classname = "AnyProto"; option java_multiple_files = true; option java_generate_equals_and_hash = true; option objc_class_prefix = "GPB"; -// `Any` contains an arbitrary serialized message along with a URL -// that describes the type of the serialized message. +// `Any` contains an arbitrary serialized protocol buffer message along with a +// URL that describes the type of the serialized message. +// +// Protobuf library provides support to pack/unpack Any values in the form +// of utility functions or additional generated methods of the Any type. +// +// Example 1: Pack and unpack a message in C++. +// +// Foo foo = ...; +// Any any; +// any.PackFrom(foo); +// ... +// if (any.UnpackTo(&foo)) { +// ... +// } +// +// Example 2: Pack and unpack a message in Java. +// +// Foo foo = ...; +// Any any = Any.pack(foo); +// ... +// if (any.is(Foo.class)) { +// foo = any.unpack(Foo.class); +// } +// +// The pack methods provided by protobuf library will by default use +// 'type.googleapis.com/full.type.name' as the type URL and the unpack +// methods only use the fully qualified type name after the last '/' +// in the type URL, for example "foo.bar.com/x/y.z" will yield type +// name "y.z". // // // JSON @@ -73,7 +102,7 @@ option objc_class_prefix = "GPB"; // message Any { // A URL/resource name whose content describes the type of the - // serialized message. + // serialized protocol buffer message. // // For URLs which use the schema `http`, `https`, or no schema, the // following restrictions and interpretations apply: @@ -94,6 +123,6 @@ message Any { // string type_url = 1; - // Must be valid serialized data of the above specified type. + // Must be a valid serialized protocol buffer of the above specified type. bytes value = 2; } diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index cd0b21a7..e856f5b1 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -37,6 +37,7 @@ namespace google { namespace protobuf { + google::protobuf::internal::SequenceNumber Arena::lifecycle_id_generator_; #if defined(GOOGLE_PROTOBUF_NO_THREADLOCAL) Arena::ThreadCache& Arena::thread_cache() { diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index 5ad94fa9..9ab0a0f9 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -56,6 +56,7 @@ using type_info = ::type_info; #include #include + namespace google { namespace protobuf { @@ -230,6 +231,7 @@ class LIBPROTOBUF_EXPORT Arena { // if it was passed in. ~Arena(); + // API to create proto2 message objects on the arena. If the arena passed in // is NULL, then a heap allocated object is returned. Type T must be a message // defined in a .proto file with cc_enable_arenas set to true, otherwise a @@ -507,11 +509,11 @@ class LIBPROTOBUF_EXPORT Arena { // // This is inside Arena because only Arena has the friend relationships // necessary to see the underlying generated code traits. - template - struct is_arena_constructable : - public google::protobuf::internal::integral_constant(static_cast(0))) == sizeof(char)> { + template + struct is_arena_constructable + : public google::protobuf::internal::integral_constant< + bool, sizeof(InternalIsArenaConstructableHelper::ArenaConstructable< + const T>(static_cast(0))) == sizeof(char)> { }; private: diff --git a/src/google/protobuf/arena_nc_test.py b/src/google/protobuf/arena_nc_test.py index 87a69b2a..56a7dd05 100644 --- a/src/google/protobuf/arena_nc_test.py +++ b/src/google/protobuf/arena_nc_test.py @@ -35,7 +35,7 @@ import unittest from google3.testing.pybase import fake_target_util -import unittest +from google3.testing.pybase import unittest class ArenaNcTest(unittest.TestCase): diff --git a/src/google/protobuf/arenastring.h b/src/google/protobuf/arenastring.h index e2e2f254..590ffce9 100755 --- a/src/google/protobuf/arenastring.h +++ b/src/google/protobuf/arenastring.h @@ -134,7 +134,8 @@ struct LIBPROTOBUF_EXPORT ArenaStringPtr { // UnsafeArenaRelease() on another field of a message in the same arena. Used // to implement unsafe_arena_set_allocated_ in generated classes. inline void UnsafeArenaSetAllocated(const ::std::string* default_value, - ::std::string* value, ::google::protobuf::Arena* /* arena */) { + ::std::string* value, + ::google::protobuf::Arena* /* arena */) { if (value != NULL) { ptr_ = value; } else { diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 3a816b05..87843f62 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -49,7 +49,7 @@ #include #include -#ifdef GOOGLE_PROTOBUF_ARCH_SPARC +#ifdef GOOGLE_PROTOBUF_ARCH_SPARC #include //For PATH_MAX #endif diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index dda007d4..e3dd2295 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -63,13 +63,13 @@ #include #include -namespace google { -namespace protobuf { -namespace compiler { // Disable the whole test when we use tcmalloc for "draconian" heap checks, in // which case tcmalloc will print warnings that fail the plugin tests. #if !GOOGLE_PROTOBUF_HEAP_CHECK_DRACONIAN +namespace google { +namespace protobuf { +namespace compiler { #if defined(_WIN32) #ifndef STDIN_FILENO diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 5ee6f000..415ae60f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -69,11 +69,12 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, EnumGenerator::~EnumGenerator() {} -void EnumGenerator::FillForwardDeclaration(set* enum_names) { +void EnumGenerator::FillForwardDeclaration( + map* enum_names) { if (!options_.proto_h) { return; } - enum_names->insert(classname_); + (*enum_names)[classname_] = descriptor_; } void EnumGenerator::GenerateDefinition(io::Printer* printer) { @@ -83,6 +84,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { vars["enumbase"] = classname_ + (options_.proto_h ? " : int" : ""); printer->Print(vars, "enum $enumbase$ {\n"); + printer->Annotate("enumbase", descriptor_); printer->Indent(); const EnumValueDescriptor* min_value = descriptor_->value(0); diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index f3aa72e4..61e40346 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -64,8 +64,10 @@ class EnumGenerator { // Fills the name to use when declaring the enum. This is for use when // generating other .proto.h files. This code should be placed within the // enum's package namespace, but NOT within any class, even for nested - // enums. - void FillForwardDeclaration(set* enum_names); + // enums. A given key in enum_names will map from an enum class name to the + // EnumDescriptor that was responsible for its inclusion in the map. This can + // be used to associate the descriptor with the code generated for it. + void FillForwardDeclaration(map* enum_names); // Generate header code defining the enum. This code should be placed // within the enum's package namespace, but NOT within any class, even for diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 37e4bae4..d48171b0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -94,7 +94,8 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) FileGenerator::~FileGenerator() {} -void FileGenerator::GenerateProtoHeader(io::Printer* printer) { +void FileGenerator::GenerateProtoHeader(io::Printer* printer, + const string& info_path) { if (!options_.proto_h) { return; } @@ -114,6 +115,8 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer) { "dependency", dependency); } + GenerateMetadataPragma(printer, info_path); + printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -167,7 +170,8 @@ void FileGenerator::GenerateProtoHeader(io::Printer* printer) { GenerateBottomHeaderGuard(printer, filename_identifier); } -void FileGenerator::GeneratePBHeader(io::Printer* printer) { +void FileGenerator::GeneratePBHeader(io::Printer* printer, + const string& info_path) { string filename_identifier = FilenameIdentifier(file_->name() + (options_.proto_h ? ".pb.h" : "")); GenerateTopHeaderGuard(printer, filename_identifier); @@ -179,6 +183,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) { GenerateLibraryIncludes(printer); } GenerateDependencyIncludes(printer); + GenerateMetadataPragma(printer, info_path); printer->Print( "// @@protoc_insertion_point(includes)\n"); @@ -237,7 +242,7 @@ void FileGenerator::GeneratePBHeader(io::Printer* printer) { } void FileGenerator::GenerateSource(io::Printer* printer) { - bool well_known = IsWellKnownMessage(file_); + const bool use_system_include = IsWellKnownMessage(file_); string header = StripProto(file_->name()) + (options_.proto_h ? ".proto.h" : ".pb.h"); printer->Print( @@ -258,8 +263,8 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include \n", "filename", file_->name(), "header", header, - "left", well_known ? "<" : "\"", - "right", well_known ? ">" : "\""); + "left", use_system_include ? "<" : "\"", + "right", use_system_include ? ">" : "\""); // Unknown fields implementation in lite mode uses StringOutputStream if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { @@ -401,20 +406,24 @@ class FileGenerator::ForwardDeclarations { return ns; } - set& classes() { return classes_; } - set& enums() { return enums_; } + map& classes() { return classes_; } + map& enums() { return enums_; } void Print(io::Printer* printer) const { - for (set::const_iterator it = enums_.begin(), end = enums_.end(); + for (map::const_iterator + it = enums_.begin(), + end = enums_.end(); it != end; ++it) { - printer->Print("enum $enumname$ : int;\n" - "bool $enumname$_IsValid(int value);\n", - "enumname", it->c_str()); + printer->Print("enum $enumname$ : int;\n", "enumname", it->first); + printer->Annotate("enumname", it->second); + printer->Print("bool $enumname$_IsValid(int value);\n", "enumname", + it->first); } - for (set::const_iterator it = classes_.begin(), - end = classes_.end(); + for (map::const_iterator it = classes_.begin(), + end = classes_.end(); it != end; ++it) { - printer->Print("class $classname$;\n", "classname", it->c_str()); + printer->Print("class $classname$;\n", "classname", it->first); + printer->Annotate("classname", it->second); } for (map::const_iterator it = namespaces_.begin(), @@ -431,8 +440,8 @@ class FileGenerator::ForwardDeclarations { private: map namespaces_; - set classes_; - set enums_; + map classes_; + map enums_; }; void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { @@ -854,6 +863,19 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { } } +void FileGenerator::GenerateMetadataPragma(io::Printer* printer, + const string& info_path) { + if (!info_path.empty() && !options_.annotation_pragma_name.empty() && + !options_.annotation_guard_name.empty()) { + printer->Print( + "#ifdef $guard$\n" + "#pragma $pragma$ \"$info_path$\"\n" + "#endif // $guard$\n", + "guard", options_.annotation_guard_name, "pragma", + options_.annotation_pragma_name, "info_path", info_path); + } +} + void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { set public_import_names; for (int i = 0; i < file_->public_dependency_count(); i++) { @@ -861,16 +883,17 @@ void FileGenerator::GenerateDependencyIncludes(io::Printer* printer) { } for (int i = 0; i < file_->dependency_count(); i++) { - bool well_known = IsWellKnownMessage(file_->dependency(i)); + const bool use_system_include = IsWellKnownMessage(file_->dependency(i)); const string& name = file_->dependency(i)->name(); bool public_import = (public_import_names.count(name) != 0); + printer->Print( "#include $left$$dependency$.pb.h$right$$iwyu$\n", "dependency", StripProto(name), "iwyu", (public_import) ? " // IWYU pragma: export" : "", - "left", well_known ? "<" : "\"", - "right", well_known ? ">" : "\""); + "left", use_system_include ? "<" : "\"", + "right", use_system_include ? ">" : "\""); } } @@ -897,13 +920,15 @@ void FileGenerator::GenerateGlobalStateFunctionDeclarations( } void FileGenerator::GenerateMessageForwardDeclarations(io::Printer* printer) { - set classes; + map classes; for (int i = 0; i < file_->message_type_count(); i++) { message_generators_[i]->FillMessageForwardDeclarations(&classes); } - for (set::const_iterator it = classes.begin(), end = classes.end(); + for (map::const_iterator it = classes.begin(), + end = classes.end(); it != end; ++it) { - printer->Print("class $classname$;\n", "classname", it->c_str()); + printer->Print("class $classname$;\n", "classname", it->first); + printer->Annotate("classname", it->second); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index 29cdaea5..ebe990c2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -69,8 +69,14 @@ class FileGenerator { const Options& options); ~FileGenerator(); - void GenerateProtoHeader(io::Printer* printer); - void GeneratePBHeader(io::Printer* printer); + // info_path, if non-empty, should be the path (relative to printer's output) + // to the metadata file describing this proto header. + void GenerateProtoHeader(io::Printer* printer, + const string& info_path); + // info_path, if non-empty, should be the path (relative to printer's output) + // to the metadata file describing this PB header. + void GeneratePBHeader(io::Printer* printer, + const string& info_path); void GenerateSource(io::Printer* printer); private: @@ -102,6 +108,10 @@ class FileGenerator { void GenerateLibraryIncludes(io::Printer* printer); void GenerateDependencyIncludes(io::Printer* printer); + // Generate a pragma to pull in metadata using the given info_path (if + // non-empty). info_path should be relative to printer's output. + void GenerateMetadataPragma(io::Printer* printer, const string& info_path); + // Generates a couple of different pieces before definitions: void GenerateGlobalStateFunctionDeclarations(io::Printer* printer); diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index 781526b5..c7aec93a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -90,6 +90,12 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.dllexport_decl = options[i].second; } else if (options[i].first == "safe_boundary_check") { file_options.safe_boundary_check = true; + } else if (options[i].first == "annotate_headers") { + file_options.annotate_headers = true; + } else if (options[i].first == "annotation_pragma_name") { + file_options.annotation_pragma_name = options[i].second; + } else if (options[i].first == "annotation_guard_name") { + file_options.annotation_guard_name = options[i].second; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -107,16 +113,40 @@ bool CppGenerator::Generate(const FileDescriptor* file, if (file_options.proto_h) { google::protobuf::scoped_ptr output( generator_context->Open(basename + ".proto.h")); - io::Printer printer(output.get(), '$'); - file_generator.GenerateProtoHeader(&printer); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector annotation_collector( + &annotations); + string info_path = basename + ".proto.h.meta"; + io::Printer printer(output.get(), '$', file_options.annotate_headers + ? &annotation_collector + : NULL); + file_generator.GenerateProtoHeader( + &printer, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { + scoped_ptr info_output( + generator_context->Open(info_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + } } basename.append(".pb"); { google::protobuf::scoped_ptr output( generator_context->Open(basename + ".h")); - io::Printer printer(output.get(), '$'); - file_generator.GeneratePBHeader(&printer); + GeneratedCodeInfo annotations; + io::AnnotationProtoCollector annotation_collector( + &annotations); + string info_path = basename + ".h.meta"; + io::Printer printer(output.get(), '$', file_options.annotate_headers + ? &annotation_collector + : NULL); + file_generator.GeneratePBHeader( + &printer, file_options.annotate_headers ? info_path : ""); + if (file_options.annotate_headers) { + scoped_ptr info_output( + generator_context->Open(info_path)); + annotations.SerializeToZeroCopyStream(info_output.get()); + } } // Generate cc file. diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 8304ebbd..c3166611 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -423,8 +423,8 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor, MessageGenerator::~MessageGenerator() {} void MessageGenerator:: -FillMessageForwardDeclarations(set* class_names) { - class_names->insert(classname_); +FillMessageForwardDeclarations(map* class_names) { + (*class_names)[classname_] = descriptor_; for (int i = 0; i < descriptor_->nested_type_count(); i++) { // map entry message doesn't need forward declaration. Since map entry @@ -436,7 +436,7 @@ FillMessageForwardDeclarations(set* class_names) { } void MessageGenerator:: -FillEnumForwardDeclarations(set* enum_names) { +FillEnumForwardDeclarations(map* enum_names) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->FillEnumForwardDeclarations(enum_names); } @@ -892,6 +892,7 @@ GenerateClassDefinition(io::Printer* printer) { } printer->Print(vars, "class $dllexport$$classname$ : public $superclass$ {\n"); + printer->Annotate("classname", descriptor_); if (use_dependent_base_) { printer->Print(vars, " friend class $superclass$;\n"); } @@ -1027,6 +1028,8 @@ GenerateClassDefinition(io::Printer* printer) { "// implements Any -----------------------------------------------\n" "\n" "void PackFrom(const ::google::protobuf::Message& message);\n" + "void PackFrom(const ::google::protobuf::Message& message,\n" + " const ::std::string& type_url_prefix);\n" "bool UnpackTo(::google::protobuf::Message* message) const;\n" "template bool Is() const {\n" " return _any_metadata_.Is();\n" @@ -1789,6 +1792,11 @@ GenerateClassMethods(io::Printer* printer) { " _any_metadata_.PackFrom(message);\n" "}\n" "\n" + "void $classname$::PackFrom(const ::google::protobuf::Message& message,\n" + " const ::std::string& type_url_prefix) {\n" + " _any_metadata_.PackFrom(message, type_url_prefix);\n" + "}\n" + "\n" "bool $classname$::UnpackTo(::google::protobuf::Message* message) const {\n" " return _any_metadata_.UnpackTo(message);\n" "}\n" @@ -1899,11 +1907,10 @@ GenerateClassMethods(io::Printer* printer) { void MessageGenerator:: GenerateOffsets(io::Printer* printer) { - printer->Print( - "static const int $classname$_offsets_[$field_count$] = {\n", - "classname", classname_, - "field_count", SimpleItoa(max( - 1, descriptor_->field_count() + descriptor_->oneof_decl_count()))); + printer->Print("static const int $classname$_offsets_[$field_count$] = {\n", + "classname", classname_, "field_count", + SimpleItoa(std::max(1, descriptor_->field_count() + + descriptor_->oneof_decl_count()))); printer->Indent(); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -2907,7 +2914,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // on the CodedOutputStream. printer->Print( " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" - " ::google::protobuf::internal::NewPermanentCallback(\n" + " google::protobuf::internal::NewPermanentCallback(\n" " &MutableUnknownFieldsFor$classname$, this));\n" " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" " &unknown_fields_string, false);\n", diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index 8e19a3f0..31223e13 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -67,9 +67,13 @@ class MessageGenerator { // Header stuff. // Return names for foward declarations of this class and all its nested - // types. - void FillMessageForwardDeclarations(set* class_names); - void FillEnumForwardDeclarations(set* enum_names); + // types. A given key in {class,enum}_names will map from a class name to the + // descriptor that was responsible for its inclusion in the map. This can be + // used to associate the descriptor with the code generated for it. + void FillMessageForwardDeclarations( + map* class_names); + void FillEnumForwardDeclarations( + map* enum_names); // Generate definitions of all nested enums (must come before class // definitions because those classes use the enums definitions). diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index 4463f200..e908362b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -43,11 +43,14 @@ namespace cpp { // Generator options (see generator.cc for a description of each): struct Options { - Options() : safe_boundary_check(false), proto_h(false) { - } + Options() + : safe_boundary_check(false), proto_h(false), annotate_headers(false) {} string dllexport_decl; bool safe_boundary_check; bool proto_h; + bool annotate_headers; + string annotation_pragma_name; + string annotation_guard_name; }; } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 9942a343..148da883 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -82,7 +82,6 @@ namespace google { namespace protobuf { -using internal::NewPermanentCallback; namespace compiler { namespace cpp { @@ -1253,7 +1252,7 @@ class GeneratedServiceTest : public testing::Test { foo_(descriptor_->FindMethodByName("Foo")), bar_(descriptor_->FindMethodByName("Bar")), stub_(&mock_channel_), - done_(NewPermanentCallback(&DoNothing)) {} + done_(google::protobuf::internal::NewPermanentCallback(&DoNothing)) {} virtual void SetUp() { ASSERT_TRUE(foo_ != NULL); diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc index 422eb73b..61dc283a 100644 --- a/src/google/protobuf/compiler/cpp/metadata_test.cc +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -51,6 +51,189 @@ namespace compiler { namespace cpp { namespace { +// A CodeGenerator that captures the FileDescriptor it's passed as a +// FileDescriptorProto. +class DescriptorCapturingGenerator : public CodeGenerator { + public: + // Does not own file; file must outlive the Generator. + explicit DescriptorCapturingGenerator(FileDescriptorProto* file) + : file_(file) {} + + virtual bool Generate(const FileDescriptor* file, const string& parameter, + GeneratorContext* context, string* error) const { + file->CopyTo(file_); + return true; + } + + private: + FileDescriptorProto* file_; +}; + +class CppMetadataTest : public ::testing::Test { + public: + // Adds a file with name `filename` and content `data`. + void AddFile(const string& filename, const string& data) { + GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/" + filename, data, + true)); + } + + // Tries to capture a FileDescriptorProto, GeneratedCodeInfo, and output + // code from the previously added file with name `filename`. Returns true on + // success. If pb_h is non-null, expects a .pb.h and a .pb.h.meta (copied to + // pb_h and pb_h_info respecfively); similarly for proto_h and proto_h_info. + bool CaptureMetadata(const string& filename, FileDescriptorProto* file, + string* pb_h, GeneratedCodeInfo* pb_h_info, + string* proto_h, GeneratedCodeInfo* proto_h_info, + string* pb_cc) { + google::protobuf::compiler::CommandLineInterface cli; + cli.SetInputsAreProtoPathRelative(true); + + CppGenerator cpp_generator; + DescriptorCapturingGenerator capturing_generator(file); + cli.RegisterGenerator("--cpp_out", &cpp_generator, ""); + cli.RegisterGenerator("--capture_out", &capturing_generator, ""); + + string proto_path = "-I" + TestTempDir(); + string cpp_out = + "--cpp_out=annotate_headers=true," + "annotation_pragma_name=pragma_name," + "annotation_guard_name=guard_name:" + + TestTempDir(); + string capture_out = "--capture_out=" + TestTempDir(); + + const char* argv[] = {"protoc", proto_path.c_str(), cpp_out.c_str(), + capture_out.c_str(), filename.c_str()}; + + if (cli.Run(5, argv) != 0) { + return false; + } + + string output_base = TestTempDir() + "/" + StripProto(filename); + + if (pb_cc != NULL) { + GOOGLE_CHECK_OK( + File::GetContents(output_base + ".pb.cc", pb_cc, true)); + } + + if (pb_h != NULL && pb_h_info != NULL) { + GOOGLE_CHECK_OK( + File::GetContents(output_base + ".pb.h", pb_h, true)); + if (!DecodeMetadata(output_base + ".pb.h.meta", pb_h_info)) { + return false; + } + } + + if (proto_h != NULL && proto_h_info != NULL) { + GOOGLE_CHECK_OK(File::GetContents(output_base + ".proto.h", proto_h, + true)); + if (!DecodeMetadata(output_base + ".proto.h.meta", proto_h_info)) { + return false; + } + } + + return true; + } + + private: + // Decodes GeneratedCodeInfo stored in path and copies it to info. + // Returns true on success. + bool DecodeMetadata(const string& path, GeneratedCodeInfo* info) { + string data; + GOOGLE_CHECK_OK(File::GetContents(path, &data, true)); + io::ArrayInputStream input(data.data(), data.size()); + return info->ParseFromZeroCopyStream(&input); + } +}; + +const char kSmallTestFile[] = + "syntax = \"proto2\";\n" + "package foo;\n" + "enum Enum { VALUE = 0; }\n" + "message Message { }\n"; + +// Finds the Annotation for a given source file and path (or returns null if it +// couldn't). +const GeneratedCodeInfo::Annotation* FindAnnotationOnPath( + const GeneratedCodeInfo& info, const string& source_file, + const vector& path) { + for (int i = 0; i < info.annotation_size(); ++i) { + const GeneratedCodeInfo::Annotation* annotation = &info.annotation(i); + if (annotation->source_file() != source_file || + annotation->path_size() != path.size()) { + continue; + } + int node = 0; + for (; node < path.size(); ++node) { + if (annotation->path(node) != path[node]) { + break; + } + } + if (node == path.size()) { + return annotation; + } + } + return NULL; +} + +// Returns true if the provided annotation covers a given substring in +// file_content. +bool AnnotationMatchesSubstring(const string& file_content, + const GeneratedCodeInfo::Annotation* annotation, + const string& expected_text) { + uint32 begin = annotation->begin(); + uint32 end = annotation->end(); + if (end < begin || end > file_content.size()) { + return false; + } + return file_content.substr(begin, end - begin) == expected_text; +} + +TEST_F(CppMetadataTest, CapturesEnumNames) { + FileDescriptorProto file; + GeneratedCodeInfo info; + string pb_h; + AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_EQ("Enum", file.enum_type(0).name()); + vector enum_path; + enum_path.push_back(FileDescriptorProto::kEnumTypeFieldNumber); + enum_path.push_back(0); + const GeneratedCodeInfo::Annotation* enum_annotation = + FindAnnotationOnPath(info, "test.proto", enum_path); + EXPECT_TRUE(NULL != enum_annotation); + EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, enum_annotation, "Enum")); +} + +TEST_F(CppMetadataTest, AddsPragma) { + FileDescriptorProto file; + GeneratedCodeInfo info; + string pb_h; + AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_TRUE(pb_h.find("#ifdef guard_name") != string::npos); + EXPECT_TRUE(pb_h.find("#pragma pragma_name \"test.pb.h.meta\"") != + string::npos); +} + +TEST_F(CppMetadataTest, CapturesMessageNames) { + FileDescriptorProto file; + GeneratedCodeInfo info; + string pb_h; + AddFile("test.proto", kSmallTestFile); + EXPECT_TRUE( + CaptureMetadata("test.proto", &file, &pb_h, &info, NULL, NULL, NULL)); + EXPECT_EQ("Message", file.message_type(0).name()); + vector message_path; + message_path.push_back(FileDescriptorProto::kMessageTypeFieldNumber); + message_path.push_back(0); + const GeneratedCodeInfo::Annotation* message_annotation = + FindAnnotationOnPath(info, "test.proto", message_path); + EXPECT_TRUE(NULL != message_annotation); + EXPECT_TRUE(AnnotationMatchesSubstring(pb_h, message_annotation, "Message")); +} + } // namespace } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc index 7d21fe61..0a112888 100644 --- a/src/google/protobuf/compiler/java/java_context.cc +++ b/src/google/protobuf/compiler/java/java_context.cc @@ -43,7 +43,7 @@ namespace compiler { namespace java { Context::Context(const FileDescriptor* file) - : name_resolver_(new ClassNameResolver) { + : name_resolver_(new ClassNameResolver), enforce_lite_(false) { InitializeFieldGeneratorInfo(file); } @@ -189,6 +189,13 @@ const OneofGeneratorInfo* Context::GetOneofGeneratorInfo( return result; } +// Does this message class have generated parsing, serialization, and other +// standard methods for which reflection-based fallback implementations exist? +bool Context::HasGeneratedMethods(const Descriptor* descriptor) const { + return enforce_lite_ || descriptor->file()->options().optimize_for() != + FileOptions::CODE_SIZE; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h index 5b595d07..a480e45d 100644 --- a/src/google/protobuf/compiler/java/java_context.h +++ b/src/google/protobuf/compiler/java/java_context.h @@ -46,6 +46,7 @@ namespace protobuf { class FieldDescriptor; class OneofDescriptor; class Descriptor; + class EnumDescriptor; namespace compiler { namespace java { class ClassNameResolver; // name_resolver.h @@ -78,6 +79,20 @@ class Context { const OneofGeneratorInfo* GetOneofGeneratorInfo( const OneofDescriptor* oneof) const; + // Enforces all the files (including transitive dependencies) to use + // LiteRuntime. + void SetEnforceLite(bool enforce_lite) { + enforce_lite_ = enforce_lite; + } + + bool EnforceLite() const { + return enforce_lite_; + } + + // Does this message class have generated parsing, serialization, and other + // standard methods for which reflection-based fallback implementations exist? + bool HasGeneratedMethods(const Descriptor* descriptor) const; + private: void InitializeFieldGeneratorInfo(const FileDescriptor* file); void InitializeFieldGeneratorInfoForMessage(const Descriptor* message); @@ -87,6 +102,7 @@ class Context { google::protobuf::scoped_ptr name_resolver_; map field_generator_info_map_; map oneof_generator_info_map_; + bool enforce_lite_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context); }; diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 5fc9b002..9eea873a 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -64,6 +64,7 @@ EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, bool immutable_api, Context* context) : descriptor_(descriptor), immutable_api_(immutable_api), + context_(context), name_resolver_(context->GetNameResolver()) { for (int i = 0; i < descriptor_->value_count(); i++) { const EnumValueDescriptor* value = descriptor_->value(i); @@ -150,7 +151,15 @@ void EnumGenerator::Generate(io::Printer* printer) { " return value;\n" "}\n" "\n" + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $classname$ forNumber(int value) {\n" " switch (value) {\n", "classname", descriptor_->name()); printer->Indent(); @@ -178,7 +187,7 @@ void EnumGenerator::Generate(io::Printer* printer) { " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" - " return $classname$.valueOf(number);\n" + " return $classname$.forNumber(number);\n" " }\n" " };\n" "\n", @@ -187,7 +196,7 @@ void EnumGenerator::Generate(io::Printer* printer) { // ----------------------------------------------------------------- // Reflection - if (HasDescriptorMethods(descriptor_)) { + if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) { printer->Print( "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n" " getValueDescriptor() {\n" @@ -229,7 +238,7 @@ void EnumGenerator::Generate(io::Printer* printer) { " (com.google.protobuf.Descriptors.FileDescriptor)\n" " m.invoke(immutableFileClass);\n" " return file.getEnumTypes().get($index$);\n" - "} catch (Exception e) {\n" + "} catch (java.lang.Exception e) {\n" // Immutable classes cannot be found. Proceed as if custom options // don't exist. "}\n", @@ -313,7 +322,7 @@ void EnumGenerator::Generate(io::Printer* printer) { "private final int value;\n\n" "private $classname$(int index, int value) {\n", "classname", descriptor_->name()); - if (HasDescriptorMethods(descriptor_)) { + if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) { printer->Print(" this.index = index;\n"); } printer->Print( diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 558da968..3e54be3d 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -68,21 +68,14 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver); (*variables)["default_number"] = SimpleItoa( descriptor->default_value_enum()->number()); - if (descriptor->is_packed()) { - (*variables)["tag"] = SimpleItoa(internal::WireFormatLite::MakeTag( - descriptor->number(), - internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); - } else { - (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); - } + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -198,7 +191,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); } @@ -231,7 +224,7 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -311,7 +304,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -405,7 +398,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -443,7 +436,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -500,7 +493,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -613,7 +606,7 @@ GenerateMembers(io::Printer* printer) const { " new com.google.protobuf.Internal.ListAdapter.Converter<\n" " java.lang.Integer, $type$>() {\n" " public $type$ convert(java.lang.Integer from) {\n" - " $type$ result = $type$.valueOf(from);\n" + " $type$ result = $type$.forNumber(from);\n" " return result == null ? $unknown$ : result;\n" " }\n" " };\n"); @@ -649,7 +642,7 @@ GenerateMembers(io::Printer* printer) const { } if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); } @@ -846,7 +839,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index e3e87c58..5b98637b 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -75,8 +75,6 @@ void SetEnumVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -179,7 +177,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); @@ -228,7 +226,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public Builder set$capitalized_name$Value(int value) {\n" " copyOnWrite();\n" - " instance.set$capitalized_name$Value(int value);\n" + " instance.set$capitalized_name$Value(value);\n" " return this;\n" "}\n"); } @@ -295,7 +293,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -389,7 +387,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -488,7 +486,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -602,7 +600,7 @@ GenerateMembers(io::Printer* printer) const { " new com.google.protobuf.Internal.ListAdapter.Converter<\n" " java.lang.Integer, $type$>() {\n" " public $type$ convert(java.lang.Integer from) {\n" - " $type$ result = $type$.valueOf(from);\n" + " $type$ result = $type$.forNumber(from);\n" " return result == null ? $unknown$ : result;\n" " }\n" " };\n"); @@ -638,7 +636,7 @@ GenerateMembers(io::Printer* printer) const { } if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize;\n"); } @@ -821,7 +819,6 @@ GenerateMergingCode(io::Printer* printer) const { " ensure$capitalized_name$IsMutable();\n" " $name$_.addAll(other.$name$_);\n" " }\n" - " $on_changed$\n" "}\n"); } @@ -844,7 +841,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc index ed415eee..c22da8d7 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_lite.cc @@ -141,7 +141,15 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { " return value;\n" "}\n" "\n" + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $classname$ forNumber(int value) {\n" " switch (value) {\n", "classname", descriptor_->name()); printer->Indent(); @@ -169,7 +177,7 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" - " return $classname$.valueOf(number);\n" + " return $classname$.forNumber(number);\n" " }\n" " };\n" "\n", diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 4db7085e..46b5faaa 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -118,75 +118,38 @@ void ImmutableExtensionGenerator::Generate(io::Printer* printer) { "public static final int $constant_name$ = $number$;\n"); WriteFieldDocComment(printer, descriptor_); - if (HasDescriptorMethods(descriptor_->file())) { - // Non-lite extensions - if (descriptor_->extension_scope() == NULL) { - // Non-nested - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" - " .newFileScopedGeneratedExtension(\n" - " $singular_type$.class,\n" - " $prototype$);\n"); - } else { - // Nested - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" - " .newMessageScopedGeneratedExtension(\n" - " $scope$.getDefaultInstance(),\n" - " $index$,\n" - " $singular_type$.class,\n" - " $prototype$);\n"); - } + if (descriptor_->extension_scope() == NULL) { + // Non-nested + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" + " .newFileScopedGeneratedExtension(\n" + " $singular_type$.class,\n" + " $prototype$);\n"); } else { - // Lite extensions - if (descriptor_->is_repeated()) { - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" - " .newRepeatedGeneratedExtension(\n" - " $containing_type$.getDefaultInstance(),\n" - " $prototype$,\n" - " $enum_map$,\n" - " $number$,\n" - " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" - " $packed$,\n" - " $singular_type$.class);\n"); - } else { - printer->Print( - vars, - "public static final\n" - " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" - " $containing_type$,\n" - " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" - " .newSingularGeneratedExtension(\n" - " $containing_type$.getDefaultInstance(),\n" - " $default$,\n" - " $prototype$,\n" - " $enum_map$,\n" - " $number$,\n" - " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" - " $singular_type$.class);\n"); - } + // Nested + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessage\n" + " .newMessageScopedGeneratedExtension(\n" + " $scope$.getDefaultInstance(),\n" + " $index$,\n" + " $singular_type$.class,\n" + " $prototype$);\n"); } } int ImmutableExtensionGenerator::GenerateNonNestedInitializationCode( io::Printer* printer) { int bytecode_estimate = 0; - if (descriptor_->extension_scope() == NULL && - HasDescriptorMethods(descriptor_->file())) { - // Only applies to non-nested, non-lite extensions. + if (descriptor_->extension_scope() == NULL) { + // Only applies to non-nested extensions. printer->Print( "$name$.internalInit(descriptor.getExtensions().get($index$));\n", "name", UnderscoresToCamelCase(descriptor_), diff --git a/src/google/protobuf/compiler/java/java_extension_lite.cc b/src/google/protobuf/compiler/java/java_extension_lite.cc index e69de29b..23261bac 100644 --- a/src/google/protobuf/compiler/java/java_extension_lite.cc +++ b/src/google/protobuf/compiler/java/java_extension_lite.cc @@ -0,0 +1,118 @@ +// 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 + +#include +#include +#include +#include +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +ImmutableExtensionLiteGenerator::ImmutableExtensionLiteGenerator( + const FieldDescriptor* descriptor, Context* context) + : descriptor_(descriptor), context_(context), + name_resolver_(context->GetNameResolver()) { + if (descriptor_->extension_scope() != NULL) { + scope_ = name_resolver_->GetImmutableClassName( + descriptor_->extension_scope()); + } else { + scope_ = name_resolver_->GetImmutableClassName(descriptor_->file()); + } +} + +ImmutableExtensionLiteGenerator::~ImmutableExtensionLiteGenerator() {} + +void ImmutableExtensionLiteGenerator::Generate(io::Printer* printer) { + map vars; + const bool kUseImmutableNames = true; + InitTemplateVars(descriptor_, scope_, kUseImmutableNames, name_resolver_, + &vars); + printer->Print(vars, + "public static final int $constant_name$ = $number$;\n"); + + WriteFieldDocComment(printer, descriptor_); + if (descriptor_->is_repeated()) { + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" + " .newRepeatedGeneratedExtension(\n" + " $containing_type$.getDefaultInstance(),\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $packed$,\n" + " $singular_type$.class);\n"); + } else { + printer->Print( + vars, + "public static final\n" + " com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" + " $containing_type$,\n" + " $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" + " .newSingularGeneratedExtension(\n" + " $containing_type$.getDefaultInstance(),\n" + " $default$,\n" + " $prototype$,\n" + " $enum_map$,\n" + " $number$,\n" + " com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" + " $singular_type$.class);\n"); + } +} + +int ImmutableExtensionLiteGenerator::GenerateNonNestedInitializationCode( + io::Printer* printer) { + return 0; +} + +int ImmutableExtensionLiteGenerator::GenerateRegistrationCode( + io::Printer* printer) { + printer->Print( + "registry.add($scope$.$name$);\n", + "scope", scope_, + "name", UnderscoresToCamelCase(descriptor_)); + return 7; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/java/java_extension_lite.h b/src/google/protobuf/compiler/java/java_extension_lite.h index e69de29b..4cd49bda 100644 --- a/src/google/protobuf/compiler/java/java_extension_lite.h +++ b/src/google/protobuf/compiler/java/java_extension_lite.h @@ -0,0 +1,76 @@ +// 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_JAVA_EXTENSION_LITE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ + +#include +#include + +#include +#include + +namespace google { +namespace protobuf { +namespace compiler { +namespace java { + +// Generates code for a lite extension, which may be within the scope of some +// message or may be at file scope. This is much simpler than FieldGenerator +// since extensions are just simple identifiers with interesting types. +class ImmutableExtensionLiteGenerator : public ExtensionGenerator { + public: + explicit ImmutableExtensionLiteGenerator(const FieldDescriptor* descriptor, + Context* context); + virtual ~ImmutableExtensionLiteGenerator(); + + virtual void Generate(io::Printer* printer); + + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateNonNestedInitializationCode(io::Printer* printer); + + // Returns an estimate of the number of bytes the printed code will compile to + virtual int GenerateRegistrationCode(io::Printer* printer); + + private: + const FieldDescriptor* descriptor_; + Context* context_; + ClassNameResolver* name_resolver_; + string scope_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ImmutableExtensionLiteGenerator); +}; + +} // namespace java +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_LITE_H__ diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index c5434767..3c7bc5c4 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -77,7 +77,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator( return new ImmutableMapFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new RepeatedImmutableLazyMessageFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -99,7 +99,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator( if (field->containing_oneof()) { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageOneofFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -119,7 +119,7 @@ ImmutableFieldGenerator* MakeImmutableGenerator( } else { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageFieldGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -150,7 +150,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( return new ImmutableMapFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new RepeatedImmutableLazyMessageFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -172,7 +172,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( if (field->containing_oneof()) { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageOneofFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { @@ -192,7 +192,7 @@ ImmutableFieldLiteGenerator* MakeImmutableLiteGenerator( } else { switch (GetJavaType(field)) { case JAVATYPE_MESSAGE: - if (IsLazy(field)) { + if (IsLazy(field, context->EnforceLite())) { return new ImmutableLazyMessageFieldLiteGenerator( field, messageBitIndex, builderBitIndex, context); } else { diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index c8172330..c53aae6b 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -177,7 +177,7 @@ void MaybeRestartJavaMethod(io::Printer* printer, // since otherwise we hit a hardcoded limit in the jvm and javac will // then fail with the error "code too large". This limit lets our // estimates be off by a factor of two and still we're okay. - static const int bytesPerMethod = 1<<15; // aka 32K + static const int bytesPerMethod = kMaxStaticSize; if ((*bytecode_estimate) > bytesPerMethod) { ++(*method_num); @@ -193,7 +193,8 @@ void MaybeRestartJavaMethod(io::Printer* printer, } // namespace -FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api) +FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api, + bool enforce_lite) : file_(file), java_package_(FileJavaPackage(file, immutable_api)), message_generators_( @@ -204,6 +205,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api) name_resolver_(context_->GetNameResolver()), immutable_api_(immutable_api) { classname_ = name_resolver_->GetFileClassName(file, immutable_api); + context_->SetEnforceLite(enforce_lite); generator_factory_.reset( new ImmutableGeneratorFactory(context_.get())); for (int i = 0; i < file_->message_type_count(); ++i) { @@ -262,7 +264,8 @@ void FileGenerator::Generate(io::Printer* printer) { printer->Print( "public static void registerAllExtensions(\n" " com.google.protobuf.ExtensionRegistry$lite$ registry) {\n", - "lite", HasDescriptorMethods(file_) ? "" : "Lite"); + "lite", + HasDescriptorMethods(file_, context_->EnforceLite()) ? "" : "Lite"); printer->Indent(); @@ -282,7 +285,7 @@ void FileGenerator::Generate(io::Printer* printer) { if (!MultipleJavaFiles(file_, immutable_api_)) { for (int i = 0; i < file_->enum_type_count(); i++) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { EnumGenerator(file_->enum_type(i), immutable_api_, context_.get()) .Generate(printer); } else { @@ -294,7 +297,7 @@ void FileGenerator::Generate(io::Printer* printer) { message_generators_[i]->GenerateInterface(printer); message_generators_[i]->Generate(printer); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, context_->EnforceLite())) { for (int i = 0; i < file_->service_count(); i++) { google::protobuf::scoped_ptr generator( generator_factory_->NewServiceGenerator(file_->service(i))); @@ -309,14 +312,18 @@ void FileGenerator::Generate(io::Printer* printer) { extension_generators_[i]->Generate(printer); } - // Static variables. + // Static variables. We'd like them to be final if possible, but due to + // the JVM's 64k size limit on static blocks, we have to initialize some + // of them in methods; thus they cannot be final. + int static_block_bytecode_estimate = 0; for (int i = 0; i < file_->message_type_count(); i++) { - message_generators_[i]->GenerateStaticVariables(printer); + message_generators_[i]->GenerateStaticVariables( + printer, &static_block_bytecode_estimate); } printer->Print("\n"); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { if (immutable_api_) { GenerateDescriptorInitializationCodeForImmutable(printer); } else { @@ -358,9 +365,11 @@ void FileGenerator::GenerateDescriptorInitializationCodeForImmutable( " getDescriptor() {\n" " return descriptor;\n" "}\n" - "private static com.google.protobuf.Descriptors.FileDescriptor\n" + "private static $final$ com.google.protobuf.Descriptors.FileDescriptor\n" " descriptor;\n" - "static {\n"); + "static {\n", + // TODO(dweis): Mark this as final. + "final", ""); printer->Indent(); SharedCodeGenerator shared_code_generator(file_); @@ -453,7 +462,7 @@ void FileGenerator::GenerateDescriptorInitializationCodeForMutable(io::Printer* " getDescriptor() {\n" " return descriptor;\n" "}\n" - "private static com.google.protobuf.Descriptors.FileDescriptor\n" + "private static final com.google.protobuf.Descriptors.FileDescriptor\n" " descriptor;\n" "static {\n"); printer->Indent(); @@ -549,7 +558,7 @@ void FileGenerator::GenerateSiblings(const string& package_dir, vector* file_list) { if (MultipleJavaFiles(file_, immutable_api_)) { for (int i = 0; i < file_->enum_type_count(); i++) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, context_->EnforceLite())) { EnumGenerator generator(file_->enum_type(i), immutable_api_, context_.get()); GenerateSibling(package_dir, java_package_, @@ -582,7 +591,7 @@ void FileGenerator::GenerateSiblings(const string& package_dir, message_generators_[i].get(), &MessageGenerator::Generate); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, context_->EnforceLite())) { for (int i = 0; i < file_->service_count(); i++) { google::protobuf::scoped_ptr generator( generator_factory_->NewServiceGenerator(file_->service(i))); diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index 080b3424..7dbeb94e 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -67,7 +67,8 @@ namespace java { class FileGenerator { public: - FileGenerator(const FileDescriptor* file, bool immutable_api = true); + FileGenerator(const FileDescriptor* file, bool immutable_api = true, + bool enforce_lite = false); ~FileGenerator(); // Checks for problems that would otherwise lead to cryptic compile errors. diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index 6c6f7286..a46c7fc4 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -75,6 +75,7 @@ bool JavaGenerator::Generate(const FileDescriptor* file, bool generate_immutable_code = false; bool generate_mutable_code = false; bool generate_shared_code = false; + bool enforce_lite = false; for (int i = 0; i < options.size(); i++) { if (options[i].first == "output_list_file") { output_list_file = options[i].second; @@ -84,12 +85,21 @@ bool JavaGenerator::Generate(const FileDescriptor* file, generate_mutable_code = true; } else if (options[i].first == "shared") { generate_shared_code = true; + } else if (options[i].first == "lite") { + // When set, the protoc will generate the current files and all the + // transitive dependencies as lite runtime. + enforce_lite = true; } else { *error = "Unknown generator option: " + options[i].first; return false; } } + if (enforce_lite && generate_mutable_code) { + *error = "lite runtime generator option cannot be used with mutable API."; + return false; + } + // By default we generate immutable code and shared code for immutable API. if (!generate_immutable_code && !generate_mutable_code && !generate_shared_code) { @@ -105,10 +115,12 @@ bool JavaGenerator::Generate(const FileDescriptor* file, vector file_generators; if (generate_immutable_code) { - file_generators.push_back(new FileGenerator(file, /* immutable = */ true)); + file_generators.push_back( + new FileGenerator(file, /* immutable = */ true, enforce_lite)); } if (generate_mutable_code) { - file_generators.push_back(new FileGenerator(file, /* mutable = */ false)); + file_generators.push_back( + new FileGenerator(file, /* mutable = */ false, enforce_lite)); } for (int i = 0; i < file_generators.size(); ++i) { if (!file_generators[i]->Validate(error)) { diff --git a/src/google/protobuf/compiler/java/java_generator_factory.cc b/src/google/protobuf/compiler/java/java_generator_factory.cc index 92ef851b..3218b410 100644 --- a/src/google/protobuf/compiler/java/java_generator_factory.cc +++ b/src/google/protobuf/compiler/java/java_generator_factory.cc @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -58,17 +59,20 @@ ImmutableGeneratorFactory::~ImmutableGeneratorFactory() {} MessageGenerator* ImmutableGeneratorFactory::NewMessageGenerator( const Descriptor* descriptor) const { - if (descriptor->file()->options().optimize_for() == - FileOptions::LITE_RUNTIME) { - return new ImmutableMessageLiteGenerator(descriptor, context_); - } else { + if (HasDescriptorMethods(descriptor, context_->EnforceLite())) { return new ImmutableMessageGenerator(descriptor, context_); + } else { + return new ImmutableMessageLiteGenerator(descriptor, context_); } } ExtensionGenerator* ImmutableGeneratorFactory::NewExtensionGenerator( const FieldDescriptor* descriptor) const { - return new ImmutableExtensionGenerator(descriptor, context_); + if (HasDescriptorMethods(descriptor->file(), context_->EnforceLite())) { + return new ImmutableExtensionGenerator(descriptor, context_); + } else { + return new ImmutableExtensionLiteGenerator(descriptor, context_); + } } ServiceGenerator* ImmutableGeneratorFactory::NewServiceGenerator( diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index 5392d6d7..c850423e 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -170,44 +170,41 @@ inline string ImmutableDefaultValue(const FieldDescriptor* field, } bool IsDefaultValueJavaDefault(const FieldDescriptor* field); -// Does this message class have generated parsing, serialization, and other -// standard methods for which reflection-based fallback implementations exist? -inline bool HasGeneratedMethods(const Descriptor* descriptor) { - return descriptor->file()->options().optimize_for() != - FileOptions::CODE_SIZE; -} - // Does this message have specialized equals() and hashCode() methods? inline bool HasEqualsAndHashCode(const Descriptor* descriptor) { return descriptor->file()->options().java_generate_equals_and_hash(); } // Does this message class have descriptor and reflection methods? -inline bool HasDescriptorMethods(const Descriptor* descriptor) { - return descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME; +inline bool HasDescriptorMethods(const Descriptor* descriptor, + bool enforce_lite) { + return !enforce_lite && + descriptor->file()->options().optimize_for() != + FileOptions::LITE_RUNTIME; } -inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) { - return descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME; +inline bool HasDescriptorMethods(const EnumDescriptor* descriptor, + bool enforce_lite) { + return !enforce_lite && + descriptor->file()->options().optimize_for() != + FileOptions::LITE_RUNTIME; } -inline bool HasDescriptorMethods(const FileDescriptor* descriptor) { - return descriptor->options().optimize_for() != - FileOptions::LITE_RUNTIME; +inline bool HasDescriptorMethods(const FileDescriptor* descriptor, + bool enforce_lite) { + return !enforce_lite && + descriptor->options().optimize_for() != FileOptions::LITE_RUNTIME; } // Should we generate generic services for this file? -inline bool HasGenericServices(const FileDescriptor *file) { +inline bool HasGenericServices(const FileDescriptor *file, bool enforce_lite) { return file->service_count() > 0 && - file->options().optimize_for() != FileOptions::LITE_RUNTIME && + HasDescriptorMethods(file, enforce_lite) && file->options().java_generic_services(); } -inline bool IsLazy(const FieldDescriptor* descriptor) { +inline bool IsLazy(const FieldDescriptor* descriptor, bool enforce_lite) { // Currently, the proto-lite version suports lazy field. // TODO(niwasaki): Support lazy fields also for other proto runtimes. - if (descriptor->file()->options().optimize_for() != - FileOptions::LITE_RUNTIME) { + if (HasDescriptorMethods(descriptor->file(), enforce_lite)) { return false; } return descriptor->options().lazy(); diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc index 283ba1d3..a648f1c2 100644 --- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc @@ -193,7 +193,7 @@ GenerateMergingCode(io::Printer* printer) const { void ImmutableLazyMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, - "$name$_.setByteString(input.readBytes(), extensionRegistry);\n"); + "$name$_.mergeFrom(input, extensionRegistry);\n"); printer->Print(variables_, "$set_has_field_bit_message$;\n"); } @@ -378,8 +378,7 @@ GenerateParsingCode(io::Printer* printer) const { "if (!($has_oneof_case_message$)) {\n" " $oneof_name$_ = new $lazy_type$();\n" "}\n" - "(($lazy_type$) $oneof_name$_).setByteString(\n" - " input.readBytes(), extensionRegistry);\n" + "(($lazy_type$) $oneof_name$_).mergeFrom(input, extensionRegistry);\n" "$set_oneof_case_message$;\n"); } diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 3e035c89..17c3646f 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -79,9 +79,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, const FieldGeneratorInfo* info, - ClassNameResolver* name_resolver, + Context* context, map* variables) { SetCommonFieldVariables(descriptor, info, variables); + ClassNameResolver* name_resolver = context->GetNameResolver(); (*variables)["type"] = name_resolver->GetImmutableClassName(descriptor->message_type()); @@ -123,8 +124,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; // For repeated fields, one bit is used for whether the array is immutable // in the parsing constructor. @@ -135,18 +135,12 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["default_entry"] = (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry"; - if (HasDescriptorMethods(descriptor->file())) { - (*variables)["lite"] = ""; - (*variables)["map_field_parameter"] = (*variables)["default_entry"]; - (*variables)["descriptor"] = - name_resolver->GetImmutableClassName(descriptor->file()) + - ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + - "_descriptor, "; - } else { - (*variables)["lite"] = "Lite"; - (*variables)["map_field_parameter"] = ""; - (*variables)["descriptor"] = ""; - } + (*variables)["lite"] = ""; + (*variables)["map_field_parameter"] = (*variables)["default_entry"]; + (*variables)["descriptor"] = + name_resolver->GetImmutableClassName(descriptor->file()) + + ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) + + "_descriptor, "; } } // namespace @@ -159,7 +153,7 @@ ImmutableMapFieldGenerator(const FieldDescriptor* descriptor, : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, context->GetFieldGeneratorInfo(descriptor), - name_resolver_, &variables_); + context, &variables_); } ImmutableMapFieldGenerator:: @@ -424,7 +418,7 @@ GenerateParsingCode(io::Printer* printer) const { "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n"); printer->Print( variables_, - "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" + "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n" " unknownFields.mergeLengthDelimitedField($number$, bytes);\n" "} else {\n" " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index d2039403..6bdebb0d 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -79,10 +79,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, int messageBitIndex, int builderBitIndex, const FieldGeneratorInfo* info, - ClassNameResolver* name_resolver, + Context* context, map* variables) { SetCommonFieldVariables(descriptor, info, variables); + ClassNameResolver* name_resolver = context->GetNameResolver(); (*variables)["type"] = name_resolver->GetImmutableClassName(descriptor->message_type()); const FieldDescriptor* key = KeyField(descriptor); @@ -123,8 +124,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; (*variables)["default_entry"] = (*variables)["capitalized_name"] + "DefaultEntryHolder.defaultEntry"; @@ -142,7 +141,7 @@ ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor, : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) { SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, context->GetFieldGeneratorInfo(descriptor), - name_resolver_, &variables_); + context, &variables_); } ImmutableMapFieldLiteGenerator:: @@ -404,7 +403,7 @@ GenerateParsingCode(io::Printer* printer) const { "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n"); printer->Print( variables_, - "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n" + "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n" " super.mergeLengthDelimitedField($number$, bytes);\n" "} else {\n" " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n" diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 22a70c32..dfd8ad08 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -95,13 +95,15 @@ ImmutableMessageGenerator::ImmutableMessageGenerator( : MessageGenerator(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_NE( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A non-lite message generator is used to " + "generate lite messages."; } ImmutableMessageGenerator::~ImmutableMessageGenerator() {} -void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { +void ImmutableMessageGenerator::GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate) { // Because descriptor.proto (com.google.protobuf.DescriptorProtos) is // used in the construction of descriptors, we have a tricky bootstrapping // problem. To help control static initialization order, we make sure all @@ -124,23 +126,29 @@ void ImmutableMessageGenerator::GenerateStaticVariables(io::Printer* printer) { } else { vars["private"] = "private "; } + if (*bytecode_estimate <= kMaxStaticSize) { + vars["final"] = "final "; + } else { + vars["final"] = ""; + } // The descriptor for this type. printer->Print(vars, // TODO(teboring): final needs to be added back. The way to fix it is to // generate methods that can construct the types, and then still declare the // types, and then init them in clinit with the new method calls. - "$private$static com.google.protobuf.Descriptors.Descriptor\n" + "$private$static $final$com.google.protobuf.Descriptors.Descriptor\n" " internal_$identifier$_descriptor;\n"); + *bytecode_estimate += 30; // And the FieldAccessorTable. - GenerateFieldAccessorTable(printer); + GenerateFieldAccessorTable(printer, bytecode_estimate); // Generate static members for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? ImmutableMessageGenerator(descriptor_->nested_type(i), context_) - .GenerateStaticVariables(printer); + .GenerateStaticVariables(printer, bytecode_estimate); } } @@ -183,7 +191,7 @@ int ImmutableMessageGenerator::GenerateStaticVariableInitializers( } void ImmutableMessageGenerator:: -GenerateFieldAccessorTable(io::Printer* printer) { +GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate) { map vars; vars["identifier"] = UniqueFileScopeIdentifier(descriptor_); if (MultipleJavaFiles(descriptor_->file(), /* immutable = */ true)) { @@ -193,10 +201,19 @@ GenerateFieldAccessorTable(io::Printer* printer) { } else { vars["private"] = "private "; } + if (*bytecode_estimate <= kMaxStaticSize) { + vars["final"] = "final "; + } else { + vars["final"] = ""; + } printer->Print(vars, - "$private$static\n" + "$private$static $final$\n" " com.google.protobuf.GeneratedMessage.FieldAccessorTable\n" " internal_$identifier$_fieldAccessorTable;\n"); + + // 6 bytes per field and oneof + *bytecode_estimate += 10 + 6 * descriptor_->field_count() + + 6 * descriptor_->oneof_decl_count(); } int ImmutableMessageGenerator:: @@ -342,7 +359,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print( "}\n"); - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { GenerateParsingConstructor(printer); } @@ -408,12 +425,20 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "cap_oneof_name", ToUpper(vars["oneof_name"])); printer->Print(vars, - "private int value = 0;\n" + "private final int value;\n" "private $oneof_capitalized_name$Case(int value) {\n" " this.value = value;\n" "}\n"); printer->Print(vars, + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" " switch (value) {\n"); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); @@ -426,8 +451,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { } printer->Print( " case 0: return $cap_oneof_name$_NOT_SET;\n" - " default: throw new java.lang.IllegalArgumentException(\n" - " \"Value is undefined for this oneof enum.\");\n" + " default: return null;\n" " }\n" "}\n" "public int getNumber() {\n" @@ -440,7 +464,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" "get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n"); @@ -459,7 +483,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateMessageSerializationMethods(printer); } @@ -664,34 +688,40 @@ GenerateParseFromMethods(io::Printer* printer) { "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseDelimitedWithIOException(PARSER, input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseDelimitedWithIOException(PARSER, input, extensionRegistry);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseDelimitedWithIOException(PARSER, input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return com.google.protobuf.GeneratedMessage.parseWithIOException(PARSER, input, extensionRegistry);" + " return com.google.protobuf.GeneratedMessage\n" + " .parseWithIOException(PARSER, input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -1049,22 +1079,52 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print("hash = (19 * hash) + getDescriptorForType().hashCode();\n"); + // hashCode non-oneofs. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { - printer->Print( - "if (has$name$()) {\n", - "name", info->capitalized_name); - printer->Indent(); - } - field_generators_.get(field).GenerateHashCode(printer); - if (check_has_bits) { - printer->Outdent(); - printer->Print("}\n"); + if (field->containing_oneof() == NULL) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateHashCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print("}\n"); + } } } + + // hashCode oneofs. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "switch ($oneof_name$Case_) {\n", + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "case $field_number$:\n", + "field_number", + SimpleItoa(field->number())); + printer->Indent(); + field_generators_.get(field).GenerateHashCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); + } + if (descriptor_->extension_range_count() > 0) { printer->Print( "hash = hashFields(hash, getExtensionFields());\n"); @@ -1105,7 +1165,8 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Print( "private $classname$(\n" " com.google.protobuf.CodedInputStream input,\n" - " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n", + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws com.google.protobuf.InvalidProtocolBufferException {\n", "classname", descriptor_->name()); printer->Indent(); @@ -1215,10 +1276,10 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Outdent(); printer->Print( "} catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" - " throw new RuntimeException(e.setUnfinishedMessage(this));\n" + " throw e.setUnfinishedMessage(this);\n" "} catch (java.io.IOException e) {\n" - " throw new RuntimeException(new com.google.protobuf.InvalidProtocolBufferException(e)\n" - " .setUnfinishedMessage(this));\n" + " throw new com.google.protobuf.InvalidProtocolBufferException(\n" + " e).setUnfinishedMessage(this);\n" "} finally {\n"); printer->Indent(); @@ -1260,20 +1321,9 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n", "classname", descriptor_->name()); - if (HasGeneratedMethods(descriptor_)) { - // The parsing constructor throws an InvalidProtocolBufferException via a - // RuntimeException to aid in method pruning. We unwrap it here. + if (context_->HasGeneratedMethods(descriptor_)) { printer->Print( - " try {\n" - " return new $classname$(input, extensionRegistry);\n" - " } catch (RuntimeException e) {\n" - " if (e.getCause() instanceof\n" - " com.google.protobuf.InvalidProtocolBufferException) {\n" - " throw (com.google.protobuf.InvalidProtocolBufferException)\n" - " e.getCause();\n" - " }\n" - " throw e;\n" - " }\n", + " return new $classname$(input, extensionRegistry);\n", "classname", descriptor_->name()); } else { // When parsing constructor isn't generated, use builder to parse @@ -1328,14 +1378,39 @@ void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) { void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { printer->Print( "private static String getTypeUrl(\n" + " java.lang.String typeUrlPrefix,\n" " com.google.protobuf.Descriptors.Descriptor descriptor) {\n" - " return \"type.googleapis.com/\" + descriptor.getFullName();\n" + " return typeUrlPrefix.endsWith(\"/\")\n" + " ? typeUrlPrefix + descriptor.getFullName()\n" + " : typeUrlPrefix + \"/\" + descriptor.getFullName();\n" + "}\n" + "\n" + "private static String getTypeNameFromTypeUrl(\n" + " java.lang.String typeUrl) {\n" + " int pos = typeUrl.lastIndexOf('/');\n" + " return pos == -1 ? \"\" : typeUrl.substring(pos + 1);\n" "}\n" "\n" "public static Any pack(\n" " T message) {\n" " return Any.newBuilder()\n" - " .setTypeUrl(getTypeUrl(message.getDescriptorForType()))\n" + " .setTypeUrl(getTypeUrl(\"type.googleapis.com\",\n" + " message.getDescriptorForType()))\n" + " .setValue(message.toByteString())\n" + " .build();\n" + "}\n" + "\n" + "/**\n" + " * Packs a message uisng the given type URL prefix. The type URL will\n" + " * be constructed by concatenating the message type's full name to the\n" + " * prefix with an optional \"/\" separator if the prefix doesn't end\n" + " * with \"/\" already.\n" + " */\n" + "public static Any pack(\n" + " T message, java.lang.String typeUrlPrefix) {\n" + " return Any.newBuilder()\n" + " .setTypeUrl(getTypeUrl(typeUrlPrefix,\n" + " message.getDescriptorForType()))\n" " .setValue(message.toByteString())\n" " .build();\n" "}\n" @@ -1344,8 +1419,8 @@ void ImmutableMessageGenerator::GenerateAnyMethods(io::Printer* printer) { " java.lang.Class clazz) {\n" " T defaultInstance =\n" " com.google.protobuf.Internal.getDefaultInstance(clazz);\n" - " return getTypeUrl().equals(\n" - " getTypeUrl(defaultInstance.getDescriptorForType()));\n" + " return getTypeNameFromTypeUrl(getTypeUrl()).equals(\n" + " defaultInstance.getDescriptorForType().getFullName());\n" "}\n" "\n" "private volatile com.google.protobuf.Message cachedUnpackValue;\n" diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index be5bfb07..e9fc57c2 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -56,6 +56,8 @@ namespace protobuf { namespace compiler { namespace java { +static const int kMaxStaticSize = 1 << 15; // aka 32k + class MessageGenerator { public: explicit MessageGenerator(const Descriptor* descriptor); @@ -64,7 +66,8 @@ class MessageGenerator { // All static variables have to be declared at the top-level of the file // so that we can control initialization order, which is important for // DescriptorProto bootstrapping to work. - virtual void GenerateStaticVariables(io::Printer* printer) = 0; + virtual void GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate) = 0; // Output code which initializes the static variables generated by // GenerateStaticVariables(). Returns an estimate of bytecode size. @@ -96,14 +99,15 @@ class ImmutableMessageGenerator : public MessageGenerator { virtual void Generate(io::Printer* printer); virtual void GenerateInterface(io::Printer* printer); virtual void GenerateExtensionRegistrationCode(io::Printer* printer); - virtual void GenerateStaticVariables(io::Printer* printer); + virtual void GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate); // Returns an estimate of the number of bytes the printed code will compile to virtual int GenerateStaticVariableInitializers(io::Printer* printer); private: - void GenerateFieldAccessorTable(io::Printer* printer); + void GenerateFieldAccessorTable(io::Printer* printer, int* bytecode_estimate); // Returns an estimate of the number of bytes the printed code will compile to int GenerateFieldAccessorTableInitializer(io::Printer* printer); diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc index 5d535034..b3e9e986 100644 --- a/src/google/protobuf/compiler/java/java_message_builder.cc +++ b/src/google/protobuf/compiler/java/java_message_builder.cc @@ -81,8 +81,9 @@ MessageBuilderGenerator::MessageBuilderGenerator( : descriptor_(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_NE( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A non-lite message generator is used to " + "generate lite messages."; } MessageBuilderGenerator::~MessageBuilderGenerator() {} @@ -113,7 +114,7 @@ Generate(io::Printer* printer) { GenerateDescriptorMethods(printer); GenerateCommonBuilderMethods(printer); - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateBuilderParsingMethods(printer); } @@ -134,7 +135,7 @@ Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" " get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n" @@ -439,7 +440,7 @@ GenerateCommonBuilderMethods(io::Printer* printer) { // ----------------------------------------------------------------- - if (HasGeneratedMethods(descriptor_)) { + if (context_->HasGeneratedMethods(descriptor_)) { printer->Print( "public Builder mergeFrom(com.google.protobuf.Message other) {\n" " if (other instanceof $classname$) {\n" diff --git a/src/google/protobuf/compiler/java/java_message_builder_lite.cc b/src/google/protobuf/compiler/java/java_message_builder_lite.cc index 8719d00d..dd429dc9 100644 --- a/src/google/protobuf/compiler/java/java_message_builder_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_builder_lite.cc @@ -81,8 +81,9 @@ MessageBuilderLiteGenerator::MessageBuilderLiteGenerator( : descriptor_(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_EQ( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A lite message generator is used to " + "generate non-lite messages."; } MessageBuilderLiteGenerator::~MessageBuilderLiteGenerator() {} @@ -148,20 +149,6 @@ Generate(io::Printer* printer) { .GenerateBuilderMembers(printer); } - if (!PreserveUnknownFields(descriptor_)) { - printer->Print( - "public final Builder setUnknownFields(\n" - " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" - " return this;\n" - "}\n" - "\n" - "public final Builder mergeUnknownFields(\n" - " final com.google.protobuf.UnknownFieldSet unknownFields) {\n" - " return this;\n" - "}\n" - "\n"); - } - printer->Print( "\n" "// @@protoc_insertion_point(builder_scope:$full_name$)\n", diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index b5f8e626..455516f6 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -70,8 +70,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc index 356520ec..049679df 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -70,8 +70,6 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -867,7 +865,6 @@ GenerateMergingCode(io::Printer* printer) const { " ensure$capitalized_name$IsMutable();\n" " $name$_.addAll(other.$name$_);\n" " }\n" - " $on_changed$\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 94ed2c39..14cc908b 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include @@ -87,19 +87,20 @@ ImmutableMessageLiteGenerator::ImmutableMessageLiteGenerator( : MessageGenerator(descriptor), context_(context), name_resolver_(context->GetNameResolver()), field_generators_(descriptor, context_) { - GOOGLE_CHECK_EQ( - FileOptions::LITE_RUNTIME, descriptor->file()->options().optimize_for()); + GOOGLE_CHECK(!HasDescriptorMethods(descriptor->file(), context->EnforceLite())) + << "Generator factory error: A lite message generator is used to " + "generate non-lite messages."; } ImmutableMessageLiteGenerator::~ImmutableMessageLiteGenerator() {} void ImmutableMessageLiteGenerator::GenerateStaticVariables( - io::Printer* printer) { + io::Printer* printer, int* bytecode_estimate) { // Generate static members for all nested types. for (int i = 0; i < descriptor_->nested_type_count(); i++) { // TODO(kenton): Reuse MessageGenerator objects? ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) - .GenerateStaticVariables(printer); + .GenerateStaticVariables(printer, bytecode_estimate); } } @@ -197,6 +198,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { } printer->Indent(); + GenerateParsingConstructor(printer); // Nested types @@ -259,12 +261,20 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { "cap_oneof_name", ToUpper(vars["oneof_name"])); printer->Print(vars, - "private int value = 0;\n" + "private final int value;\n" "private $oneof_capitalized_name$Case(int value) {\n" " this.value = value;\n" "}\n"); printer->Print(vars, + "/**\n" + " * @deprecated Use {@link #forNumber(int)} instead.\n" + " */\n" + "@java.lang.Deprecated\n" "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" " switch (value) {\n"); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); @@ -277,8 +287,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { } printer->Print( " case 0: return $cap_oneof_name$_NOT_SET;\n" - " default: throw new java.lang.IllegalArgumentException(\n" - " \"Value is undefined for this oneof enum.\");\n" + " default: return null;\n" " }\n" "}\n" "public int getNumber() {\n" @@ -291,7 +300,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" "get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n" @@ -317,7 +326,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { GenerateEqualsAndHashCode(printer); } - GenerateParseFromMethods(printer); GenerateBuilder(printer); @@ -446,7 +454,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { // because the DEFAULT_INSTANCE is used by the extension to lazily retrieve // the outer class's FileDescriptor. for (int i = 0; i < descriptor_->extension_count(); i++) { - ImmutableExtensionGenerator(descriptor_->extension(i), context_) + ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) .Generate(printer); } @@ -557,9 +565,6 @@ GenerateMessageSerializationMethods(io::Printer* printer) { " return size;\n" "}\n" "\n"); - - printer->Print( - "private static final long serialVersionUID = 0L;\n"); } void ImmutableMessageLiteGenerator:: @@ -571,54 +576,62 @@ GenerateParseFromMethods(io::Printer* printer) { "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.ByteString data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(byte[] data)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data);\n" "}\n" "public static $classname$ parseFrom(\n" " byte[] data,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws com.google.protobuf.InvalidProtocolBufferException {\n" - " return parser().parseFrom(data, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, data, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input);\n" "}\n" "public static $classname$ parseFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input, extensionRegistry);\n" "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return parser().parseDelimitedFrom(input);\n" + " return parseDelimitedFrom(DEFAULT_INSTANCE, input);\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return parser().parseDelimitedFrom(input, extensionRegistry);\n" + " return parseDelimitedFrom(DEFAULT_INSTANCE, input, extensionRegistry);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input);\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return parser().parseFrom(input, extensionRegistry);\n" + " return com.google.protobuf.GeneratedMessageLite.parseFrom(\n" + " DEFAULT_INSTANCE, input, extensionRegistry);\n" "}\n" "\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -906,24 +919,61 @@ GenerateEqualsAndHashCode(io::Printer* printer) { "classname", name_resolver_->GetImmutableClassName(descriptor_)); printer->Print("boolean result = true;\n"); + // Compare non-oneofs. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { - printer->Print( - "result = result && (has$name$() == other.has$name$());\n" - "if (has$name$()) {\n", - "name", info->capitalized_name); - printer->Indent(); - } - field_generators_.get(field).GenerateEqualsCode(printer); - if (check_has_bits) { - printer->Outdent(); - printer->Print( - "}\n"); + if (field->containing_oneof() == NULL) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "result = result && (has$name$() == other.has$name$());\n" + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateEqualsCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print( + "}\n"); + } } } + + // Compare oneofs. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "result = result && get$oneof_capitalized_name$Case().equals(\n" + " other.get$oneof_capitalized_name$Case());\n", + "oneof_capitalized_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->capitalized_name); + printer->Print( + "if (!result) return false;\n" + "switch ($oneof_name$Case_) {\n", + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); + printer->Print( + "case $field_number$:\n", + "field_number", + SimpleItoa(field->number())); + printer->Indent(); + field_generators_.get(field).GenerateEqualsCode(printer); + printer->Print("break;\n"); + printer->Outdent(); + } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); + } + if (PreserveUnknownFields(descriptor_)) { // Always consider unknown fields for equality. This will sometimes return // false for non-canonical ordering when running in LITE_RUNTIME but it's @@ -957,21 +1007,50 @@ GenerateEqualsAndHashCode(io::Printer* printer) { printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); + // hashCode non-oneofs. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { + if (field->containing_oneof() == NULL) { + const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); + bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); + if (check_has_bits) { + printer->Print( + "if (has$name$()) {\n", + "name", info->capitalized_name); + printer->Indent(); + } + field_generators_.get(field).GenerateHashCode(printer); + if (check_has_bits) { + printer->Outdent(); + printer->Print("}\n"); + } + } + } + + // hashCode oneofs. + for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { + printer->Print( + "switch ($oneof_name$Case_) {\n", + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); + printer->Indent(); + for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { + const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); printer->Print( - "if (has$name$()) {\n", - "name", info->capitalized_name); + "case $field_number$:\n", + "field_number", + SimpleItoa(field->number())); printer->Indent(); - } - field_generators_.get(field).GenerateHashCode(printer); - if (check_has_bits) { + field_generators_.get(field).GenerateHashCode(printer); + printer->Print("break;\n"); printer->Outdent(); - printer->Print("}\n"); } + printer->Print( + "case 0:\n" + "default:\n"); + printer->Outdent(); + printer->Print("}\n"); } printer->Print( @@ -990,7 +1069,7 @@ GenerateEqualsAndHashCode(io::Printer* printer) { void ImmutableMessageLiteGenerator:: GenerateExtensionRegistrationCode(io::Printer* printer) { for (int i = 0; i < descriptor_->extension_count(); i++) { - ImmutableExtensionGenerator(descriptor_->extension(i), context_) + ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) .GenerateRegistrationCode(printer); } @@ -1167,7 +1246,6 @@ void ImmutableMessageLiteGenerator::GenerateInitializers(io::Printer* printer) { } } - } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h index 2bd3cdd4..c8ee99bd 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.h +++ b/src/google/protobuf/compiler/java/java_message_lite.h @@ -54,7 +54,8 @@ class ImmutableMessageLiteGenerator : public MessageGenerator { virtual void Generate(io::Printer* printer); virtual void GenerateInterface(io::Printer* printer); virtual void GenerateExtensionRegistrationCode(io::Printer* printer); - virtual void GenerateStaticVariables(io::Printer* printer); + virtual void GenerateStaticVariables( + io::Printer* printer, int* bytecode_estimate); virtual int GenerateStaticVariableInitializers(io::Printer* printer); private: diff --git a/src/google/protobuf/compiler/java/java_name_resolver.cc b/src/google/protobuf/compiler/java/java_name_resolver.cc index 0c363f9f..bffe4f16 100644 --- a/src/google/protobuf/compiler/java/java_name_resolver.cc +++ b/src/google/protobuf/compiler/java/java_name_resolver.cc @@ -259,6 +259,13 @@ string ClassNameResolver::GetJavaImmutableClassName( descriptor->file(), true); } +string ClassNameResolver::GetJavaImmutableClassName( + const EnumDescriptor* descriptor) { + return GetJavaClassFullName( + ClassNameWithoutPackage(descriptor, true), + descriptor->file(), true); +} + } // namespace java } // namespace compiler diff --git a/src/google/protobuf/compiler/java/java_name_resolver.h b/src/google/protobuf/compiler/java/java_name_resolver.h index ab60b0a0..570d8d8f 100644 --- a/src/google/protobuf/compiler/java/java_name_resolver.h +++ b/src/google/protobuf/compiler/java/java_name_resolver.h @@ -98,6 +98,7 @@ class ClassNameResolver { // For example: // com.package.OuterClass$OuterMessage$InnerMessage string GetJavaImmutableClassName(const Descriptor* descriptor); + string GetJavaImmutableClassName(const EnumDescriptor* descriptor); private: // Get the full name of a Java class by prepending the Java package name // or outer class name. diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 178bbe19..e42ec280 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -75,12 +75,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver)); (*variables)["capitalized_type"] = GetCapitalizedType(descriptor, /* immutable = */ true); - if (descriptor->is_packed()) { - (*variables)["tag"] = SimpleItoa(WireFormatLite::MakeTag( - descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); - } else { - (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); - } + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), GetType(descriptor))); if (IsReferenceType(GetJavaType(descriptor))) { @@ -99,8 +94,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -606,7 +600,7 @@ GenerateMembers(io::Printer* printer) const { "}\n"); if (descriptor_->is_packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize = -1;\n"); } diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index 5a7bf82d..d277e4f3 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -129,8 +129,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -635,7 +633,7 @@ GenerateMembers(io::Printer* printer) const { "}\n"); if (descriptor_->options().packed() && - HasGeneratedMethods(descriptor_->containing_type())) { + context_->HasGeneratedMethods(descriptor_->containing_type())) { printer->Print(variables_, "private int $name$MemoizedSerializedSize = -1;\n"); } @@ -758,7 +756,6 @@ GenerateMergingCode(io::Printer* printer) const { " ensure$capitalized_name$IsMutable();\n" " $name$_.addAll(other.$name$_);\n" " }\n" - " $on_changed$\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc index 70177367..74253c3f 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc @@ -52,8 +52,9 @@ namespace compiler { namespace java { SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file) - : name_resolver_(new ClassNameResolver), file_(file) { -} + : name_resolver_(new ClassNameResolver), + enforce_lite_(false), + file_(file) {} SharedCodeGenerator::~SharedCodeGenerator() { } @@ -63,7 +64,7 @@ void SharedCodeGenerator::Generate(GeneratorContext* context, string java_package = FileJavaPackage(file_); string package_dir = JavaPackageToDir(java_package); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, enforce_lite_)) { // Generate descriptors. string classname = name_resolver_->GetDescriptorClassName(file_); string filename = package_dir + classname + ".java"; diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h index 38a32fc2..3b573c07 100644 --- a/src/google/protobuf/compiler/java/java_shared_code_generator.h +++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h @@ -72,6 +72,10 @@ class SharedCodeGenerator { void Generate(GeneratorContext* generator_context, vector* file_list); + void SetEnforceLite(bool value) { + enforce_lite_ = value; + } + void GenerateDescriptors(io::Printer* printer); private: @@ -81,6 +85,7 @@ class SharedCodeGenerator { bool ShouldIncludeDependency(const FileDescriptor* descriptor); google::protobuf::scoped_ptr name_resolver_; + bool enforce_lite_; const FileDescriptor* file_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator); }; diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc index 7f757e47..b67eeb53 100644 --- a/src/google/protobuf/compiler/java/java_string_field.cc +++ b/src/google/protobuf/compiler/java/java_string_field.cc @@ -87,8 +87,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; + (*variables)["on_changed"] = "onChanged();"; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -408,15 +407,6 @@ GenerateParsingCode(io::Printer* printer) const { "java.lang.String s = input.readStringRequireUtf8();\n" "$set_has_field_bit_message$\n" "$name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { - // Lite runtime should attempt to reduce allocations by attempting to - // construct the string directly from the input stream buffer. This avoids - // spurious intermediary ByteString allocations, cutting overall allocations - // in half. - printer->Print(variables_, - "java.lang.String s = input.readString();\n" - "$set_has_field_bit_message$\n" - "$name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -668,15 +658,6 @@ GenerateParsingCode(io::Printer* printer) const { "java.lang.String s = input.readStringRequireUtf8();\n" "$set_oneof_case_message$;\n" "$oneof_name$_ = s;\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { - // Lite runtime should attempt to reduce allocations by attempting to - // construct the string directly from the input stream buffer. This avoids - // spurious intermediary ByteString allocations, cutting overall allocations - // in half. - printer->Print(variables_, - "java.lang.String s = input.readString();\n" - "$set_oneof_case_message$;\n" - "$oneof_name$_ = s;\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n" @@ -934,13 +915,6 @@ GenerateParsingCode(io::Printer* printer) const { if (CheckUtf8(descriptor_)) { printer->Print(variables_, "java.lang.String s = input.readStringRequireUtf8();\n"); - } else if (!HasDescriptorMethods(descriptor_->file())) { - // Lite runtime should attempt to reduce allocations by attempting to - // construct the string directly from the input stream buffer. This avoids - // spurious intermediary ByteString allocations, cutting overall allocations - // in half. - printer->Print(variables_, - "java.lang.String s = input.readString();\n"); } else { printer->Print(variables_, "com.google.protobuf.ByteString bs = input.readBytes();\n"); @@ -950,7 +924,7 @@ GenerateParsingCode(io::Printer* printer) const { " $name$_ = new com.google.protobuf.LazyStringArrayList();\n" " $set_mutable_bit_parser$;\n" "}\n"); - if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { + if (CheckUtf8(descriptor_)) { printer->Print(variables_, "$name$_.add(s);\n"); } else { diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index eb5964bd..9012ab5e 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -84,8 +84,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // by the proto compiler (*variables)["deprecation"] = descriptor->options().deprecated() ? "@java.lang.Deprecated " : ""; - (*variables)["on_changed"] = - HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; if (SupportFieldPresence(descriptor->file())) { // For singular messages and builders, one bit is used for the hasField bit. @@ -103,7 +101,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["clear_has_field_bit_message"] = ""; (*variables)["is_field_present_message"] = - "!get" + (*variables)["capitalized_name"] + ".isEmpty()"; + "!" + (*variables)["name"] + "_.isEmpty()"; } // For repeated builders, the underlying list tracks mutability state. @@ -309,13 +307,11 @@ GenerateMergingCode(io::Printer* printer) const { "if (other.has$capitalized_name$()) {\n" " $set_has_field_bit_message$\n" " $name$_ = other.$name$_;\n" - " $on_changed$\n" "}\n"); } else { printer->Print(variables_, "if (!other.get$capitalized_name$().isEmpty()) {\n" " $name$_ = other.$name$_;\n" - " $on_changed$\n" "}\n"); } } @@ -528,8 +524,7 @@ GenerateMergingCode(io::Printer* printer) const { // all string fields to Strings when copying fields from a Message. printer->Print(variables_, "$set_oneof_case_message$;\n" - "$oneof_name$_ = other.$oneof_name$_;\n" - "$on_changed$\n"); + "$oneof_name$_ = other.$oneof_name$_;\n"); } void ImmutableStringOneofFieldLiteGenerator:: @@ -792,7 +787,6 @@ GenerateMergingCode(io::Printer* printer) const { " ensure$capitalized_name$IsMutable();\n" " $name$_.addAll(other.$name$_);\n" " }\n" - " $on_changed$\n" "}\n"); } @@ -819,13 +813,8 @@ GenerateParsingCode(io::Printer* printer) const { "if (!$is_mutable$) {\n" " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" "}\n"); - if (CheckUtf8(descriptor_) || !HasDescriptorMethods(descriptor_->file())) { - printer->Print(variables_, - "$name$_.add(s);\n"); - } else { - printer->Print(variables_, - "$name$_.add(bs);\n"); - } + printer->Print(variables_, + "$name$_.add(s);\n"); } void RepeatedImmutableStringFieldLiteGenerator:: diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc index a33eba1b..a342e6bb 100644 --- a/src/google/protobuf/compiler/javanano/javanano_generator.cc +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -68,12 +68,7 @@ void UpdateParamsRecursively(Params& params, } if (file->options().has_java_package()) { string result = file->options().java_package(); - if (!file->options().javanano_use_deprecated_package()) { - if (!result.empty()) { - result += "."; - } - result += "nano"; - } + result += "nano"; params.set_java_package( file->name(), result); } diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc index 5465655f..02811a24 100644 --- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc @@ -201,12 +201,10 @@ string FileJavaPackage(const Params& params, const FileDescriptor* file) { result += file->package(); } - if (!file->options().javanano_use_deprecated_package()) { - if (!result.empty()) { - result += "."; - } - result += "nano"; + if (!result.empty()) { + result += "."; } + result += "nano"; return result; } diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index 0de7e2c6..534a5b5b 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -28,7 +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. -#include +#include "google/protobuf/compiler/js/js_generator.h" #include #include @@ -123,6 +123,16 @@ static const int kNumKeyword = sizeof(kKeyword) / sizeof(char*); namespace { +// The mode of operation for bytes fields. Historically JSPB always carried +// bytes as JS {string}, containing base64 content by convention. With binary +// and proto3 serialization the new convention is to represent it as binary +// data in Uint8Array. See b/26173701 for background on the migration. +enum BytesMode { + BYTES_DEFAULT, // Default type for getBytesField to return. + BYTES_B64, // Explicitly coerce to base64 string where needed. + BYTES_U8, // Explicitly coerce to Uint8Array where needed. +}; + bool IsReserved(const string& ident) { for (int i = 0; i < kNumKeyword; i++) { if (ident == kKeyword[i]) { @@ -134,7 +144,7 @@ bool IsReserved(const string& ident) { // Returns a copy of |filename| with any trailing ".protodevel" or ".proto // suffix stripped. -// TODO(robinson): Unify with copy in compiler/cpp/internal/helpers.cc. +// TODO(haberman): Unify with copy in compiler/cpp/internal/helpers.cc. string StripProto(const string& filename) { const char* suffix = HasSuffixString(filename, ".protodevel") ? ".protodevel" : ".proto"; @@ -144,9 +154,7 @@ string StripProto(const string& filename) { // Given a filename like foo/bar/baz.proto, returns the correspoding JavaScript // file foo/bar/baz.js. string GetJSFilename(const string& filename) { - const char* suffix = HasSuffixString(filename, ".protodevel") - ? ".protodevel" : ".proto"; - return StripSuffixString(filename, suffix) + "_pb.js"; + return StripProto(filename) + "_pb.js"; } // Given a filename like foo/bar/baz.proto, returns the root directory @@ -385,15 +393,47 @@ string ToFileName(const string& input) { return result; } +// When we're generating one output file per type name, this is the filename +// that top-level extensions should go in. +string GetExtensionFileName(const GeneratorOptions& options, + const FileDescriptor* file) { + return options.output_dir + "/" + ToFileName(GetPath(options, file)) + ".js"; +} + +// When we're generating one output file per type name, this is the filename +// that a top-level message should go in. +string GetMessageFileName(const GeneratorOptions& options, + const Descriptor* desc) { + return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; +} + +// When we're generating one output file per type name, this is the filename +// that a top-level message should go in. +string GetEnumFileName(const GeneratorOptions& options, + const EnumDescriptor* desc) { + return options.output_dir + "/" + ToFileName(desc->name()) + ".js"; +} + // Returns the message/response ID, if set. string GetMessageId(const Descriptor* desc) { return string(); } +bool IgnoreExtensionField(const FieldDescriptor* field) { + // Exclude descriptor extensions from output "to avoid clutter" (from original + // codegen). + return field->is_extension() && + field->containing_type()->file()->name() == + "google/protobuf/descriptor.proto"; +} + // Used inside Google only -- do not remove. bool IsResponse(const Descriptor* desc) { return false; } -bool IgnoreField(const FieldDescriptor* field) { return false; } + +bool IgnoreField(const FieldDescriptor* field) { + return IgnoreExtensionField(field); +} // Does JSPB ignore this entire oneof? True only if all fields are ignored. @@ -438,12 +478,32 @@ string JSObjectFieldName(const FieldDescriptor* field) { return name; } +string JSByteGetterSuffix(BytesMode bytes_mode) { + switch (bytes_mode) { + case BYTES_DEFAULT: + return ""; + case BYTES_B64: + return "B64"; + case BYTES_U8: + return "U8"; + default: + assert(false); + } +} + // Returns the field name as a capitalized portion of a getter/setter method // name, e.g. MyField for .getMyField(). -string JSGetterName(const FieldDescriptor* field) { +string JSGetterName(const FieldDescriptor* field, + BytesMode bytes_mode = BYTES_DEFAULT) { string name = JSIdent(field, /* is_upper_camel = */ true, /* is_map = */ false); + if (field->type() == FieldDescriptor::TYPE_BYTES) { + string suffix = JSByteGetterSuffix(bytes_mode); + if (!suffix.empty()) { + name += "_as" + suffix; + } + } if (name == "Extension" || name == "JsPbMessageId") { // Avoid conflicts with base-class names. name += "$"; @@ -504,8 +564,7 @@ string JSOneofIndex(const OneofDescriptor* oneof) { return SimpleItoa(index); } -// Decodes a codepoint in \x0000 -- \xFFFF. Since JS strings are UTF-16, we only -// need to handle the BMP (16-bit range) here. +// Decodes a codepoint in \x0000 -- \xFFFF. uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) { if (*length == 0) { return 0; @@ -542,80 +601,56 @@ uint16 DecodeUTF8Codepoint(uint8* bytes, size_t* length) { } // Escapes the contents of a string to be included within double-quotes ("") in -// JavaScript. |is_utf8| determines whether the input data (in a C++ string of -// chars) is UTF-8 encoded (in which case codepoints become JavaScript string -// characters, escaped with 16-bit hex escapes where necessary) or raw binary -// (in which case bytes become JavaScript string characters 0 -- 255). -string EscapeJSString(const string& in, bool is_utf8) { - string result; +// JavaScript. The input data should be a UTF-8 encoded C++ string of chars. +// Returns false if |out| was truncated because |in| contained invalid UTF-8 or +// codepoints outside the BMP. +// TODO(lukestebbing): Support codepoints outside the BMP. +bool EscapeJSString(const string& in, string* out) { size_t decoded = 0; for (size_t i = 0; i < in.size(); i += decoded) { uint16 codepoint = 0; - if (is_utf8) { - // Decode the next UTF-8 codepoint. - size_t have_bytes = in.size() - i; - uint8 bytes[3] = { + // Decode the next UTF-8 codepoint. + size_t have_bytes = in.size() - i; + uint8 bytes[3] = { static_cast(in[i]), static_cast(((i + 1) < in.size()) ? in[i + 1] : 0), static_cast(((i + 2) < in.size()) ? in[i + 2] : 0), - }; - codepoint = DecodeUTF8Codepoint(bytes, &have_bytes); - if (have_bytes == 0) { - break; - } - decoded = have_bytes; - } else { - codepoint = static_cast(static_cast(in[i])); - decoded = 1; + }; + codepoint = DecodeUTF8Codepoint(bytes, &have_bytes); + if (have_bytes == 0) { + return false; } - - // Next byte -- used for minimal octal escapes below. - char next_byte = (i + decoded) < in.size() ? - in[i + decoded] : 0; - bool pad_octal = (next_byte >= '0' && next_byte <= '7'); + decoded = have_bytes; switch (codepoint) { - case '\0': result += pad_octal ? "\\000" : "\\0"; break; - case '\b': result += "\\\b"; break; - case '\t': result += "\\\t"; break; - case '\n': result += "\\\n"; break; - case '\r': result += "\\\r"; break; - case '\f': result += "\\\f"; break; - case '\\': result += "\\\\"; break; - case '"': result += pad_octal ? "\\042" : "\\42"; break; - case '&': result += pad_octal ? "\\046" : "\\46"; break; - case '\'': result += pad_octal ? "\\047" : "\\47"; break; - case '<': result += pad_octal ? "\\074" : "\\74"; break; - case '=': result += pad_octal ? "\\075" : "\\75"; break; - case '>': result += pad_octal ? "\\076" : "\\76"; break; + case '\'': *out += "\\x27"; break; + case '"': *out += "\\x22"; break; + case '<': *out += "\\x3c"; break; + case '=': *out += "\\x3d"; break; + case '>': *out += "\\x3e"; break; + case '&': *out += "\\x26"; break; + case '\b': *out += "\\b"; break; + case '\t': *out += "\\t"; break; + case '\n': *out += "\\n"; break; + case '\f': *out += "\\f"; break; + case '\r': *out += "\\r"; break; + case '\\': *out += "\\\\"; break; default: - // All other non-ASCII codepoints are escaped. - // Original codegen uses hex for >= 0x100 and octal for others. + // TODO(lukestebbing): Once we're supporting codepoints outside the BMP, + // use a single Unicode codepoint escape if the output language is + // ECMAScript 2015 or above. Otherwise, use a surrogate pair. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#String_literals if (codepoint >= 0x20 && codepoint <= 0x7e) { - result += static_cast(codepoint); + *out += static_cast(codepoint); + } else if (codepoint >= 0x100) { + *out += StringPrintf("\\u%04x", codepoint); } else { - if (codepoint >= 0x100) { - result += StringPrintf("\\u%04x", codepoint); - } else { - if (pad_octal || codepoint >= 0100) { - result += "\\"; - result += ('0' + ((codepoint >> 6) & 07)); - result += ('0' + ((codepoint >> 3) & 07)); - result += ('0' + ((codepoint >> 0) & 07)); - } else if (codepoint >= 010) { - result += "\\"; - result += ('0' + ((codepoint >> 3) & 07)); - result += ('0' + ((codepoint >> 0) & 07)); - } else { - result += "\\"; - result += ('0' + ((codepoint >> 0) & 07)); - } - } + *out += StringPrintf("\\x%02x", codepoint); } break; } } - return result; + return true; } string EscapeBase64(const string& in) { @@ -740,11 +775,17 @@ string JSFieldDefault(const FieldDescriptor* field) { return DoubleToString(field->default_value_double()); case FieldDescriptor::CPPTYPE_STRING: if (field->type() == FieldDescriptor::TYPE_STRING) { - return "\"" + EscapeJSString(field->default_value_string(), true) + - "\""; - } else { - return "\"" + EscapeBase64(field->default_value_string()) + - "\""; + string out; + bool is_valid = EscapeJSString(field->default_value_string(), &out); + if (!is_valid) { + // TODO(lukestebbing): Decide whether this should be a hard error. + GOOGLE_LOG(WARNING) << "The default value for field " << field->full_name() + << " was truncated since it contained invalid UTF-8 or" + " codepoints outside the basic multilingual plane."; + } + return "\"" + out + "\""; + } else { // Bytes + return "\"" + EscapeBase64(field->default_value_string()) + "\""; } case FieldDescriptor::CPPTYPE_MESSAGE: return "null"; @@ -801,8 +842,27 @@ string JSIntegerTypeName(const FieldDescriptor* field) { return "number"; } +string JSStringTypeName(const GeneratorOptions& options, + const FieldDescriptor* field, + BytesMode bytes_mode) { + if (field->type() == FieldDescriptor::TYPE_BYTES) { + switch (bytes_mode) { + case BYTES_DEFAULT: + return "(string|Uint8Array)"; + case BYTES_B64: + return "string"; + case BYTES_U8: + return "Uint8Array"; + default: + assert(false); + } + } + return "string"; +} + string JSTypeName(const GeneratorOptions& options, - const FieldDescriptor* field) { + const FieldDescriptor* field, + BytesMode bytes_mode) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_BOOL: return "boolean"; @@ -819,7 +879,7 @@ string JSTypeName(const GeneratorOptions& options, case FieldDescriptor::CPPTYPE_DOUBLE: return "number"; case FieldDescriptor::CPPTYPE_STRING: - return "string"; + return JSStringTypeName(options, field, bytes_mode); case FieldDescriptor::CPPTYPE_ENUM: return GetPath(options, field->enum_type()); case FieldDescriptor::CPPTYPE_MESSAGE: @@ -836,20 +896,26 @@ string JSFieldTypeAnnotation(const GeneratorOptions& options, bool force_optional, bool force_present, bool singular_if_not_packed, - bool always_singular) { + BytesMode bytes_mode = BYTES_DEFAULT) { bool is_primitive = (field->cpp_type() != FieldDescriptor::CPPTYPE_ENUM && - field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE); + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE && + (field->type() != FieldDescriptor::TYPE_BYTES || + bytes_mode == BYTES_B64)); - string jstype = JSTypeName(options, field); + string jstype = JSTypeName(options, field, bytes_mode); if (field->is_repeated() && - !always_singular && (field->is_packed() || !singular_if_not_packed)) { - if (!is_primitive) { - jstype = "!" + jstype; + if (field->type() == FieldDescriptor::TYPE_BYTES && + bytes_mode == BYTES_DEFAULT) { + jstype = "(Array|Array)"; + } else { + if (!is_primitive) { + jstype = "!" + jstype; + } + jstype = "Array.<" + jstype + ">"; } - jstype = "Array.<" + jstype + ">"; if (!force_optional) { jstype = "!" + jstype; } @@ -884,10 +950,6 @@ string JSBinaryReaderMethodType(const FieldDescriptor* field) { string JSBinaryReadWriteMethodName(const FieldDescriptor* field, bool is_writer) { string name = JSBinaryReaderMethodType(field); - if (is_writer && field->type() == FieldDescriptor::TYPE_BYTES) { - // Override for `bytes` fields: treat string as raw bytes, not base64. - name = "BytesRawString"; - } if (field->is_packed()) { name = "Packed" + name; } else if (is_writer && field->is_repeated()) { @@ -1044,7 +1106,7 @@ string FieldDefinition(const GeneratorOptions& options, field->number()); } -string FieldComments(const FieldDescriptor* field) { +string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) { string comments; if (field->cpp_type() == FieldDescriptor::CPPTYPE_BOOL) { comments += @@ -1060,6 +1122,11 @@ string FieldComments(const FieldDescriptor* field) { " * replace the array itself, then you must call the setter to " "update it.\n"; } + if (field->type() == FieldDescriptor::TYPE_BYTES && bytes_mode == BYTES_U8) { + comments += + " * Note that Uint8Array is not supported on all browsers.\n" + " * @see http://caniuse.com/Uint8Array\n"; + } return comments; } @@ -1070,8 +1137,10 @@ bool ShouldGenerateExtension(const FieldDescriptor* field) { } bool HasExtensions(const Descriptor* desc) { - if (desc->extension_count() > 0) { - return true; + for (int i = 0; i < desc->extension_count(); i++) { + if (ShouldGenerateExtension(desc->extension(i))) { + return true; + } } for (int i = 0; i < desc->nested_type_count(); i++) { if (HasExtensions(desc->nested_type(i))) { @@ -1123,7 +1192,7 @@ string GetPivot(const Descriptor* desc) { } // Returns true for fields that represent "null" as distinct from the default -// value. See https://go/proto3#heading=h.kozewqqcqhuz for more information. +// value. See http://go/proto3#heading=h.kozewqqcqhuz for more information. bool HasFieldPresence(const FieldDescriptor* field) { return (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) || @@ -1132,7 +1201,7 @@ bool HasFieldPresence(const FieldDescriptor* field) { } // For proto3 fields without presence, returns a string representing the default -// value in JavaScript. See https://go/proto3#heading=h.kozewqqcqhuz for more +// value in JavaScript. See http://go/proto3#heading=h.kozewqqcqhuz for more // information. string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { switch (field->cpp_type()) { @@ -1151,16 +1220,153 @@ string Proto3PrimitiveFieldDefault(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_BOOL: return "false"; - case FieldDescriptor::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_STRING: // includes BYTES return "\"\""; default: - // BYTES and MESSAGE are handled separately. + // MESSAGE is handled separately. assert(false); return ""; } } +// We use this to implement the semantics that same file can be generated +// multiple times, but the last one wins. We never actually write the files, +// but we keep a set of which descriptors were the final one for a given +// filename. +class FileDeduplicator { + public: + explicit FileDeduplicator(const GeneratorOptions& options) + : error_on_conflict_(options.error_on_name_conflict) {} + + bool AddFile(const string& filename, const void* desc, string* error) { + if (descs_by_filename_.find(filename) != descs_by_filename_.end()) { + if (error_on_conflict_) { + *error = "Name conflict: file name " + filename + + " would be generated by two descriptors"; + return false; + } + allowed_descs_.erase(descs_by_filename_[filename]); + } + + descs_by_filename_[filename] = desc; + allowed_descs_.insert(desc); + return true; + } + + void GetAllowedSet(set* allowed_set) { + *allowed_set = allowed_descs_; + } + + private: + bool error_on_conflict_; + map descs_by_filename_; + set allowed_descs_; +}; + +void DepthFirstSearch(const FileDescriptor* file, + vector* list, + set* seen) { + if (!seen->insert(file).second) { + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + DepthFirstSearch(file->dependency(i), list, seen); + } + + // Add this file. + list->push_back(file); +} + +// A functor for the predicate to remove_if() below. Returns true if a given +// FileDescriptor is not in the given set. +class NotInSet { + public: + explicit NotInSet(const set& file_set) + : file_set_(file_set) {} + + bool operator()(const FileDescriptor* file) { + return file_set_.count(file) == 0; + } + + private: + const set& file_set_; +}; + +// This function generates an ordering of the input FileDescriptors that matches +// the logic of the old code generator. The order is significant because two +// different input files can generate the same output file, and the last one +// needs to win. +void GenerateJspbFileOrder(const vector& input, + vector* ordered) { + // First generate an ordering of all reachable files (including dependencies) + // with depth-first search. This mimics the behavior of --include_imports, + // which is what the old codegen used. + ordered->clear(); + set seen; + set input_set; + for (int i = 0; i < input.size(); i++) { + DepthFirstSearch(input[i], ordered, &seen); + input_set.insert(input[i]); + } + + // Now remove the entries that are not actually in our input list. + ordered->erase( + std::remove_if(ordered->begin(), ordered->end(), NotInSet(input_set)), + ordered->end()); +} + +// If we're generating code in file-per-type mode, avoid overwriting files +// by choosing the last descriptor that writes each filename and permitting +// only those to generate code. + +bool GenerateJspbAllowedSet(const GeneratorOptions& options, + const vector& files, + set* allowed_set, + string* error) { + vector files_ordered; + GenerateJspbFileOrder(files, &files_ordered); + + // Choose the last descriptor for each filename. + FileDeduplicator dedup(options); + for (int i = 0; i < files_ordered.size(); i++) { + for (int j = 0; j < files_ordered[i]->message_type_count(); j++) { + const Descriptor* desc = files_ordered[i]->message_type(j); + if (!dedup.AddFile(GetMessageFileName(options, desc), desc, error)) { + return false; + } + } + for (int j = 0; j < files_ordered[i]->enum_type_count(); j++) { + const EnumDescriptor* desc = files_ordered[i]->enum_type(j); + if (!dedup.AddFile(GetEnumFileName(options, desc), desc, error)) { + return false; + } + } + + // Pull out all free-floating extensions and generate files for those too. + bool has_extension = false; + + for (int j = 0; j < files_ordered[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files_ordered[i]->extension(j))) { + has_extension = true; + } + } + + if (has_extension) { + if (!dedup.AddFile(GetExtensionFileName(options, files_ordered[i]), + files_ordered[i], error)) { + return false; + } + } + } + + dedup.GetAllowedSet(allowed_set); + + return true; +} + } // anonymous namespace void Generator::GenerateHeader(const GeneratorOptions& options, @@ -1251,10 +1457,10 @@ void Generator::GenerateProvides(const GeneratorOptions& options, } } -void Generator::GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const Descriptor* desc, - std::set* provided) const { +void Generator::GenerateRequiresForMessage(const GeneratorOptions& options, + io::Printer* printer, + const Descriptor* desc, + std::set* provided) const { std::set required; std::set forwards; bool have_message = false; @@ -1266,55 +1472,50 @@ void Generator::GenerateRequires(const GeneratorOptions& options, /* require_extension = */ HasExtensions(desc)); } -void Generator::GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector& files, - std::set* provided) const { - if (options.import_style == GeneratorOptions::IMPORT_BROWSER) { - return; - } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { - // For Closure imports we need to import every message type individually. - std::set required; - std::set forwards; - bool have_extensions = false; - bool have_message = false; +void Generator::GenerateRequiresForLibrary( + const GeneratorOptions& options, io::Printer* printer, + const vector& files, + std::set* provided) const { + GOOGLE_CHECK_EQ(options.import_style, GeneratorOptions::IMPORT_CLOSURE); + // For Closure imports we need to import every message type individually. + std::set required; + std::set forwards; + bool have_extensions = false; + bool have_message = false; - for (int i = 0; i < files.size(); i++) { - for (int j = 0; j < files[i]->message_type_count(); j++) { - FindRequiresForMessage(options, - files[i]->message_type(j), - &required, &forwards, &have_message); - } - if (!have_extensions && HasExtensions(files[i])) { - have_extensions = true; - } - - for (int j = 0; j < files[i]->extension_count(); j++) { - const FieldDescriptor* extension = files[i]->extension(j); - if (IgnoreField(extension)) { - continue; - } - if (extension->containing_type()->full_name() != - "google.protobuf.bridge.MessageSet") { - required.insert(GetPath(options, extension->containing_type())); - } - FindRequiresForField(options, extension, &required, &forwards); - have_extensions = true; - } + for (int i = 0; i < files.size(); i++) { + for (int j = 0; j < files[i]->message_type_count(); j++) { + FindRequiresForMessage(options, + files[i]->message_type(j), + &required, &forwards, &have_message); + } + if (!have_extensions && HasExtensions(files[i])) { + have_extensions = true; } - GenerateRequiresImpl(options, printer, &required, &forwards, provided, - /* require_jspb = */ have_message, - /* require_extension = */ have_extensions); - } else if (options.import_style == GeneratorOptions::IMPORT_COMMONJS) { - // CommonJS imports are based on files + for (int j = 0; j < files[i]->extension_count(); j++) { + const FieldDescriptor* extension = files[i]->extension(j); + if (IgnoreField(extension)) { + continue; + } + if (extension->containing_type()->full_name() != + "google.protobuf.bridge.MessageSet") { + required.insert(GetPath(options, extension->containing_type())); + } + FindRequiresForField(options, extension, &required, &forwards); + have_extensions = true; + } } + + GenerateRequiresImpl(options, printer, &required, &forwards, provided, + /* require_jspb = */ have_message, + /* require_extension = */ have_extensions); } -void Generator::GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector& fields, - std::set* provided) const { +void Generator::GenerateRequiresForExtensions( + const GeneratorOptions& options, io::Printer* printer, + const vector& fields, + std::set* provided) const { std::set required; std::set forwards; for (int i = 0; i < fields.size(); i++) { @@ -1741,17 +1942,34 @@ void Generator::GenerateClassFieldToObject(const GeneratorOptions& options, } } else { // Simple field (singular or repeated). - if (!HasFieldPresence(field) && !field->is_repeated()) { + if ((!HasFieldPresence(field) && !field->is_repeated()) || + field->type() == FieldDescriptor::TYPE_BYTES) { // Delegate to the generated get() method in order not to duplicate - // the proto3-field-default-value logic here. + // the proto3-field-default-value or byte-coercion logic here. printer->Print("msg.get$getter$()", - "getter", JSGetterName(field)); + "getter", JSGetterName(field, BYTES_B64)); } else { if (field->has_default_value()) { - printer->Print("jspb.Message.getField(msg, $index$) != null ? " - "jspb.Message.getField(msg, $index$) : $defaultValue$", + printer->Print("jspb.Message.getField(msg, $index$) == null ? " + "$defaultValue$ : ", "index", JSFieldIndex(field), "defaultValue", JSFieldDefault(field)); + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || + field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { + if (field->is_repeated()) { + printer->Print("jspb.Message.getRepeatedFloatingPointField(" + "msg, $index$)", + "index", JSFieldIndex(field)); + } else if (field->is_optional() && !field->has_default_value()) { + printer->Print("jspb.Message.getOptionalFloatingPointField(" + "msg, $index$)", + "index", JSFieldIndex(field)); + } else { + // Convert "NaN" to NaN. + printer->Print("+jspb.Message.getField(msg, $index$)", + "index", JSFieldIndex(field)); + } } else { printer->Print("jspb.Message.getField(msg, $index$)", "index", JSFieldIndex(field)); @@ -1860,6 +2078,40 @@ void Generator::GenerateClassFields(const GeneratorOptions& options, } } +void GenerateBytesWrapper(const GeneratorOptions& options, + io::Printer* printer, + const FieldDescriptor* field, + BytesMode bytes_mode) { + string type = + JSFieldTypeAnnotation(options, field, + /* force_optional = */ false, + /* force_present = */ !HasFieldPresence(field), + /* singular_if_not_packed = */ false, + bytes_mode); + printer->Print( + "/**\n" + " * $fielddef$\n" + "$comment$" + " * This is a type-conversion wrapper around `get$defname$()`\n" + " * @return {$type$}\n" + " */\n" + "$class$.prototype.get$name$ = function() {\n" + " return /** @type {$type$} */ (jspb.Message.bytes$list$As$suffix$(\n" + " this.get$defname$()));\n" + "};\n" + "\n" + "\n", + "fielddef", FieldDefinition(options, field), + "comment", FieldComments(field, bytes_mode), + "type", type, + "class", GetPath(options, field->containing_type()), + "name", JSGetterName(field, bytes_mode), + "list", field->is_repeated() ? "List" : "", + "suffix", JSByteGetterSuffix(bytes_mode), + "defname", JSGetterName(field, BYTES_DEFAULT)); +} + + void Generator::GenerateClassField(const GeneratorOptions& options, io::Printer* printer, const FieldDescriptor* field) const { @@ -1871,12 +2123,11 @@ void Generator::GenerateClassField(const GeneratorOptions& options, " * @return {$type$}\n" " */\n", "fielddef", FieldDefinition(options, field), - "comment", FieldComments(field), + "comment", FieldComments(field, BYTES_DEFAULT), "type", JSFieldTypeAnnotation(options, field, /* force_optional = */ false, /* force_present = */ false, - /* singular_if_not_packed = */ false, - /* always_singular = */ false)); + /* singular_if_not_packed = */ false)); printer->Print( "$class$.prototype.get$name$ = function() {\n" " return /** @type{$type$} */ (\n" @@ -1890,8 +2141,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "type", JSFieldTypeAnnotation(options, field, /* force_optional = */ false, /* force_present = */ false, - /* singular_if_not_packed = */ false, - /* always_singular = */ false), + /* singular_if_not_packed = */ false), "rpt", (field->is_repeated() ? "Repeated" : ""), "index", JSFieldIndex(field), "wrapperclass", SubmessageTypeRef(options, field), @@ -1905,8 +2155,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, JSFieldTypeAnnotation(options, field, /* force_optional = */ true, /* force_present = */ false, - /* singular_if_not_packed = */ false, - /* always_singular = */ false), + /* singular_if_not_packed = */ false), "returndoc", JSReturnDoc(options, field), "class", GetPath(options, field->containing_type()), "name", JSGetterName(field), @@ -1935,15 +2184,29 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "returnvalue", JSReturnClause(field)); } else { - string typed_annotation; + bool untyped = + false; // Simple (primitive) field, either singular or repeated. - { - typed_annotation = JSFieldTypeAnnotation(options, field, + + // TODO(b/26173701): Always use BYTES_DEFAULT for the getter return type; + // at this point we "lie" to non-binary users and tell the the return + // type is always base64 string, pending a LSC to migrate to typed getters. + BytesMode bytes_mode = + field->type() == FieldDescriptor::TYPE_BYTES && !options.binary ? + BYTES_B64 : BYTES_DEFAULT; + string typed_annotation = + JSFieldTypeAnnotation(options, field, /* force_optional = */ false, /* force_present = */ !HasFieldPresence(field), /* singular_if_not_packed = */ false, - /* always_singular = */ false), + /* bytes_mode = */ bytes_mode); + if (untyped) { + printer->Print( + "/**\n" + " * @return {?} Raw field, untyped.\n" + " */\n"); + } else { printer->Print( "/**\n" " * $fielddef$\n" @@ -1951,7 +2214,7 @@ void Generator::GenerateClassField(const GeneratorOptions& options, " * @return {$type$}\n" " */\n", "fielddef", FieldDefinition(options, field), - "comment", FieldComments(field), + "comment", FieldComments(field, bytes_mode), "type", typed_annotation); } @@ -1960,7 +2223,10 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "class", GetPath(options, field->containing_type()), "name", JSGetterName(field)); - { + if (untyped) { + printer->Print( + " return "); + } else { printer->Print( " return /** @type {$type$} */ (", "type", typed_annotation); @@ -1975,17 +2241,39 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "default", Proto3PrimitiveFieldDefault(field)); } else { if (field->has_default_value()) { - printer->Print("jspb.Message.getField(this, $index$) != null ? " - "jspb.Message.getField(this, $index$) : $defaultValue$", + printer->Print("jspb.Message.getField(this, $index$) == null ? " + "$defaultValue$ : ", "index", JSFieldIndex(field), "defaultValue", JSFieldDefault(field)); + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_FLOAT || + field->cpp_type() == FieldDescriptor::CPPTYPE_DOUBLE) { + if (field->is_repeated()) { + printer->Print("jspb.Message.getRepeatedFloatingPointField(" + "this, $index$)", + "index", JSFieldIndex(field)); + } else if (field->is_optional() && !field->has_default_value()) { + printer->Print("jspb.Message.getOptionalFloatingPointField(" + "this, $index$)", + "index", JSFieldIndex(field)); + } else { + // Convert "NaN" to NaN. + printer->Print("+jspb.Message.getField(this, $index$)", + "index", JSFieldIndex(field)); + } } else { printer->Print("jspb.Message.getField(this, $index$)", "index", JSFieldIndex(field)); } } - { + if (untyped) { + printer->Print( + ";\n" + "};\n" + "\n" + "\n"); + } else { printer->Print( ");\n" "};\n" @@ -1993,18 +2281,27 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "\n"); } - { + if (field->type() == FieldDescriptor::TYPE_BYTES && !untyped) { + GenerateBytesWrapper(options, printer, field, BYTES_B64); + GenerateBytesWrapper(options, printer, field, BYTES_U8); + } + + if (untyped) { + printer->Print( + "/**\n" + " * @param {*} value $returndoc$\n" + " */\n", + "returndoc", JSReturnDoc(options, field)); + } else { printer->Print( "/** @param {$optionaltype$} value $returndoc$ */\n", "optionaltype", JSFieldTypeAnnotation(options, field, /* force_optional = */ true, /* force_present = */ !HasFieldPresence(field), - /* singular_if_not_packed = */ false, - /* always_singular = */ false), + /* singular_if_not_packed = */ false), "returndoc", JSReturnDoc(options, field)); } - printer->Print( "$class$.prototype.set$name$ = function(value) {\n" " jspb.Message.set$oneoftag$Field(this, $index$", @@ -2017,14 +2314,22 @@ void Generator::GenerateClassField(const GeneratorOptions& options, "};\n" "\n" "\n", - "type", "", - "typeclose", "", + "type", + untyped ? "/** @type{string|number|boolean|Array|undefined} */(" : "", + "typeclose", untyped ? ")" : "", "oneofgroup", (field->containing_oneof() ? (", " + JSOneofArray(options, field)) : ""), "returnvalue", JSReturnClause(field), "rptvalueinit", (field->is_repeated() ? " || []" : "")); + if (untyped) { + printer->Print( + "/**\n" + " * Clears the value. $returndoc$\n" + " */\n", + "returndoc", JSReturnDoc(options, field)); + } if (HasFieldPresence(field)) { printer->Print( @@ -2162,16 +2467,18 @@ void Generator::GenerateClassDeserializeBinaryField( " var value = /** @type {$fieldtype$} */ (reader.$reader$());\n", "fieldtype", JSFieldTypeAnnotation(options, field, false, true, /* singular_if_not_packed = */ true, - /* always_singular = */ false), + BYTES_U8), "reader", JSBinaryReaderMethodName(field)); } if (field->is_repeated() && !field->is_packed()) { // Repeated fields receive a |value| one at at a time; append to array - // returned by get$name$(). - printer->Print( - " msg.get$name$().push(value);\n", - "name", JSGetterName(field)); + // returned by get$name$(). Annoyingly, we have to call 'set' after + // changing the array. + printer->Print(" msg.get$name$().push(value);\n", "name", + JSGetterName(field)); + printer->Print(" msg.set$name$(msg.get$name$());\n", "name", + JSGetterName(field)); } else { // Singular fields, and packed repeated fields, receive a |value| either as // the field's value or as the array of all the field's values; set this as @@ -2244,7 +2551,7 @@ void Generator::GenerateClassSerializeBinaryField( const FieldDescriptor* field) const { printer->Print( " f = this.get$name$();\n", - "name", JSGetterName(field)); + "name", JSGetterName(field, BYTES_U8)); if (field->is_repeated()) { printer->Print( @@ -2294,7 +2601,6 @@ void Generator::GenerateClassSerializeBinaryField( " $index$,\n" " f", "writer", JSBinaryWriterMethodName(field), - "name", JSGetterName(field), "index", SimpleItoa(field->number())); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { @@ -2356,8 +2662,7 @@ void Generator::GenerateExtension(const GeneratorOptions& options, options, field, /* force_optional = */ false, /* force_present = */ true, - /* singular_if_not_packed = */ false, - /* always_singular = */ false)); + /* singular_if_not_packed = */ false)); printer->Print( " $index$,\n" " {$name$: 0},\n" @@ -2528,7 +2833,7 @@ void Generator::GenerateFile(const GeneratorOptions& options, printer->Print("var global = Function('return this')();\n\n"); for (int i = 0; i < file->dependency_count(); i++) { - const std::string& name = file->dependency(i)->name(); + const string& name = file->dependency(i)->name(); printer->Print( "var $alias$ = require('$file$');\n", "alias", ModuleAlias(name), @@ -2543,7 +2848,7 @@ void Generator::GenerateFile(const GeneratorOptions& options, // // // Later generated code expects foo.bar = {} to exist: // foo.bar.Baz = function() { /* ... */ } - std::set provided; + set provided; // Cover the case where this file declares extensions but no messages. // This will ensure that the file-level object will be declared to hold @@ -2615,7 +2920,7 @@ bool Generator::GenerateAll(const vector& files, FindProvidesForFields(options, &printer, extensions, &provided); GenerateProvides(options, &printer, &provided); GenerateTestOnly(options, &printer); - GenerateRequires(options, &printer, files, &provided); + GenerateRequiresForLibrary(options, &printer, files, &provided); GenerateFilesInDepOrder(options, &printer, files); @@ -2629,66 +2934,20 @@ bool Generator::GenerateAll(const vector& files, return false; } } else if (options.import_style == GeneratorOptions::IMPORT_CLOSURE) { - // Collect all types, and print each type to a separate file. Pull out - // free-floating extensions while we make this pass. - map< string, vector > extensions_by_namespace; - - // If we're generating code in file-per-type mode, avoid overwriting files - // by choosing the last descriptor that writes each filename and permitting - // only those to generate code. - - // Current descriptor that will generate each filename, indexed by filename. - map desc_by_filename; - // Set of descriptors allowed to generate files. - set allowed_descs; - - for (int i = 0; i < files.size(); i++) { - // Collect all (descriptor, filename) pairs. - map descs_in_file; - for (int j = 0; j < files[i]->message_type_count(); j++) { - const Descriptor* desc = files[i]->message_type(j); - string filename = - options.output_dir + "/" + ToFileName(desc->name()) + ".js"; - descs_in_file[desc] = filename; - } - for (int j = 0; j < files[i]->enum_type_count(); j++) { - const EnumDescriptor* desc = files[i]->enum_type(j); - string filename = - options.output_dir + "/" + ToFileName(desc->name()) + ".js"; - descs_in_file[desc] = filename; - } - - // For each (descriptor, filename) pair, update the - // descriptors-by-filename map, and if a previous descriptor was already - // writing the filename, remove it from the allowed-descriptors set. - map::iterator it; - for (it = descs_in_file.begin(); it != descs_in_file.end(); ++it) { - const void* desc = it->first; - const string& filename = it->second; - if (desc_by_filename.find(filename) != desc_by_filename.end()) { - if (options.error_on_name_conflict) { - *error = "Name conflict: file name " + filename + - " would be generated by two descriptors"; - return false; - } - allowed_descs.erase(desc_by_filename[filename]); - } - desc_by_filename[filename] = desc; - allowed_descs.insert(desc); - } + set allowed_set; + if (!GenerateJspbAllowedSet(options, files, &allowed_set, error)) { + return false; } - // Generate code. for (int i = 0; i < files.size(); i++) { const FileDescriptor* file = files[i]; for (int j = 0; j < file->message_type_count(); j++) { const Descriptor* desc = file->message_type(j); - if (allowed_descs.find(desc) == allowed_descs.end()) { + if (allowed_set.count(desc) == 0) { continue; } - string filename = options.output_dir + "/" + - ToFileName(desc->name()) + ".js"; + string filename = GetMessageFileName(options, desc); google::protobuf::scoped_ptr output( context->Open(filename)); GOOGLE_CHECK(output.get()); @@ -2700,7 +2959,7 @@ bool Generator::GenerateAll(const vector& files, FindProvidesForMessage(options, &printer, desc, &provided); GenerateProvides(options, &printer, &provided); GenerateTestOnly(options, &printer); - GenerateRequires(options, &printer, desc, &provided); + GenerateRequiresForMessage(options, &printer, desc, &provided); GenerateClass(options, &printer, desc); @@ -2710,13 +2969,11 @@ bool Generator::GenerateAll(const vector& files, } for (int j = 0; j < file->enum_type_count(); j++) { const EnumDescriptor* enumdesc = file->enum_type(j); - if (allowed_descs.find(enumdesc) == allowed_descs.end()) { + if (allowed_set.count(enumdesc) == 0) { continue; } - string filename = options.output_dir + "/" + - ToFileName(enumdesc->name()) + ".js"; - + string filename = GetEnumFileName(options, enumdesc); google::protobuf::scoped_ptr output( context->Open(filename)); GOOGLE_CHECK(output.get()); @@ -2735,38 +2992,36 @@ bool Generator::GenerateAll(const vector& files, return false; } } - // Pull out all free-floating extensions and generate files for those too. - for (int j = 0; j < file->extension_count(); j++) { - const FieldDescriptor* extension = file->extension(j); - extensions_by_namespace[GetPath(options, files[i])] - .push_back(extension); - } - } + // File-level extensions (message-level extensions are generated under + // the enclosing message). + if (allowed_set.count(file) == 1) { + string filename = GetExtensionFileName(options, file); - // Generate extensions in separate files. - map< string, vector >::iterator it; - for (it = extensions_by_namespace.begin(); - it != extensions_by_namespace.end(); - ++it) { - string filename = options.output_dir + "/" + - ToFileName(it->first) + ".js"; + google::protobuf::scoped_ptr output( + context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); - google::protobuf::scoped_ptr output( - context->Open(filename)); - GOOGLE_CHECK(output.get()); - io::Printer printer(output.get(), '$'); + GenerateHeader(options, &printer); - GenerateHeader(options, &printer); + std::set provided; + vector fields; - std::set provided; - FindProvidesForFields(options, &printer, it->second, &provided); - GenerateProvides(options, &printer, &provided); - GenerateTestOnly(options, &printer); - GenerateRequires(options, &printer, it->second, &provided); + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + fields.push_back(files[i]->extension(j)); + } + } - for (int j = 0; j < it->second.size(); j++) { - if (ShouldGenerateExtension(it->second[j])) { - GenerateExtension(options, &printer, it->second[j]); + FindProvidesForFields(options, &printer, fields, &provided); + GenerateProvides(options, &printer, &provided); + GenerateTestOnly(options, &printer); + GenerateRequiresForExtensions(options, &printer, fields, &provided); + + for (int j = 0; j < files[i]->extension_count(); j++) { + if (ShouldGenerateExtension(files[i]->extension(j))) { + GenerateExtension(options, &printer, files[i]->extension(j)); + } } } } @@ -2777,7 +3032,7 @@ bool Generator::GenerateAll(const vector& files, const google::protobuf::FileDescriptor* file = files[i]; string filename = options.output_dir + "/" + GetJSFilename(file->name()); - google::protobuf::scoped_ptr output( + scoped_ptr output( context->Open(filename)); GOOGLE_CHECK(output.get()); io::Printer printer(output.get(), '$'); diff --git a/src/google/protobuf/compiler/js/js_generator.h b/src/google/protobuf/compiler/js/js_generator.h index db9178d3..6fd7ca50 100755 --- a/src/google/protobuf/compiler/js/js_generator.h +++ b/src/google/protobuf/compiler/js/js_generator.h @@ -146,19 +146,19 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { io::Printer* printer) const; // Generate goog.requires() calls. - void GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector& file, - std::set* provided) const; - void GenerateRequires(const GeneratorOptions& options, + void GenerateRequiresForLibrary(const GeneratorOptions& options, + io::Printer* printer, + const vector& files, + std::set* provided) const; + void GenerateRequiresForMessage(const GeneratorOptions& options, io::Printer* printer, const Descriptor* desc, std::set* provided) const; // For extension fields at file scope. - void GenerateRequires(const GeneratorOptions& options, - io::Printer* printer, - const vector& fields, - std::set* provided) const; + void GenerateRequiresForExtensions( + const GeneratorOptions& options, io::Printer* printer, + const vector& fields, + std::set* provided) const; void GenerateRequiresImpl(const GeneratorOptions& options, io::Printer* printer, std::set* required, diff --git a/src/google/protobuf/compiler/mock_code_generator.cc b/src/google/protobuf/compiler/mock_code_generator.cc index 121d917b..82bb3427 100644 --- a/src/google/protobuf/compiler/mock_code_generator.cc +++ b/src/google/protobuf/compiler/mock_code_generator.cc @@ -32,20 +32,26 @@ #include +#include +#include #include #ifndef _SHARED_PTR_H #include #endif +#include +#include +#include #include +#include +#include +#include +#include #include #include -#include -#include #include #include #include -#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/mock_code_generator.h b/src/google/protobuf/compiler/mock_code_generator.h index 8c8348d8..e1665f88 100644 --- a/src/google/protobuf/compiler/mock_code_generator.h +++ b/src/google/protobuf/compiler/mock_code_generator.h @@ -34,9 +34,14 @@ #define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ #include + #include namespace google { +namespace protobuf { +class FileDescriptor; +} // namespace protobuf + namespace protobuf { namespace compiler { diff --git a/src/google/protobuf/compiler/plugin.cc b/src/google/protobuf/compiler/plugin.cc index 2bebf1f3..2ff50f61 100644 --- a/src/google/protobuf/compiler/plugin.cc +++ b/src/google/protobuf/compiler/plugin.cc @@ -93,6 +93,65 @@ class GeneratorResponseContext : public GeneratorContext { const vector& parsed_files_; }; +bool GenerateCode(const CodeGeneratorRequest& request, + const CodeGenerator& generator, CodeGeneratorResponse* response, + string* error_msg) { + DescriptorPool pool; + for (int i = 0; i < request.proto_file_size(); i++) { + const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); + if (file == NULL) { + // BuildFile() already wrote an error message. + return false; + } + } + + vector parsed_files; + for (int i = 0; i < request.file_to_generate_size(); i++) { + parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); + if (parsed_files.back() == NULL) { + *error_msg = "protoc asked plugin to generate a file but " + "did not provide a descriptor for the file: " + + request.file_to_generate(i); + return false; + } + } + + GeneratorResponseContext context(response, parsed_files); + + if (generator.HasGenerateAll()) { + string error; + bool succeeded = generator.GenerateAll( + parsed_files, request.parameter(), &context, &error); + + if (!succeeded && error.empty()) { + error = "Code generator returned false but provided no error " + "description."; + } + if (!error.empty()) { + response->set_error(error); + } + } else { + for (int i = 0; i < parsed_files.size(); i++) { + const FileDescriptor* file = parsed_files[i]; + + string error; + bool succeeded = generator.Generate( + file, request.parameter(), &context, &error); + + if (!succeeded && error.empty()) { + error = "Code generator returned false but provided no error " + "description."; + } + if (!error.empty()) { + response->set_error(file->name() + ": " + error); + break; + } + } + } + + return true; +} + int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { if (argc > 1) { @@ -112,62 +171,18 @@ int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { return 1; } - DescriptorPool pool; - for (int i = 0; i < request.proto_file_size(); i++) { - const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); - if (file == NULL) { - // BuildFile() already wrote an error message. - return 1; - } - } - - vector parsed_files; - for (int i = 0; i < request.file_to_generate_size(); i++) { - parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); - if (parsed_files.back() == NULL) { - std::cerr << argv[0] << ": protoc asked plugin to generate a file but " - "did not provide a descriptor for the file: " - << request.file_to_generate(i) << std::endl; - return 1; - } - } - + string error_msg; CodeGeneratorResponse response; - GeneratorResponseContext context(&response, parsed_files); - if (generator->HasGenerateAll()) { - string error; - bool succeeded = generator->GenerateAll( - parsed_files, request.parameter(), &context, &error); - - if (!succeeded && error.empty()) { - error = "Code generator returned false but provided no error " - "description."; - } - if (!error.empty()) { - response.set_error(error); + if (GenerateCode(request, *generator, &response, &error_msg)) { + if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { + std::cerr << argv[0] << ": Error writing to stdout." << std::endl; + return 1; } } else { - for (int i = 0; i < parsed_files.size(); i++) { - const FileDescriptor* file = parsed_files[i]; - - string error; - bool succeeded = generator->Generate( - file, request.parameter(), &context, &error); - - if (!succeeded && error.empty()) { - error = "Code generator returned false but provided no error " - "description."; - } - if (!error.empty()) { - response.set_error(file->name() + ": " + error); - break; - } + if (!error_msg.empty()) { + std::cerr << argv[0] << ": " << error_msg << std::endl; } - } - - if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { - std::cerr << argv[0] << ": Error writing to stdout." << std::endl; return 1; } diff --git a/src/google/protobuf/compiler/plugin.h b/src/google/protobuf/compiler/plugin.h index 679f9bdb..d2793a9f 100644 --- a/src/google/protobuf/compiler/plugin.h +++ b/src/google/protobuf/compiler/plugin.h @@ -40,6 +40,13 @@ // } // You must link your plugin against libprotobuf and libprotoc. // +// The core part of PluginMain is to invoke the given CodeGenerator on a +// CodeGeneratorRequest to generate a CodeGeneratorResponse. This part is +// abstracted out and made into function GenerateCode so that it can be reused, +// for example, to implement a variant of PluginMain that does some +// preprocessing on the input CodeGeneratorRequest before feeding the request +// to the given code generator. +// // To get protoc to use the plugin, do one of the following: // * Place the plugin binary somewhere in the PATH and give it the name // "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you @@ -55,16 +62,27 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ #define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ +#include + #include namespace google { namespace protobuf { namespace compiler { class CodeGenerator; // code_generator.h +class CodeGeneratorRequest; +class CodeGeneratorResponse; // Implements main() for a protoc plugin exposing the given code generator. LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator); +// Generates code using the given code generator. Returns true if the code +// generation is successful. If the code geneartion fails, error_msg may be +// populated to describe the failure cause. +bool GenerateCode(const CodeGeneratorRequest& request, + const CodeGenerator& generator, CodeGeneratorResponse* response, + string* error_msg); + } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index 4d500f90..0553dd0d 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -235,7 +235,7 @@ string StringifyDefaultValue(const FieldDescriptor& field) { // infinity * 0 = nan return "(1e10000 * 0)"; } else { - return SimpleDtoa(value); + return "float(" + SimpleDtoa(value) + ")"; } } case FieldDescriptor::CPPTYPE_FLOAT: { @@ -251,7 +251,7 @@ string StringifyDefaultValue(const FieldDescriptor& field) { // infinity - infinity = nan return "(1e10000 * 0)"; } else { - return SimpleFtoa(value); + return "float(" + SimpleFtoa(value) + ")"; } } case FieldDescriptor::CPPTYPE_BOOL: diff --git a/src/google/protobuf/compiler/subprocess.cc b/src/google/protobuf/compiler/subprocess.cc index a30ac305..6e258664 100644 --- a/src/google/protobuf/compiler/subprocess.cc +++ b/src/google/protobuf/compiler/subprocess.cc @@ -361,7 +361,7 @@ bool Subprocess::Communicate(const Message& input, Message* output, string output_data; int input_pos = 0; - int max_fd = max(child_stdin_, child_stdout_); + int max_fd = std::max(child_stdin_, child_stdout_); while (child_stdout_ != -1) { fd_set read_fds; diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 7e3a7496..3ecc0a9c 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -127,6 +127,11 @@ namespace descriptor_unittest { class DescriptorTest; } // namespace descriptor_unittest +// Defined in printer.h +namespace io { +class Printer; +} // namespace io + // NB, all indices are zero-based. struct SourceLocation { int start_line; @@ -359,6 +364,9 @@ class LIBPROTOBUF_EXPORT Descriptor { // Allows tests to test CopyTo(proto, true). friend class ::google::protobuf::descriptor_unittest::DescriptorTest; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // Fill the json_name field of FieldDescriptorProto. void CopyJsonNameTo(DescriptorProto* proto) const; @@ -644,6 +652,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { private: typedef FieldOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // Fill the json_name field of FieldDescriptorProto. void CopyJsonNameTo(FieldDescriptorProto* proto) const; @@ -756,6 +767,9 @@ class LIBPROTOBUF_EXPORT OneofDescriptor { bool GetSourceLocation(SourceLocation* out_location) const; private: + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(int depth, string* contents, const DebugStringOptions& options) const; @@ -846,6 +860,9 @@ class LIBPROTOBUF_EXPORT EnumDescriptor { private: typedef EnumOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // Looks up a value by number. If the value does not exist, dynamically // creates a new EnumValueDescriptor for that value, assuming that it was // unknown. If a new descriptor is created, this is done in a thread-safe way, @@ -942,6 +959,9 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptor { private: typedef EnumValueOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(int depth, string *contents, const DebugStringOptions& options) const; @@ -1018,6 +1038,9 @@ class LIBPROTOBUF_EXPORT ServiceDescriptor { private: typedef ServiceOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(string *contents, const DebugStringOptions& options) const; @@ -1096,6 +1119,9 @@ class LIBPROTOBUF_EXPORT MethodDescriptor { private: typedef MethodOptions OptionsType; + // Allows access to GetLocationPath for annotations. + friend class ::google::protobuf::io::Printer; + // See Descriptor::DebugString(). void DebugString(int depth, string *contents, const DebugStringOptions& options) const; diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index ff0cfcf8..1338537e 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -319,7 +319,7 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_), -1); FileOptions_descriptor_ = file->message_type(9); - static const int FileOptions_offsets_[16] = { + static const int FileOptions_offsets_[15] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_), @@ -334,7 +334,6 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_enable_arenas_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, objc_class_prefix_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, csharp_namespace_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, javanano_use_deprecated_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_), }; FileOptions_reflection_ = @@ -746,7 +745,7 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr" "otobuf.MethodOptions\022\037\n\020client_streaming" "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:" - "\005false\"\256\005\n\013FileOptions\022\024\n\014java_package\030\001" + "\005false\"\207\005\n\013FileOptions\022\024\n\014java_package\030\001" " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja" "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g" "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026" @@ -758,60 +757,59 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n" "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar" "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$" - " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022+\n\037javana" - "no_use_deprecated_package\030& \001(\010B\002\030\001\022C\n\024u" - "ninterpreted_option\030\347\007 \003(\0132$.google.prot" - "obuf.UninterpretedOption\":\n\014OptimizeMode" - "\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTI" - "ME\020\003*\t\010\350\007\020\200\200\200\200\002\"\346\001\n\016MessageOptions\022&\n\027me" - "ssage_set_wire_format\030\001 \001(\010:\005false\022.\n\037no" - "_standard_descriptor_accessor\030\002 \001(\010:\005fal" - "se\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_ent" - "ry\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132" - "$.google.protobuf.UninterpretedOption*\t\010" - "\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(\016" - "2#.google.protobuf.FieldOptions.CType:\006S" - "TRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$." - "google.protobuf.FieldOptions.JSType:\tJS_" - "NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecate" - "d\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024u" - "ninterpreted_option\030\347\007 \003(\0132$.google.prot" - "obuf.UninterpretedOption\"/\n\005CType\022\n\n\006STR" - "ING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JST" - "ype\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS_" - "NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013a" - "llow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005fa" - "lse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo" - "gle.protobuf.UninterpretedOption*\t\010\350\007\020\200\200" - "\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 " - "\001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003(" - "\0132$.google.protobuf.UninterpretedOption*" - "\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecat" - "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030" - "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" - "tion*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndepr" - "ecated\030! \001(\010:\005false\022C\n\024uninterpreted_opt" - "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret" - "edOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOpt" - "ion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Unin" - "terpretedOption.NamePart\022\030\n\020identifier_v" - "alue\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032" - "\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_val" - "ue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggreg" - "ate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part" - "\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016SourceC" - "odeInfo\022:\n\010location\030\001 \003(\0132(.google.proto" - "buf.SourceCodeInfo.Location\032\206\001\n\010Location" - "\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020" - "leading_comments\030\003 \001(\t\022\031\n\021trailing_comme" - "nts\030\004 \001(\t\022!\n\031leading_detached_comments\030\006" - " \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotation" - "\030\001 \003(\0132-.google.protobuf.GeneratedCodeIn" - "fo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003(" - "\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(" - "\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020D" - "escriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032Go" - "ogle.Protobuf.Reflection", 5184); + " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024uninte" + "rpreted_option\030\347\007 \003(\0132$.google.protobuf." + "UninterpretedOption\":\n\014OptimizeMode\022\t\n\005S" + "PEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*" + "\t\010\350\007\020\200\200\200\200\002J\004\010&\020\'\"\346\001\n\016MessageOptions\022&\n\027m" + "essage_set_wire_format\030\001 \001(\010:\005false\022.\n\037n" + "o_standard_descriptor_accessor\030\002 \001(\010:\005fa" + "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_en" + "try\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\013" + "2$.google.protobuf.UninterpretedOption*\t" + "\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001(" + "\0162#.google.protobuf.FieldOptions.CType:\006" + "STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$" + ".google.protobuf.FieldOptions.JSType:\tJS" + "_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecat" + "ed\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024" + "uninterpreted_option\030\347\007 \003(\0132$.google.pro" + "tobuf.UninterpretedOption\"/\n\005CType\022\n\n\006ST" + "RING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JS" + "Type\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS" + "_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013" + "allow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005f" + "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" + "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200" + "\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001" + " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003" + "(\0132$.google.protobuf.UninterpretedOption" + "*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndepreca" + "ted\030! \001(\010:\005false\022C\n\024uninterpreted_option" + "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO" + "ption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndep" + "recated\030! \001(\010:\005false\022C\n\024uninterpreted_op" + "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" + "tedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOp" + "tion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Uni" + "nterpretedOption.NamePart\022\030\n\020identifier_" + "value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022" + "\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_va" + "lue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggre" + "gate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_par" + "t\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016Source" + "CodeInfo\022:\n\010location\030\001 \003(\0132(.google.prot" + "obuf.SourceCodeInfo.Location\032\206\001\n\010Locatio" + "n\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n" + "\020leading_comments\030\003 \001(\t\022\031\n\021trailing_comm" + "ents\030\004 \001(\t\022!\n\031leading_detached_comments\030" + "\006 \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotatio" + "n\030\001 \003(\0132-.google.protobuf.GeneratedCodeI" + "nfo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003" + "(\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001" + "(\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020" + "DescriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032G" + "oogle.Protobuf.Reflection", 5145); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -7770,7 +7768,6 @@ const int FileOptions::kDeprecatedFieldNumber; const int FileOptions::kCcEnableArenasFieldNumber; const int FileOptions::kObjcClassPrefixFieldNumber; const int FileOptions::kCsharpNamespaceFieldNumber; -const int FileOptions::kJavananoUseDeprecatedPackageFieldNumber; const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !defined(_MSC_VER) || _MSC_VER >= 1900 @@ -7808,7 +7805,6 @@ void FileOptions::SharedCtor() { cc_enable_arenas_ = false; objc_class_prefix_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); csharp_namespace_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - javanano_use_deprecated_package_ = false; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -7875,8 +7871,8 @@ void FileOptions::Clear() { go_package_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } } - if (_has_bits_[8 / 32] & 32512u) { - ZR_(java_generic_services_, javanano_use_deprecated_package_); + if (_has_bits_[8 / 32] & 16128u) { + ZR_(java_generic_services_, cc_enable_arenas_); if (has_objc_class_prefix()) { objc_class_prefix_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -8125,21 +8121,6 @@ bool FileOptions::MergePartialFromCodedStream( } else { goto handle_unusual; } - if (input->ExpectTag(304)) goto parse_javanano_use_deprecated_package; - break; - } - - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - case 38: { - if (tag == 304) { - parse_javanano_use_deprecated_package: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &javanano_use_deprecated_package_))); - set_has_javanano_use_deprecated_package(); - } else { - goto handle_unusual; - } if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } @@ -8287,11 +8268,6 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), output); } - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - if (has_javanano_use_deprecated_package()) { - ::google::protobuf::internal::WireFormatLite::WriteBool(38, this->javanano_use_deprecated_package(), output); - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) { ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( @@ -8413,11 +8389,6 @@ void FileOptions::SerializeWithCachedSizes( 37, this->csharp_namespace(), target); } - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - if (has_javanano_use_deprecated_package()) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(38, this->javanano_use_deprecated_package(), target); - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) { target = ::google::protobuf::internal::WireFormatLite:: @@ -8489,7 +8460,7 @@ int FileOptions::ByteSize() const { } } - if (_has_bits_[8 / 32] & 32512u) { + if (_has_bits_[8 / 32] & 16128u) { // optional bool java_generic_services = 17 [default = false]; if (has_java_generic_services()) { total_size += 2 + 1; @@ -8524,11 +8495,6 @@ int FileOptions::ByteSize() const { this->csharp_namespace()); } - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - if (has_javanano_use_deprecated_package()) { - total_size += 2 + 1; - } - } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -8616,9 +8582,6 @@ void FileOptions::MergeFrom(const FileOptions& from) { set_has_csharp_namespace(); csharp_namespace_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.csharp_namespace_); } - if (from.has_javanano_use_deprecated_package()) { - set_javanano_use_deprecated_package(from.javanano_use_deprecated_package()); - } } _extensions_.MergeFrom(from._extensions_); if (from._internal_metadata_.have_unknown_fields()) { @@ -8664,7 +8627,6 @@ void FileOptions::InternalSwap(FileOptions* other) { std::swap(cc_enable_arenas_, other->cc_enable_arenas_); objc_class_prefix_.Swap(&other->objc_class_prefix_); csharp_namespace_.Swap(&other->csharp_namespace_); - std::swap(javanano_use_deprecated_package_, other->javanano_use_deprecated_package_); uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); _internal_metadata_.Swap(&other->_internal_metadata_); @@ -9165,30 +9127,6 @@ void FileOptions::clear_csharp_namespace() { // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace) } -// optional bool javanano_use_deprecated_package = 38 [deprecated = true]; -bool FileOptions::has_javanano_use_deprecated_package() const { - return (_has_bits_[0] & 0x00004000u) != 0; -} -void FileOptions::set_has_javanano_use_deprecated_package() { - _has_bits_[0] |= 0x00004000u; -} -void FileOptions::clear_has_javanano_use_deprecated_package() { - _has_bits_[0] &= ~0x00004000u; -} -void FileOptions::clear_javanano_use_deprecated_package() { - javanano_use_deprecated_package_ = false; - clear_has_javanano_use_deprecated_package(); -} - bool FileOptions::javanano_use_deprecated_package() const { - // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.javanano_use_deprecated_package) - return javanano_use_deprecated_package_; -} - void FileOptions::set_javanano_use_deprecated_package(bool value) { - set_has_javanano_use_deprecated_package(); - javanano_use_deprecated_package_ = value; - // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.javanano_use_deprecated_package) -} - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 3fe07bf5..9f15bf27 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -2017,13 +2017,6 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { ::std::string* release_csharp_namespace(); void set_allocated_csharp_namespace(::std::string* csharp_namespace); - // optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - bool has_javanano_use_deprecated_package() const PROTOBUF_DEPRECATED; - void clear_javanano_use_deprecated_package() PROTOBUF_DEPRECATED; - static const int kJavananoUseDeprecatedPackageFieldNumber = 38; - bool javanano_use_deprecated_package() const PROTOBUF_DEPRECATED; - void set_javanano_use_deprecated_package(bool value) PROTOBUF_DEPRECATED; - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; int uninterpreted_option_size() const; void clear_uninterpreted_option(); @@ -2067,8 +2060,6 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline void clear_has_objc_class_prefix(); inline void set_has_csharp_namespace(); inline void clear_has_csharp_namespace(); - inline void set_has_javanano_use_deprecated_package(); - inline void clear_has_javanano_use_deprecated_package(); ::google::protobuf::internal::ExtensionSet _extensions_; @@ -2083,14 +2074,13 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { bool cc_generic_services_; int optimize_for_; ::google::protobuf::internal::ArenaStringPtr go_package_; + ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_; + ::google::protobuf::internal::ArenaStringPtr csharp_namespace_; + ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; bool java_generic_services_; bool py_generic_services_; bool deprecated_; bool cc_enable_arenas_; - bool javanano_use_deprecated_package_; - ::google::protobuf::internal::ArenaStringPtr objc_class_prefix_; - ::google::protobuf::internal::ArenaStringPtr csharp_namespace_; - ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); @@ -6194,30 +6184,6 @@ inline void FileOptions::set_allocated_csharp_namespace(::std::string* csharp_na // @@protoc_insertion_point(field_set_allocated:google.protobuf.FileOptions.csharp_namespace) } -// optional bool javanano_use_deprecated_package = 38 [deprecated = true]; -inline bool FileOptions::has_javanano_use_deprecated_package() const { - return (_has_bits_[0] & 0x00004000u) != 0; -} -inline void FileOptions::set_has_javanano_use_deprecated_package() { - _has_bits_[0] |= 0x00004000u; -} -inline void FileOptions::clear_has_javanano_use_deprecated_package() { - _has_bits_[0] &= ~0x00004000u; -} -inline void FileOptions::clear_javanano_use_deprecated_package() { - javanano_use_deprecated_package_ = false; - clear_has_javanano_use_deprecated_package(); -} -inline bool FileOptions::javanano_use_deprecated_package() const { - // @@protoc_insertion_point(field_get:google.protobuf.FileOptions.javanano_use_deprecated_package) - return javanano_use_deprecated_package_; -} -inline void FileOptions::set_javanano_use_deprecated_package(bool value) { - set_has_javanano_use_deprecated_package(); - javanano_use_deprecated_package_ = value; - // @@protoc_insertion_point(field_set:google.protobuf.FileOptions.javanano_use_deprecated_package) -} - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 3e664d59..08b15554 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -377,15 +377,13 @@ message FileOptions { // Namespace for generated classes; defaults to the package. optional string csharp_namespace = 37; - // Whether the nano proto compiler should generate in the deprecated non-nano - // suffixed package. - optional bool javanano_use_deprecated_package = 38 [deprecated = true]; - // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; // Clients can define custom options in extensions of this message. See above. extensions 1000 to max; + + reserved 38; } message MessageOptions { diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index be8e0b72..e4720a7e 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -54,6 +54,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc index b325944e..c71ce663 100644 --- a/src/google/protobuf/duration.pb.cc +++ b/src/google/protobuf/duration.pb.cc @@ -83,9 +83,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fduration_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\036google/protobuf/duration.proto\022\017google" ".protobuf\"*\n\010Duration\022\017\n\007seconds\030\001 \001(\003\022\r" - "\n\005nanos\030\002 \001(\005BP\n\023com.google.protobufB\rDu" - "rationProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Protobuf" - ".WellKnownTypesb\006proto3", 183); + "\n\005nanos\030\002 \001(\005B|\n\023com.google.protobufB\rDu" + "rationProtoP\001Z*github.com/golang/protobu" + "f/ptypes/duration\240\001\001\242\002\003GPB\252\002\036Google.Prot" + "obuf.WellKnownTypesb\006proto3", 227); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/duration.proto", &protobuf_RegisterTypes); Duration::default_instance_ = new Duration(); diff --git a/src/google/protobuf/duration.proto b/src/google/protobuf/duration.proto index 78bcc74b..96c1796d 100644 --- a/src/google/protobuf/duration.proto +++ b/src/google/protobuf/duration.proto @@ -33,6 +33,7 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/duration"; option java_package = "com.google.protobuf"; option java_outer_classname = "DurationProto"; option java_multiple_files = true; @@ -80,6 +81,7 @@ option objc_class_prefix = "GPB"; // end.nanos -= 1000000000; // } // +// message Duration { // Signed seconds of the span of time. Must be from -315,576,000,000 diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 8d689ac8..9e83bd29 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -267,6 +267,16 @@ class DynamicMessage : public Message { Metadata GetMetadata() const; + // We actually allocate more memory than sizeof(*this) when this + // class's memory is allocated via the global operator new. Thus, we need to + // manually call the global operator delete. Calling the destructor is taken + // care of for us. This makes DynamicMessage compatible with -fsized-delete. + // It doesn't work for MSVC though. +#ifndef _MSC_VER + static void operator delete(void* ptr) { + ::operator delete(ptr); + } +#endif // !_MSC_VER private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage); @@ -442,8 +452,10 @@ DynamicMessage::~DynamicMessage() { case FieldOptions::STRING: { const ::std::string* default_value = &(reinterpret_cast( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i]))->Get(NULL)); + reinterpret_cast( + type_info_->default_oneof_instance) + + type_info_->offsets[i]) + ->Get(NULL)); reinterpret_cast(field_ptr)->Destroy( default_value, NULL); break; @@ -704,7 +716,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( // Oneof fields do not use any space. if (!type->field(i)->containing_oneof()) { int field_size = FieldSpaceUsed(type->field(i)); - size = AlignTo(size, min(kSafeAlignment, field_size)); + size = AlignTo(size, std::min(kSafeAlignment, field_size)); offsets[i] = size; size += field_size; } @@ -748,7 +760,7 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( for (int j = 0; j < type->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = type->oneof_decl(i)->field(j); int field_size = OneofFieldSpaceUsed(field); - oneof_size = AlignTo(oneof_size, min(kSafeAlignment, field_size)); + oneof_size = AlignTo(oneof_size, std::min(kSafeAlignment, field_size)); offsets[field->index()] = oneof_size; oneof_size += field_size; } diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc index f2eec782..4550921b 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -80,9 +80,10 @@ void protobuf_AddDesc_google_2fprotobuf_2fempty_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\033google/protobuf/empty.proto\022\017google.pr" - "otobuf\"\007\n\005EmptyBP\n\023com.google.protobufB\n" - "EmptyProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Protob" - "uf.WellKnownTypesb\006proto3", 145); + "otobuf\"\007\n\005EmptyBy\n\023com.google.protobufB\n" + "EmptyProtoP\001Z\'github.com/golang/protobuf" + "/ptypes/empty\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Proto" + "buf.WellKnownTypesb\006proto3", 186); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/empty.proto", &protobuf_RegisterTypes); Empty::default_instance_ = new Empty(); diff --git a/src/google/protobuf/empty.proto b/src/google/protobuf/empty.proto index b96daf28..37f4cd10 100644 --- a/src/google/protobuf/empty.proto +++ b/src/google/protobuf/empty.proto @@ -33,6 +33,7 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/empty"; option java_package = "com.google.protobuf"; option java_outer_classname = "EmptyProto"; option java_multiple_files = true; diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto index 908c8a86..b1657f5f 100644 --- a/src/google/protobuf/field_mask.proto +++ b/src/google/protobuf/field_mask.proto @@ -162,6 +162,32 @@ option java_generate_equals_and_hash = true; // mask: "user.displayName,photo" // } // +// # Field Masks and Oneof Fields +// +// Field masks treat fields in oneofs just as regular fields. Consider the +// following message: +// +// message SampleMessage { +// oneof test_oneof { +// string name = 4; +// SubMessage sub_message = 9; +// } +// } +// +// The field mask can be: +// +// mask { +// paths: "name" +// } +// +// Or: +// +// mask { +// paths: "sub_message" +// } +// +// Note that oneof type names ("test_oneof" in this case) cannot be used in +// paths. message FieldMask { // The set of field mask paths. repeated string paths = 1; diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index e3a34d0a..d8354c1f 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -105,7 +105,7 @@ void CodedInputStream::BackUpInputToCurrentPosition() { inline void CodedInputStream::RecomputeBufferLimits() { buffer_end_ += buffer_size_after_limit_; - int closest_limit = min(current_limit_, total_bytes_limit_); + int closest_limit = std::min(current_limit_, total_bytes_limit_); if (closest_limit < total_bytes_read_) { // The limit position is in the current buffer. We must adjust // the buffer size accordingly. @@ -135,7 +135,7 @@ CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { // We need to enforce all limits, not just the new one, so if the previous // limit was before the new requested limit, we continue to enforce the // previous limit. - current_limit_ = min(current_limit_, old_limit); + current_limit_ = std::min(current_limit_, old_limit); RecomputeBufferLimits(); return old_limit; @@ -188,7 +188,7 @@ void CodedInputStream::SetTotalBytesLimit( // Make sure the limit isn't already past, since this could confuse other // code. int current_position = CurrentPosition(); - total_bytes_limit_ = max(current_position, total_bytes_limit); + total_bytes_limit_ = std::max(current_position, total_bytes_limit); if (warning_threshold >= 0) { total_bytes_warning_threshold_ = warning_threshold; } else { @@ -233,7 +233,7 @@ bool CodedInputStream::Skip(int count) { buffer_end_ = buffer_; // Make sure this skip doesn't try to skip past the current limit. - int closest_limit = min(current_limit_, total_bytes_limit_); + int closest_limit = std::min(current_limit_, total_bytes_limit_); int bytes_until_limit = closest_limit - total_bytes_read_; if (bytes_until_limit < count) { // We hit the limit. Skip up to it then fail. @@ -270,7 +270,7 @@ bool CodedInputStream::ReadStringFallback(string* buffer, int size) { buffer->clear(); } - int closest_limit = min(current_limit_, total_bytes_limit_); + int closest_limit = std::min(current_limit_, total_bytes_limit_); if (closest_limit != INT_MAX) { int bytes_to_limit = closest_limit - CurrentPosition(); if (bytes_to_limit > 0 && size > 0 && size <= bytes_to_limit) { diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index d1782e39..f10d4670 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -46,6 +46,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/io/gzip_stream.h b/src/google/protobuf/io/gzip_stream.h index 82445000..15b02fe3 100644 --- a/src/google/protobuf/io/gzip_stream.h +++ b/src/google/protobuf/io/gzip_stream.h @@ -43,10 +43,9 @@ #ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ #define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__ -#include - #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 7d886506..7532b098 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -42,13 +42,25 @@ namespace protobuf { namespace io { Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter) - : variable_delimiter_(variable_delimiter), - output_(output), - buffer_(NULL), - buffer_size_(0), - at_start_of_line_(true), - failed_(false) { -} + : variable_delimiter_(variable_delimiter), + output_(output), + buffer_(NULL), + buffer_size_(0), + offset_(0), + at_start_of_line_(true), + failed_(false), + annotation_collector_(NULL) {} + +Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter, + AnnotationCollector* annotation_collector) + : variable_delimiter_(variable_delimiter), + output_(output), + buffer_(NULL), + buffer_size_(0), + offset_(0), + at_start_of_line_(true), + failed_(false), + annotation_collector_(annotation_collector) {} Printer::~Printer() { // Only BackUp() if we have called Next() at least once and never failed. @@ -57,9 +69,47 @@ Printer::~Printer() { } } +bool Printer::GetSubstitutionRange(const char* varname, + pair* range) { + map >::const_iterator iter = + substitutions_.find(varname); + if (iter == substitutions_.end()) { + GOOGLE_LOG(DFATAL) << " Undefined variable in annotation: " << varname; + return false; + } + if (iter->second.first > iter->second.second) { + GOOGLE_LOG(DFATAL) << " Variable used for annotation used multiple times: " + << varname; + return false; + } + *range = iter->second; + return true; +} + +void Printer::Annotate(const char* begin_varname, const char* end_varname, + const string& file_path, const vector& path) { + if (annotation_collector_ == NULL) { + // Can't generate signatures with this Printer. + return; + } + pair begin, end; + if (!GetSubstitutionRange(begin_varname, &begin) || + !GetSubstitutionRange(end_varname, &end)) { + return; + } + if (begin.first > end.second) { + GOOGLE_LOG(DFATAL) << " Annotation has negative length from " << begin_varname + << " to " << end_varname; + } else { + annotation_collector_->AddAnnotation(begin.first, end.second, file_path, + path); + } +} + void Printer::Print(const map& variables, const char* text) { int size = strlen(text); int pos = 0; // The number of bytes we've written so far. + substitutions_.clear(); for (int i = 0; i < size; i++) { if (text[i] == '\n') { @@ -97,7 +147,17 @@ void Printer::Print(const map& variables, const char* text) { if (iter == variables.end()) { GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname; } else { + size_t begin = offset_; WriteRaw(iter->second.data(), iter->second.size()); + pair >::iterator, bool> inserted = + substitutions_.insert( + std::make_pair(varname, std::make_pair(begin, offset_))); + if (!inserted.second) { + // This variable was used multiple times. Make its span have + // negative length so we can detect it if it gets used in an + // annotation. + inserted.first->second = std::make_pair(1, 0); + } } } @@ -265,6 +325,7 @@ void Printer::WriteRaw(const char* data, int size) { // Data exceeds space in the buffer. Copy what we can and request a // new buffer. memcpy(buffer_, data, buffer_size_); + offset_ += buffer_size_; data += buffer_size_; size -= buffer_size_; void* void_buffer; @@ -277,6 +338,7 @@ void Printer::WriteRaw(const char* data, int size) { memcpy(buffer_, data, size); buffer_ += size; buffer_size_ -= size; + offset_ += size; } } // namespace io diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index f1490bbe..2ba84559 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -39,6 +39,7 @@ #include #include +#include #include namespace google { @@ -47,6 +48,47 @@ namespace io { class ZeroCopyOutputStream; // zero_copy_stream.h +// Records annotations about a Printer's output. +class LIBPROTOBUF_EXPORT AnnotationCollector { + public: + // Records that the bytes in file_path beginning with begin_offset and ending + // before end_offset are associated with the SourceCodeInfo-style path. + virtual void AddAnnotation(size_t begin_offset, size_t end_offset, + const string& file_path, + const vector& path) = 0; + + virtual ~AnnotationCollector() {} +}; + +// Records annotations about a Printer's output to the given protocol buffer, +// assuming that the buffer has an ::Annotation message exposing path, +// source_file, begin and end fields. +template +class AnnotationProtoCollector : public AnnotationCollector { + public: + // annotation_proto is the protocol buffer to which new Annotations should be + // added. It is not owned by the AnnotationProtoCollector. + explicit AnnotationProtoCollector(AnnotationProto* annotation_proto) + : annotation_proto_(annotation_proto) {} + + // Override for AnnotationCollector::AddAnnotation. + virtual void AddAnnotation(size_t begin_offset, size_t end_offset, + const string& file_path, const vector& path) { + typename AnnotationProto::Annotation* annotation = + annotation_proto_->add_annotation(); + for (int i = 0; i < path.size(); ++i) { + annotation->add_path(path[i]); + } + annotation->set_source_file(file_path); + annotation->set_begin(begin_offset); + annotation->set_end(end_offset); + } + + private: + // The protocol buffer to which new annotations should be added. + AnnotationProto* const annotation_proto_; +}; + // This simple utility class assists in code generation. It basically // allows the caller to define a set of variables and then output some // text with variable substitutions. Example usage: @@ -61,13 +103,103 @@ class ZeroCopyOutputStream; // zero_copy_stream.h // Printer aggressively enforces correct usage, crashing (with assert failures) // in the case of undefined variables in debug builds. This helps greatly in // debugging code which uses it. +// +// If a Printer is constructed with an AnnotationCollector, it will provide it +// with annotations that connect the Printer's output to paths that can identify +// various descriptors. In the above example, if person_ is a descriptor that +// identifies Bob, we can associate the output string "My name is Bob." with +// a source path pointing to that descriptor with: +// +// printer.Annotate("name", person_); +// +// The AnnotationCollector will be sent an annotation linking the output range +// covering "Bob" to the logical path provided by person_. Tools may use +// this association to (for example) link "Bob" in the output back to the +// source file that defined the person_ descriptor identifying Bob. +// +// Annotate can only examine variables substituted during the last call to +// Print. It is invalid to refer to a variable that was used multiple times +// in a single Print call. +// +// In full generality, one may specify a range of output text using a beginning +// substitution variable and an ending variable. The resulting annotation will +// span from the first character of the substituted value for the beginning +// variable to the last character of the substituted value for the ending +// variable. For example, the Annotate call above is equivalent to this one: +// +// printer.Annotate("name", "name", person_); +// +// This is useful if multiple variables combine to form a single span of output +// that should be annotated with the same source path. For example: +// +// Printer printer(output, '$'); +// map vars; +// vars["first"] = "Alice"; +// vars["last"] = "Smith"; +// printer.Print(vars, "My name is $first$ $last$."); +// printer.Annotate("first", "last", person_); +// +// This code would associate the span covering "Alice Smith" in the output with +// the person_ descriptor. +// +// Note that the beginning variable must come before (or overlap with, in the +// case of zero-sized substitution values) the ending variable. +// +// It is also sometimes useful to use variables with zero-sized values as +// markers. This avoids issues with multiple references to the same variable +// and also allows annotation ranges to span literal text from the Print +// templates: +// +// Printer printer(output, '$'); +// map vars; +// vars["foo"] = "bar"; +// vars["function"] = "call"; +// vars["mark"] = ""; +// printer.Print(vars, "$function$($foo$,$foo$)$mark$"); +// printer.Annotate("function", "rmark", call_); +// +// This code associates the span covering "call(bar,bar)" in the output with the +// call_ descriptor. + class LIBPROTOBUF_EXPORT Printer { public: // Create a printer that writes text to the given output stream. Use the // given character as the delimiter for variables. Printer(ZeroCopyOutputStream* output, char variable_delimiter); + + // Create a printer that writes text to the given output stream. Use the + // given character as the delimiter for variables. If annotation_collector + // is not null, Printer will provide it with annotations about code written + // to the stream. annotation_collector is not owned by Printer. + Printer(ZeroCopyOutputStream* output, char variable_delimiter, + AnnotationCollector* annotation_collector); + ~Printer(); + // Link a subsitution variable emitted by the last call to Print to the object + // described by descriptor. + template + void Annotate(const char* varname, const SomeDescriptor* descriptor) { + Annotate(varname, varname, descriptor); + } + + // Link the output range defined by the substitution variables as emitted by + // the last call to Print to the object described by descriptor. The range + // begins at begin_varname's value and ends after the last character of the + // value substituted for end_varname. + template + void Annotate(const char* begin_varname, const char* end_varname, + const SomeDescriptor* descriptor) { + if (annotation_collector_ == NULL) { + // Annotations aren't turned on for this Printer, so don't pay the cost + // of building the location path. + return; + } + vector path; + descriptor->GetLocationPath(&path); + Annotate(begin_varname, end_varname, descriptor->file()->name(), path); + } + // Print some text after applying variable substitutions. If a particular // variable in the text is not defined, this will crash. Variables to be // substituted are identified by their names surrounded by delimiter @@ -149,16 +281,48 @@ class LIBPROTOBUF_EXPORT Printer { bool failed() const { return failed_; } private: + // Link the output range defined by the substitution variables as emitted by + // the last call to Print to the object found at the SourceCodeInfo-style path + // in a file with path file_path. The range begins at the start of + // begin_varname's value and ends after the last character of the value + // substituted for end_varname. Note that begin_varname and end_varname + // may refer to the same variable. + void Annotate(const char* begin_varname, const char* end_varname, + const string& file_path, const vector& path); + const char variable_delimiter_; ZeroCopyOutputStream* const output_; char* buffer_; int buffer_size_; + // The current position, in bytes, in the output stream. This is equivalent + // to the total number of bytes that have been written so far. This value is + // used to calculate annotation ranges in the substitutions_ map below. + size_t offset_; string indent_; bool at_start_of_line_; bool failed_; + // A map from variable name to [start, end) offsets in the output buffer. + // These refer to the offsets used for a variable after the last call to + // Print. If a variable was used more than once, the entry used in + // this map is set to a negative-length span. For singly-used variables, the + // start offset is the beginning of the substitution; the end offset is the + // last byte of the substitution plus one (such that (end - start) is the + // length of the substituted string). + map > substitutions_; + + // Returns true and sets range to the substitution range in the output for + // varname if varname was used once in the last call to Print. If varname + // was not used, or if it was used multiple times, returns false (and + // fails a debug assertion). + bool GetSubstitutionRange(const char* varname, pair* range); + + // If non-null, annotation_collector_ is used to store annotations about + // generated code. + AnnotationCollector* const annotation_collector_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer); }; diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc index 258dd986..95f3afa2 100644 --- a/src/google/protobuf/io/printer_unittest.cc +++ b/src/google/protobuf/io/printer_unittest.cc @@ -36,6 +36,7 @@ #include #include +#include #include #include @@ -169,6 +170,196 @@ TEST(Printer, InlineVariableSubstitution) { buffer); } +// MockDescriptorFile defines only those members that Printer uses to write out +// annotations. +class MockDescriptorFile { + public: + explicit MockDescriptorFile(const string& file) : file_(file) {} + + // The mock filename for this file. + const string& name() const { return file_; } + + private: + string file_; +}; + +// MockDescriptor defines only those members that Printer uses to write out +// annotations. +class MockDescriptor { + public: + MockDescriptor(const string& file, const vector& path) + : file_(file), path_(path) {} + + // The mock file in which this descriptor was defined. + const MockDescriptorFile* file() const { return &file_; } + + private: + // Allows access to GetLocationPath. + friend class ::google::protobuf::io::Printer; + + // Copies the pre-stored path to output. + void GetLocationPath(std::vector* output) const { *output = path_; } + + MockDescriptorFile file_; + vector path_; +}; + +TEST(Printer, AnnotateMap) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + map vars; + vars["foo"] = "3"; + vars["bar"] = "5"; + printer.Print(vars, "012$foo$4$bar$\n"); + vector path_1; + path_1.push_back(33); + vector path_2; + path_2.push_back(11); + path_2.push_back(22); + MockDescriptor descriptor_1("path_1", path_1); + MockDescriptor descriptor_2("path_2", path_2); + printer.Annotate("foo", "foo", &descriptor_1); + printer.Annotate("bar", "bar", &descriptor_2); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(2, info.annotation_size()); + const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1 + ? &info.annotation(0) + : &info.annotation(1); + const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1 + ? &info.annotation(1) + : &info.annotation(0); + ASSERT_EQ(1, foo->path_size()); + ASSERT_EQ(2, bar->path_size()); + EXPECT_EQ(33, foo->path(0)); + EXPECT_EQ(11, bar->path(0)); + EXPECT_EQ(22, bar->path(1)); + EXPECT_EQ("path_1", foo->source_file()); + EXPECT_EQ("path_2", bar->source_file()); + EXPECT_EQ(3, foo->begin()); + EXPECT_EQ(4, foo->end()); + EXPECT_EQ(5, bar->begin()); + EXPECT_EQ(6, bar->end()); +} + +TEST(Printer, AnnotateInline) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5"); + vector path_1; + path_1.push_back(33); + vector path_2; + path_2.push_back(11); + path_2.push_back(22); + MockDescriptor descriptor_1("path_1", path_1); + MockDescriptor descriptor_2("path_2", path_2); + printer.Annotate("foo", "foo", &descriptor_1); + printer.Annotate("bar", "bar", &descriptor_2); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(2, info.annotation_size()); + const GeneratedCodeInfo::Annotation* foo = info.annotation(0).path_size() == 1 + ? &info.annotation(0) + : &info.annotation(1); + const GeneratedCodeInfo::Annotation* bar = info.annotation(0).path_size() == 1 + ? &info.annotation(1) + : &info.annotation(0); + ASSERT_EQ(1, foo->path_size()); + ASSERT_EQ(2, bar->path_size()); + EXPECT_EQ(33, foo->path(0)); + EXPECT_EQ(11, bar->path(0)); + EXPECT_EQ(22, bar->path(1)); + EXPECT_EQ("path_1", foo->source_file()); + EXPECT_EQ("path_2", bar->source_file()); + EXPECT_EQ(3, foo->begin()); + EXPECT_EQ(4, foo->end()); + EXPECT_EQ(5, bar->begin()); + EXPECT_EQ(6, bar->end()); +} + +TEST(Printer, AnnotateRange) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5"); + vector path; + path.push_back(33); + MockDescriptor descriptor("path", path); + printer.Annotate("foo", "bar", &descriptor); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(1, info.annotation_size()); + const GeneratedCodeInfo::Annotation* foobar = &info.annotation(0); + ASSERT_EQ(1, foobar->path_size()); + EXPECT_EQ(33, foobar->path(0)); + EXPECT_EQ("path", foobar->source_file()); + EXPECT_EQ(3, foobar->begin()); + EXPECT_EQ(6, foobar->end()); +} + +TEST(Printer, AnnotateEmptyRange) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$baz$$bam$$bar$\n", "foo", "3", "bar", "5", "baz", + "", "bam", ""); + vector path; + path.push_back(33); + MockDescriptor descriptor("path", path); + printer.Annotate("baz", "bam", &descriptor); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("012345\n", buffer); + ASSERT_EQ(1, info.annotation_size()); + const GeneratedCodeInfo::Annotation* bazbam = &info.annotation(0); + ASSERT_EQ(1, bazbam->path_size()); + EXPECT_EQ(33, bazbam->path(0)); + EXPECT_EQ("path", bazbam->source_file()); + EXPECT_EQ(5, bazbam->begin()); + EXPECT_EQ(5, bazbam->end()); +} + +TEST(Printer, AnnotateDespiteUnrelatedMultipleUses) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$foo$$bar$\n", "foo", "3", "bar", "5"); + vector path; + path.push_back(33); + MockDescriptor descriptor("path", path); + printer.Annotate("bar", "bar", &descriptor); + } + buffer[output.ByteCount()] = '\0'; + EXPECT_STREQ("0123435\n", buffer); + ASSERT_EQ(1, info.annotation_size()); + const GeneratedCodeInfo::Annotation* bar = &info.annotation(0); + ASSERT_EQ(1, bar->path_size()); + EXPECT_EQ(33, bar->path(0)); + EXPECT_EQ("path", bar->source_file()); + EXPECT_EQ(6, bar->begin()); + EXPECT_EQ(7, bar->end()); +} + TEST(Printer, Indenting) { char buffer[8192]; @@ -232,6 +423,52 @@ TEST(Printer, Death) { EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name"); EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent"); } + +TEST(Printer, AnnotateMultipleUsesDeath) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$foo$\n", "foo", "3"); + vector path; + path.push_back(33); + MockDescriptor descriptor("path", path); + EXPECT_DEBUG_DEATH(printer.Annotate("foo", "foo", &descriptor), "multiple"); + } +} + +TEST(Printer, AnnotateNegativeLengthDeath) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$bar$\n", "foo", "3", "bar", "5"); + vector path; + path.push_back(33); + MockDescriptor descriptor("path", path); + EXPECT_DEBUG_DEATH(printer.Annotate("bar", "foo", &descriptor), "negative"); + } +} + +TEST(Printer, AnnotateUndefinedDeath) { + char buffer[8192]; + ArrayOutputStream output(buffer, sizeof(buffer)); + GeneratedCodeInfo info; + AnnotationProtoCollector info_collector(&info); + { + Printer printer(&output, '$', &info_collector); + printer.Print("012$foo$4$foo$\n", "foo", "3"); + vector path; + path.push_back(33); + MockDescriptor descriptor("path", path); + EXPECT_DEBUG_DEATH(printer.Annotate("bar", "bar", &descriptor), + "Undefined"); + } +} #endif // PROTOBUF_HAS_DEATH_TEST TEST(Printer, WriteFailurePartial) { diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 3d57707c..b3550dfb 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -881,9 +881,11 @@ bool Tokenizer::ParseInteger(const string& text, uint64 max_value, uint64 result = 0; for (; *ptr != '\0'; ptr++) { int digit = DigitValue(*ptr); - GOOGLE_LOG_IF(DFATAL, digit < 0 || digit >= base) - << " Tokenizer::ParseInteger() passed text that could not have been" - " tokenized as an integer: " << CEscape(text); + if (digit < 0 || digit >= base) { + // The token provided by Tokenizer is invalid. i.e., 099 is an invalid + // token, but Tokenizer still think it's integer. + return false; + } if (digit > max_value || result > (max_value - digit) / base) { // Overflow. return false; diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h index 49885eda..64ee7d84 100644 --- a/src/google/protobuf/io/tokenizer.h +++ b/src/google/protobuf/io/tokenizer.h @@ -52,6 +52,12 @@ class ZeroCopyInputStream; // zero_copy_stream.h class ErrorCollector; class Tokenizer; +// By "column number", the proto compiler refers to a count of the number +// of bytes before a given byte, except that a tab character advances to +// the next multiple of 8 bytes. Note in particular that column numbers +// are zero-based, while many user interfaces use one-based column numbers. +typedef int ColumnNumber; + // Abstract interface for an object which collects the errors that occur // during parsing. A typical implementation might simply print the errors // to stdout. @@ -63,13 +69,14 @@ class LIBPROTOBUF_EXPORT ErrorCollector { // Indicates that there was an error in the input at the given line and // column numbers. The numbers are zero-based, so you may want to add // 1 to each before printing them. - virtual void AddError(int line, int column, const string& message) = 0; + virtual void AddError(int line, ColumnNumber column, + const string& message) = 0; // Indicates that there was a warning in the input at the given line and // column numbers. The numbers are zero-based, so you may want to add // 1 to each before printing them. - virtual void AddWarning(int /* line */, int /* column */, - const string& /* message */) { } + virtual void AddWarning(int line, ColumnNumber column, + const string& message) { } private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); @@ -124,8 +131,8 @@ class LIBPROTOBUF_EXPORT Tokenizer { // "line" and "column" specify the position of the first character of // the token within the input stream. They are zero-based. int line; - int column; - int end_column; + ColumnNumber column; + ColumnNumber end_column; }; // Get the current token. This is updated when Next() is called. Before @@ -263,7 +270,7 @@ class LIBPROTOBUF_EXPORT Tokenizer { // Line and column number of current_char_ within the whole input stream. int line_; - int column_; + ColumnNumber column_; // String to which text should be appended as we advance through it. // Call RecordTo(&str) to start recording and StopRecording() to stop. @@ -280,6 +287,7 @@ class LIBPROTOBUF_EXPORT Tokenizer { // Since we count columns we need to interpret tabs somehow. We'll take // the standard 8-character definition for lack of any way to do better. + // This must match the documentation of ColumnNumber. static const int kTabWidth = 8; // ----------------------------------------------------------------- diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index 20d50a2c..ae0811f8 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -736,19 +736,13 @@ TEST_F(TokenizerTest, ParseInteger) { EXPECT_EQ(0, ParseInteger("0x")); uint64 i; -#ifdef PROTOBUF_HAS_DEATH_TEST // death tests do not work on Windows yet + // Test invalid integers that will never be tokenized as integers. - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("zxy", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("1.2", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("08", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("0xg", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); - EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("-1", kuint64max, &i), - "passed text that could not have been tokenized as an integer"); -#endif // PROTOBUF_HAS_DEATH_TEST + EXPECT_FALSE(Tokenizer::ParseInteger("zxy", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("1.2", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("08", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("0xg", kuint64max, &i)); + EXPECT_FALSE(Tokenizer::ParseInteger("-1", kuint64max, &i)); // Test overflows. EXPECT_TRUE (Tokenizer::ParseInteger("0", 0, &i)); diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc index 083beca4..e6ca88c2 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.cc +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -69,7 +69,7 @@ ArrayInputStream::~ArrayInputStream() { bool ArrayInputStream::Next(const void** data, int* size) { if (position_ < size_) { - last_returned_size_ = min(block_size_, size_ - position_); + last_returned_size_ = std::min(block_size_, size_ - position_); *data = data_ + position_; *size = last_returned_size_; position_ += last_returned_size_; @@ -122,7 +122,7 @@ ArrayOutputStream::~ArrayOutputStream() { bool ArrayOutputStream::Next(void** data, int* size) { if (position_ < size_) { - last_returned_size_ = min(block_size_, size_ - position_); + last_returned_size_ = std::min(block_size_, size_ - position_); *data = data_ + position_; *size = last_returned_size_; position_ += last_returned_size_; @@ -157,7 +157,7 @@ StringOutputStream::~StringOutputStream() { } bool StringOutputStream::Next(void** data, int* size) { - GOOGLE_CHECK_NE(NULL, target_); + GOOGLE_CHECK(target_ != NULL); int old_size = target_->size(); // Grow the string. @@ -177,9 +177,9 @@ bool StringOutputStream::Next(void** data, int* size) { // Double the size, also make sure that the new size is at least // kMinimumSize. STLStringResizeUninitialized( - target_, - max(old_size * 2, - kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness. + target_, + std::max(old_size * 2, + kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness. } *data = mutable_string_data(target_) + old_size; @@ -189,13 +189,13 @@ bool StringOutputStream::Next(void** data, int* size) { void StringOutputStream::BackUp(int count) { GOOGLE_CHECK_GE(count, 0); - GOOGLE_CHECK_NE(NULL, target_); + GOOGLE_CHECK(target_ != NULL); GOOGLE_CHECK_LE(count, target_->size()); target_->resize(target_->size() - count); } int64 StringOutputStream::ByteCount() const { - GOOGLE_CHECK_NE(NULL, target_); + GOOGLE_CHECK(target_ != NULL); return target_->size(); } @@ -235,8 +235,8 @@ int CopyingInputStream::Skip(int count) { char junk[4096]; int skipped = 0; while (skipped < count) { - int bytes = Read(junk, min(count - skipped, - implicit_cast(sizeof(junk)))); + int bytes = + Read(junk, std::min(count - skipped, implicit_cast(sizeof(junk)))); if (bytes <= 0) { // EOF or read error. return skipped; diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index 1c397dea..cc7430ec 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index dfc62420..a182abe6 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -31,9 +31,11 @@ #ifndef GOOGLE_PROTOBUF_MAP_H__ #define GOOGLE_PROTOBUF_MAP_H__ -#include #include +#include #include // To support Visual Studio 2008 +#include +#include #include #include @@ -41,17 +43,23 @@ #include #include #include +#if __cpp_exceptions && LANG_CXX11 +#include +#endif namespace google { namespace protobuf { +// The Map and MapIterator types are provided by this header file. +// Please avoid using other types defined here, unless they are public +// types within Map or MapIterator, such as Map::value_type. template class Map; -template struct is_proto_enum; - class MapIterator; +template struct is_proto_enum; + namespace internal { template m0, m1; +// m0[0] = m1[0] = m0[1] = m1[1] = 0; +// assert(m0.begin()->first == m1.begin()->first); // Bug! +// +// Map's interface is similar to std::unordered_map, except that Map is not +// designed to play well with exceptions. Mutations to a Map do not invalidate +// a Map's iterators, pointers to elements, or references to elements. Except +// for erase(iterator), any non-const method can reorder iterators. template class Map { public: @@ -473,40 +521,56 @@ class Map { typedef size_t size_type; typedef hash hasher; - typedef equal_to key_equal; - Map() + Map(bool old_style = true) : arena_(NULL), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) {} - explicit Map(Arena* arena) - : arena_(arena), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) { - arena_->OwnDestructor(&elements_); + default_enum_value_(0), + old_style_(old_style) { + Init(); + } + explicit Map(Arena* arena, bool old_style = true) + : arena_(arena), + default_enum_value_(0), + old_style_(old_style) { + Init(); } - Map(const Map& other) : arena_(NULL), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(other.default_enum_value_) { + default_enum_value_(other.default_enum_value_), + old_style_(other.old_style_) { + Init(); insert(other.begin(), other.end()); } template - Map(const InputIt& first, const InputIt& last) + Map(const InputIt& first, const InputIt& last, bool old_style = true) : arena_(NULL), - allocator_(arena_), - elements_(0, hasher(), key_equal(), allocator_), - default_enum_value_(0) { + default_enum_value_(0), + old_style_(old_style) { + Init(); insert(first, last); } - ~Map() { clear(); } + ~Map() { + clear(); + if (arena_ == NULL) { + if (old_style_) + delete deprecated_elements_; + else + delete elements_; + } + } private: + void Init() { + if (old_style_) + deprecated_elements_ = Arena::Create( + arena_, 0, hasher(), equal_to(), + MapAllocator*> >(arena_)); + else + elements_ = + Arena::Create(arena_, 0, hasher(), Allocator(arena_)); + } + // re-implement std::allocator to use arena allocator for memory allocation. // Used for google::protobuf::Map implementation. Users should not use this class // directly. @@ -544,8 +608,8 @@ class Map { } } -#if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \ - !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID) +#if __cplusplus >= 201103L && !defined(GOOGLE_PROTOBUF_OS_APPLE) && \ + !defined(GOOGLE_PROTOBUF_OS_NACL) && !defined(GOOGLE_PROTOBUF_OS_ANDROID) template void construct(NodeType* p, Args&&... args) { new (static_cast(p)) NodeType(std::forward(args)...); @@ -589,86 +653,837 @@ class Map { friend class MapAllocator; }; - typedef MapAllocator*> > Allocator; - typedef hash_map, equal_to, Allocator> - InnerMap; + // InnerMap's key type is Key and its value type is value_type*. We use a + // custom class here and for Node, below, to ensure that k_ is at offset 0, + // allowing safe conversion from pointer to Node to pointer to Key, and vice + // versa when appropriate. + class LIBPROTOBUF_EXPORT KeyValuePair { + public: + KeyValuePair(const Key& k, value_type* v) : k_(k), v_(v) {} + + const Key& key() const { return k_; } + Key& key() { return k_; } + value_type* const value() const { return v_; } + value_type*& value() { return v_; } + + private: + Key k_; + value_type* v_; + }; + + typedef MapAllocator Allocator; + + // InnerMap is a generic hash-based map. It doesn't contain any + // protocol-buffer-specific logic. It 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 containers most of the time. + // + // The implementation doesn't need the full generality of unordered_map, + // and it doesn't have it. More bells and whistles can be added as needed. + // Some implementation details: + // 1. The hash function has type hasher and the equality function + // equal_to. We inherit from hasher to save space + // (empty-base-class optimization). + // 2. The number of buckets is a power of two. + // 3. Buckets are converted to trees in pairs: if we convert bucket b then + // buckets b and b^1 will share a tree. Invariant: buckets b and b^1 have + // the same non-NULL value iff they are sharing a tree. (An alternative + // implementation strategy would be to have a tag bit per bucket.) + // 4. As is typical for hash_map and such, the Keys and Values are always + // stored in linked list nodes. Pointers to elements are never invalidated + // until the element is deleted. + // 5. The trees' payload type is pointer to linked-list node. Tree-converting + // a bucket doesn't copy Key-Value pairs. + // 6. Once we've tree-converted a bucket, it is never converted back. However, + // the items a tree contains may wind up assigned to trees or lists upon a + // rehash. + // 7. The code requires no C++ features from C++11 or later. + // 8. Mutations to a map do not invalidate the map's iterators, pointers to + // elements, or references to elements. + // 9. Except for erase(iterator), any non-const method can reorder iterators. + class LIBPROTOBUF_EXPORT InnerMap : private hasher { + public: + typedef value_type* Value; + + InnerMap(size_type n, hasher h, Allocator alloc) + : hasher(h), + num_elements_(0), + seed_(Seed()), + table_(NULL), + alloc_(alloc) { + n = TableSize(n); + table_ = CreateEmptyTable(n); + num_buckets_ = index_of_first_non_null_ = n; + } + + ~InnerMap() { + if (table_ != NULL) { + clear(); + Dealloc(table_, num_buckets_); + } + } + + private: + enum { kMinTableSize = 8 }; + + // Linked-list nodes, as one would expect for a chaining hash table. + struct Node { + KeyValuePair kv; + Node* next; + }; + + // This is safe only if the given pointer is known to point to a Key that is + // part of a Node. + static Node* NodePtrFromKeyPtr(Key* k) { + return reinterpret_cast(k); + } + + static Key* KeyPtrFromNodePtr(Node* node) { return &node->kv.key(); } + + // Trees. The payload type is pointer to Key, so that we can query the tree + // with Keys that are not in any particular data structure. When we insert, + // though, the pointer is always pointing to a Key that is inside a Node. + struct KeyCompare { + bool operator()(const Key* n0, const Key* n1) const { return *n0 < *n1; } + }; + typedef typename Allocator::template rebind::other KeyPtrAllocator; + typedef std::set Tree; + + // iterator and const_iterator are instantiations of iterator_base. + template + class iterator_base { + public: + typedef KeyValueType& reference; + typedef KeyValueType* pointer; + typedef typename Tree::iterator TreeIterator; + + // Invariants: + // node_ is always correct. This is handy because the most common + // operations are operator* and operator-> and they only use node_. + // When node_ is set to a non-NULL value, all the other non-const fields + // are updated to be correct also, but those fields can become stale + // if the underlying map is modified. When those fields are needed they + // are rechecked, and updated if necessary. + iterator_base() : node_(NULL) {} + + explicit iterator_base(const InnerMap* m) : m_(m) { + SearchFrom(m->index_of_first_non_null_); + } + + // Any iterator_base can convert to any other. This is overkill, and we + // rely on the enclosing class to use it wisely. The standard "iterator + // can convert to const_iterator" is OK but the reverse direction is not. + template + explicit iterator_base(const iterator_base& it) + : node_(it.node_), + m_(it.m_), + bucket_index_(it.bucket_index_), + tree_it_(it.tree_it_) {} + + iterator_base(Node* n, const InnerMap* m, size_type index) + : node_(n), + m_(m), + bucket_index_(index) {} + + iterator_base(TreeIterator tree_it, const InnerMap* m, size_type index) + : node_(NodePtrFromKeyPtr(*tree_it)), + m_(m), + bucket_index_(index), + tree_it_(tree_it) { + // Invariant: iterators that use tree_it_ have an even bucket_index_. + GOOGLE_DCHECK_EQ(bucket_index_ % 2, 0); + } + + // Advance through buckets, looking for the first that isn't empty. + // If nothing non-empty is found then leave node_ == NULL. + void SearchFrom(size_type start_bucket) { + node_ = NULL; + for (bucket_index_ = start_bucket; bucket_index_ < m_->num_buckets_; + bucket_index_++) { + if (m_->TableEntryIsNonEmptyList(bucket_index_)) { + node_ = static_cast(m_->table_[bucket_index_]); + break; + } else if (m_->TableEntryIsTree(bucket_index_)) { + Tree* tree = static_cast(m_->table_[bucket_index_]); + GOOGLE_DCHECK(!tree->empty()); + tree_it_ = tree->begin(); + node_ = NodePtrFromKeyPtr(*tree_it_); + break; + } + } + } + + reference operator*() const { return node_->kv; } + pointer operator->() const { return &(operator*()); } + + friend bool operator==(const iterator_base& a, const iterator_base& b) { + return a.node_ == b.node_; + } + friend bool operator!=(const iterator_base& a, const iterator_base& b) { + return a.node_ != b.node_; + } + + iterator_base& operator++() { + if (node_->next == NULL) { + const bool is_list = revalidate_if_necessary(); + if (is_list) { + SearchFrom(bucket_index_ + 1); + } else { + GOOGLE_DCHECK_EQ(bucket_index_ & 1, 0); + Tree* tree = static_cast(m_->table_[bucket_index_]); + if (++tree_it_ == tree->end()) { + SearchFrom(bucket_index_ + 2); + } else { + node_ = NodePtrFromKeyPtr(*tree_it_); + } + } + } else { + node_ = node_->next; + } + return *this; + } + + iterator_base operator++(int /* unused */) { + iterator_base tmp = *this; + ++*this; + return tmp; + } + + // Assumes node_ and m_ are correct and non-NULL, but other fields may be + // stale. Fix them as needed. Then return true iff node_ points to a + // Node in a list. + bool revalidate_if_necessary() { + GOOGLE_DCHECK(node_ != NULL && m_ != NULL); + // Force bucket_index_ to be in range. + bucket_index_ &= (m_->num_buckets_ - 1); + // Common case: the bucket we think is relevant points to node_. + if (m_->table_[bucket_index_] == static_cast(node_)) + return true; + // Less common: the bucket is a linked list with node_ somewhere in it, + // but not at the head. + if (m_->TableEntryIsNonEmptyList(bucket_index_)) { + Node* l = static_cast(m_->table_[bucket_index_]); + while ((l = l->next) != NULL) { + if (l == node_) { + return true; + } + } + } + // Well, bucket_index_ still might be correct, but probably + // not. Revalidate just to be sure. This case is rare enough that we + // don't worry about potential optimizations, such as having a custom + // find-like method that compares Node* instead of const Key&. + iterator_base i(m_->find(*KeyPtrFromNodePtr(node_))); + bucket_index_ = i.bucket_index_; + tree_it_ = i.tree_it_; + return m_->TableEntryIsList(bucket_index_); + } + + Node* node_; + const InnerMap* m_; + size_type bucket_index_; + TreeIterator tree_it_; + }; + + public: + typedef iterator_base iterator; + typedef iterator_base const_iterator; + + iterator begin() { return iterator(this); } + iterator end() { return iterator(); } + const_iterator begin() const { return const_iterator(this); } + const_iterator end() const { return const_iterator(); } + + void clear() { + for (size_type b = 0; b < num_buckets_; b++) { + if (TableEntryIsNonEmptyList(b)) { + Node* node = static_cast(table_[b]); + table_[b] = NULL; + do { + Node* next = node->next; + DestroyNode(node); + node = next; + } while (node != NULL); + } else if (TableEntryIsTree(b)) { + Tree* tree = static_cast(table_[b]); + GOOGLE_DCHECK(table_[b] == table_[b + 1] && (b & 1) == 0); + table_[b] = table_[b + 1] = NULL; + typename Tree::iterator tree_it = tree->begin(); + do { + Node* node = NodePtrFromKeyPtr(*tree_it); + typename Tree::iterator next = tree_it; + ++next; + tree->erase(tree_it); + DestroyNode(node); + tree_it = next; + } while (tree_it != tree->end()); + DestroyTree(tree); + b++; + } + } + num_elements_ = 0; + index_of_first_non_null_ = num_buckets_; + } + + const hasher& hash_function() const { return *this; } + + static size_type max_size() { + return static_cast(1) << (sizeof(table_) >= 8 ? 60 : 28); + } + size_type size() const { return num_elements_; } + bool empty() const { return size() == 0; } + + iterator find(const Key& k) { return iterator(FindHelper(k).first); } + const_iterator find(const Key& k) const { return FindHelper(k).first; } + + // In traditional C++ style, this performs "insert if not present." + std::pair insert(const KeyValuePair& kv) { + std::pair p = FindHelper(kv.key()); + // Case 1: key was already present. + if (p.first.node_ != NULL) + return std::make_pair(iterator(p.first), false); + // Case 2: insert. + if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) { + p = FindHelper(kv.key()); + } + const size_type b = p.second; // bucket number + Node* node = Alloc(1); + alloc_.construct(&node->kv, kv); + iterator result = InsertUnique(b, node); + ++num_elements_; + return std::make_pair(result, true); + } + + // The same, but if an insertion is necessary then the value portion of the + // inserted key-value pair is left uninitialized. + std::pair insert(const Key& k) { + std::pair p = FindHelper(k); + // Case 1: key was already present. + if (p.first.node_ != NULL) + return std::make_pair(iterator(p.first), false); + // Case 2: insert. + if (ResizeIfLoadIsOutOfRange(num_elements_ + 1)) { + p = FindHelper(k); + } + const size_type b = p.second; // bucket number + Node* node = Alloc(1); + typedef typename Allocator::template rebind::other KeyAllocator; + KeyAllocator(alloc_).construct(&node->kv.key(), k); + iterator result = InsertUnique(b, node); + ++num_elements_; + return std::make_pair(result, true); + } + + Value& operator[](const Key& k) { + KeyValuePair kv(k, Value()); + return insert(kv).first->value(); + } + + void erase(iterator it) { + GOOGLE_DCHECK_EQ(it.m_, this); + const bool is_list = it.revalidate_if_necessary(); + const size_type b = it.bucket_index_; + Node* const item = it.node_; + if (is_list) { + GOOGLE_DCHECK(TableEntryIsNonEmptyList(b)); + Node* head = static_cast(table_[b]); + head = EraseFromLinkedList(item, head); + table_[b] = static_cast(head); + } else { + GOOGLE_DCHECK(TableEntryIsTree(b)); + Tree* tree = static_cast(table_[b]); + tree->erase(it.tree_it_); + if (tree->empty()) { + DestroyTree(tree); + table_[b] = table_[b ^ 1] = NULL; + } + } + DestroyNode(item); + --num_elements_; + if (GOOGLE_PREDICT_FALSE(b == index_of_first_non_null_)) { + while (index_of_first_non_null_ < num_buckets_ && + table_[index_of_first_non_null_] == 0) { + ++index_of_first_non_null_; + } + } + } + + private: + std::pair FindHelper(const Key& k) const { + size_type b = BucketNumber(k); + if (TableEntryIsNonEmptyList(b)) { + Node* node = static_cast(table_[b]); + do { + if (IsMatch(*KeyPtrFromNodePtr(node), k)) { + return std::make_pair(const_iterator(node, this, b), b); + } else { + node = node->next; + } + } while (node != NULL); + } else if (TableEntryIsTree(b)) { + GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]); + b &= ~static_cast(1); + Tree* tree = static_cast(table_[b]); + Key* key = const_cast(&k); + typename Tree::iterator tree_it = tree->find(key); + if (tree_it != tree->end()) { + return std::make_pair(const_iterator(tree_it, this, b), b); + } + } + return std::make_pair(end(), b); + } + + // 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 and b^1 to share. + // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct + // bucket. num_elements_ is not modified. + iterator InsertUnique(size_type b, Node* node) { + // In practice, the code that led to this point may have already + // determined whether we are inserting into an empty list, a short list, + // or whatever. But it's probably cheap enough to recompute that here; + // it's likely that we're inserting into an empty or short list. + iterator result; + GOOGLE_DCHECK(find(*KeyPtrFromNodePtr(node)) == end()); + if (TableEntryIsEmpty(b)) { + result = InsertUniqueInList(b, node); + } else if (TableEntryIsNonEmptyList(b)) { + if (GOOGLE_PREDICT_FALSE(TableEntryIsTooLong(b))) { + TreeConvert(b); + result = InsertUniqueInTree(b, node); + } else { + result = InsertUniqueInList(b, node); + } + } else { + result = InsertUniqueInTree(b, node); + } + index_of_first_non_null_ = + std::min(index_of_first_non_null_, result.bucket_index_); + return result; + } + + // Helper for InsertUnique. Handles the case where bucket b is a + // not-too-long linked list. + iterator InsertUniqueInList(size_type b, Node* node) { + node->next = static_cast(table_[b]); + table_[b] = static_cast(node); + return iterator(node, this, b); + } + + // Helper for InsertUnique. Handles the case where bucket b points to a + // Tree. + iterator InsertUniqueInTree(size_type b, Node* node) { + GOOGLE_DCHECK_EQ(table_[b], table_[b ^ 1]); + // Maintain the invariant that node->next is NULL for all Nodes in Trees. + node->next = NULL; + return iterator(static_cast(table_[b]) + ->insert(KeyPtrFromNodePtr(node)) + .first, + this, b & ~static_cast(1)); + } + + // Returns whether it did resize. Currently this is only used when + // num_elements_ increases, though it could be used in other situations. + // It checks for load too low as well as load too high: because any number + // of erases can occur between inserts, the load could be as low as 0 here. + // Resizing to a lower size is not always helpful, but failing to do so can + // destroy the expected big-O bounds for some operations. By having the + // policy that sometimes we resize down as well as up, clients can easily + // keep O(size()) = O(number of buckets) if they want that. + bool ResizeIfLoadIsOutOfRange(size_type new_size) { + const size_type kMaxMapLoadTimes16 = 12; // controls RAM vs CPU tradeoff + const size_type hi_cutoff = num_buckets_ * kMaxMapLoadTimes16 / 16; + const size_type lo_cutoff = hi_cutoff / 4; + // We don't care how many elements are in trees. If a lot are, + // we may resize even though there are many empty buckets. In + // practice, this seems fine. + if (GOOGLE_PREDICT_FALSE(new_size >= hi_cutoff)) { + if (num_buckets_ <= max_size() / 2) { + Resize(num_buckets_ * 2); + return true; + } + } else if (GOOGLE_PREDICT_FALSE(new_size <= lo_cutoff && + num_buckets_ > kMinTableSize)) { + size_type lg2_of_size_reduction_factor = 1; + // It's possible we want to shrink a lot here... size() could even be 0. + // So, estimate how much to shrink by making sure we don't shrink so + // much that we would need to grow the table after a few inserts. + const size_type hypothetical_size = new_size * 5 / 4 + 1; + while ((hypothetical_size << lg2_of_size_reduction_factor) < + hi_cutoff) { + ++lg2_of_size_reduction_factor; + } + size_type new_num_buckets = std::max( + kMinTableSize, num_buckets_ >> lg2_of_size_reduction_factor); + if (new_num_buckets != num_buckets_) { + Resize(new_num_buckets); + return true; + } + } + return false; + } + + // Resize to the given number of buckets. + void Resize(size_t new_num_buckets) { + GOOGLE_DCHECK_GE(new_num_buckets, kMinTableSize); + void** const old_table = table_; + const size_type old_table_size = num_buckets_; + num_buckets_ = new_num_buckets; + table_ = CreateEmptyTable(num_buckets_); + const size_type start = index_of_first_non_null_; + index_of_first_non_null_ = 0; + for (size_type i = start; i < old_table_size; i++) { + if (TableEntryIsNonEmptyList(old_table, i)) { + TransferList(old_table, i); + } else if (TableEntryIsTree(old_table, i)) { + TransferTree(old_table, i++); + } + } + Dealloc(old_table, old_table_size); + } + + void TransferList(void* const* table, size_type index) { + Node* node = static_cast(table[index]); + do { + Node* next = node->next; + InsertUnique(BucketNumber(*KeyPtrFromNodePtr(node)), node); + node = next; + } while (node != NULL); + } + + void TransferTree(void* const* table, size_type index) { + Tree* tree = static_cast(table[index]); + typename Tree::iterator tree_it = tree->begin(); + do { + Node* node = NodePtrFromKeyPtr(*tree_it); + InsertUnique(BucketNumber(**tree_it), node); + } while (++tree_it != tree->end()); + DestroyTree(tree); + } + + Node* EraseFromLinkedList(Node* item, Node* head) { + if (head == item) { + return head->next; + } else { + head->next = EraseFromLinkedList(item, head->next); + return head; + } + } + + bool TableEntryIsEmpty(size_type b) const { + return TableEntryIsEmpty(table_, b); + } + bool TableEntryIsNonEmptyList(size_type b) const { + return TableEntryIsNonEmptyList(table_, b); + } + bool TableEntryIsTree(size_type b) const { + return TableEntryIsTree(table_, b); + } + bool TableEntryIsList(size_type b) const { + return TableEntryIsList(table_, b); + } + static bool TableEntryIsEmpty(void* const* table, size_type b) { + return table[b] == 0; + } + static bool TableEntryIsNonEmptyList(void* const* table, size_type b) { + return table[b] != 0 && table[b] != table[b ^ 1]; + } + static bool TableEntryIsTree(void* const* table, size_type b) { + return !TableEntryIsEmpty(table, b) && + !TableEntryIsNonEmptyList(table, b); + } + static bool TableEntryIsList(void* const* table, size_type b) { + return !TableEntryIsTree(table, b); + } + + void TreeConvert(size_type b) { + GOOGLE_DCHECK(!TableEntryIsTree(b) && !TableEntryIsTree(b ^ 1)); + typename Allocator::template rebind::other tree_allocator(alloc_); + Tree* tree = tree_allocator.allocate(1); + // We want to use the three-arg form of construct, if it exists, but we + // create a temporary and use the two-arg construct that's known to exist. + // It's clunky, but the compiler should be able to generate more-or-less + // the same code. + tree_allocator.construct(tree, + Tree(KeyCompare(), KeyPtrAllocator(alloc_))); + // Now the tree is ready to use. + size_type count = CopyListToTree(b, tree) + CopyListToTree(b ^ 1, tree); + GOOGLE_DCHECK_EQ(count, tree->size()); + table_[b] = table_[b ^ 1] = static_cast(tree); + } + + // Copy a linked list in the given bucket to a tree. + // Returns the number of things it copied. + size_type CopyListToTree(size_type b, Tree* tree) { + size_type count = 0; + Node* node = static_cast(table_[b]); + while (node != NULL) { + tree->insert(KeyPtrFromNodePtr(node)); + ++count; + Node* next = node->next; + node->next = NULL; + node = next; + } + return count; + } + + // Return whether table_[b] is a linked list that seems awfully long. + // Requires table_[b] to point to a non-empty linked list. + bool TableEntryIsTooLong(size_type b) { + const int kMaxLength = 8; + size_type count = 0; + Node* node = static_cast(table_[b]); + do { + ++count; + node = node->next; + } while (node != NULL); + // Invariant: no linked list ever is more than kMaxLength in length. + GOOGLE_DCHECK_LE(count, kMaxLength); + return count >= kMaxLength; + } + + size_type BucketNumber(const Key& k) const { + // We inherit from hasher, so one-arg operator() provides a hash function. + size_type h = (*this)(k); + // To help prevent people from making assumptions about the hash function, + // we use the seed differently depending on NDEBUG. The default hash + // function, the seeding, etc., are all likely to change in the future. +#ifndef NDEBUG + return (h * (seed_ | 1)) & (num_buckets_ - 1); +#else + return (h + seed_) & (num_buckets_ - 1); +#endif + } + + bool IsMatch(const Key& k0, const Key& k1) const { + return std::equal_to()(k0, k1); + } + + // Return a power of two no less than max(kMinTableSize, n). + // Assumes either n < kMinTableSize or n is a power of two. + size_type TableSize(size_type n) { + return n < kMinTableSize ? kMinTableSize : n; + } + + // Use alloc_ to allocate an array of n objects of type U. + template + U* Alloc(size_type n) { + typedef typename Allocator::template rebind::other alloc_type; + return alloc_type(alloc_).allocate(n); + } + + // Use alloc_ to deallocate an array of n objects of type U. + template + void Dealloc(U* t, size_type n) { + typedef typename Allocator::template rebind::other alloc_type; + alloc_type(alloc_).deallocate(t, n); + } + + void DestroyNode(Node* node) { + alloc_.destroy(&node->kv); + Dealloc(node, 1); + } + + void DestroyTree(Tree* tree) { + typename Allocator::template rebind::other tree_allocator(alloc_); + tree_allocator.destroy(tree); + tree_allocator.deallocate(tree, 1); + } + + void** CreateEmptyTable(size_type n) { + GOOGLE_DCHECK(n >= kMinTableSize); + GOOGLE_DCHECK_EQ(n & (n - 1), 0); + void** result = Alloc(n); + memset(result, 0, n * sizeof(result[0])); + return result; + } + + // Return a randomish value. + size_type Seed() const { + // random_device can throw, so avoid it unless we are compiling with + // exceptions enabled. +#if __cpp_exceptions && LANG_CXX11 + try { + std::random_device rd; + std::knuth_b knuth(rd()); + std::uniform_int_distribution u; + return u(knuth); + } catch (...) { } +#endif + size_type s = static_cast(reinterpret_cast(this)); +#if defined(__x86_64__) && defined(__GNUC__) + uint32 hi, lo; + asm("rdtsc" : "=a" (lo), "=d" (hi)); + s += ((static_cast(hi) << 32) | lo); +#endif + return s; + } + + size_type num_elements_; + size_type num_buckets_; + size_type seed_; + size_type index_of_first_non_null_; + void** table_; // an array with num_buckets_ entries + Allocator alloc_; + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(InnerMap); + }; // end of class InnerMap + + typedef hash_map, equal_to, + MapAllocator*> > > + DeprecatedInnerMap; public: // Iterators + class LIBPROTOBUF_EXPORT iterator_base { + public: + // We support "old style" and "new style" iterators for now. This is + // temporary. Also, for "iterator()" we have an unknown category. + // TODO(gpike): get rid of this. + enum IteratorStyle { kUnknown, kOld, kNew }; + explicit iterator_base(IteratorStyle style) : iterator_style_(style) {} + + bool OldStyle() const { + GOOGLE_DCHECK_NE(iterator_style_, kUnknown); + return iterator_style_ == kOld; + } + bool UnknownStyle() const { + return iterator_style_ == kUnknown; + } + bool SameStyle(const iterator_base& other) const { + return iterator_style_ == other.iterator_style_; + } + + private: + IteratorStyle iterator_style_; + }; + class const_iterator - : public std::iterator { typedef typename InnerMap::const_iterator InnerIt; + typedef typename DeprecatedInnerMap::const_iterator DeprecatedInnerIt; public: - const_iterator() {} - explicit const_iterator(const InnerIt& it) : it_(it) {} + const_iterator() : iterator_base(iterator_base::kUnknown) {} + explicit const_iterator(const DeprecatedInnerIt& dit) + : iterator_base(iterator_base::kOld), dit_(dit) {} + explicit const_iterator(const InnerIt& it) + : iterator_base(iterator_base::kNew), it_(it) {} - const_reference operator*() const { return *it_->second; } - const_pointer operator->() const { return it_->second; } + const_iterator(const const_iterator& other) + : iterator_base(other), it_(other.it_), dit_(other.dit_) {} + + const_reference operator*() const { + return this->OldStyle() ? *dit_->second : *it_->value(); + } + const_pointer operator->() const { return &(operator*()); } const_iterator& operator++() { - ++it_; + if (this->OldStyle()) + ++dit_; + else + ++it_; return *this; } - const_iterator operator++(int) { return const_iterator(it_++); } + const_iterator operator++(int) { + return this->OldStyle() ? const_iterator(dit_++) : const_iterator(it_++); + } friend bool operator==(const const_iterator& a, const const_iterator& b) { - return a.it_ == b.it_; + if (!a.SameStyle(b)) return false; + if (a.UnknownStyle()) return true; + return a.OldStyle() ? (a.dit_ == b.dit_) : (a.it_ == b.it_); } friend bool operator!=(const const_iterator& a, const const_iterator& b) { - return a.it_ != b.it_; + return !(a == b); } private: InnerIt it_; + DeprecatedInnerIt dit_; }; - class iterator : public std::iterator { + class iterator : private iterator_base, + public std::iterator { typedef typename InnerMap::iterator InnerIt; + typedef typename DeprecatedInnerMap::iterator DeprecatedInnerIt; public: - iterator() {} - explicit iterator(const InnerIt& it) : it_(it) {} + iterator() : iterator_base(iterator_base::kUnknown) {} + explicit iterator(const DeprecatedInnerIt& dit) + : iterator_base(iterator_base::kOld), dit_(dit) {} + explicit iterator(const InnerIt& it) + : iterator_base(iterator_base::kNew), it_(it) {} - reference operator*() const { return *it_->second; } - pointer operator->() const { return it_->second; } + reference operator*() const { + return this->OldStyle() ? *dit_->second : *it_->value(); + } + pointer operator->() const { return &(operator*()); } iterator& operator++() { - ++it_; + if (this->OldStyle()) + ++dit_; + else + ++it_; return *this; } - iterator operator++(int) { return iterator(it_++); } + iterator operator++(int) { + return this->OldStyle() ? iterator(dit_++) : iterator(it_++); + } - // Implicitly convertible to const_iterator. - operator const_iterator() const { return const_iterator(it_); } + // Allow implicit conversion to const_iterator. + operator const_iterator() const { + return this->OldStyle() ? + const_iterator(typename DeprecatedInnerMap::const_iterator(dit_)) : + const_iterator(typename InnerMap::const_iterator(it_)); + } friend bool operator==(const iterator& a, const iterator& b) { - return a.it_ == b.it_; + if (!a.SameStyle(b)) return false; + if (a.UnknownStyle()) return true; + return a.OldStyle() ? a.dit_ == b.dit_ : a.it_ == b.it_; } friend bool operator!=(const iterator& a, const iterator& b) { - return a.it_ != b.it_; + return !(a == b); } private: friend class Map; + InnerIt it_; + DeprecatedInnerIt dit_; }; - iterator begin() { return iterator(elements_.begin()); } - iterator end() { return iterator(elements_.end()); } - const_iterator begin() const { return const_iterator(elements_.begin()); } - const_iterator end() const { return const_iterator(elements_.end()); } + iterator begin() { + return old_style_ ? iterator(deprecated_elements_->begin()) + : iterator(elements_->begin()); + } + iterator end() { + return old_style_ ? iterator(deprecated_elements_->end()) + : iterator(elements_->end()); + } + const_iterator begin() const { + return old_style_ ? const_iterator(deprecated_elements_->begin()) + : const_iterator(iterator(elements_->begin())); + } + const_iterator end() const { + return old_style_ ? const_iterator(deprecated_elements_->end()) + : const_iterator(iterator(elements_->end())); + } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } // Capacity - size_type size() const { return elements_.size(); } - bool empty() const { return elements_.empty(); } + size_type size() const { + return old_style_ ? deprecated_elements_->size() : elements_->size(); + } + bool empty() const { return size() == 0; } // Element access T& operator[](const key_type& key) { - value_type** value = &elements_[key]; + value_type** value = + old_style_ ? &(*deprecated_elements_)[key] : &(*elements_)[key]; if (*value == NULL) { *value = CreateValueTypeInternal(key); internal::MapValueInitializer::value, @@ -690,13 +1505,16 @@ class Map { // Lookup size_type count(const key_type& key) const { - return elements_.count(key); + if (find(key) != end()) assert(key == find(key)->first); + return find(key) == end() ? 0 : 1; } const_iterator find(const key_type& key) const { - return const_iterator(elements_.find(key)); + return old_style_ ? const_iterator(deprecated_elements_->find(key)) + : const_iterator(iterator(elements_->find(key))); } iterator find(const key_type& key) { - return iterator(elements_.find(key)); + return old_style_ ? iterator(deprecated_elements_->find(key)) + : iterator(elements_->find(key)); } std::pair equal_range( const key_type& key) const { @@ -720,13 +1538,22 @@ class Map { // insert std::pair insert(const value_type& value) { - iterator it = find(value.first); - if (it != end()) { - return std::pair(it, false); + if (old_style_) { + iterator it = find(value.first); + if (it != end()) { + return std::pair(it, false); + } else { + return std::pair( + iterator(deprecated_elements_->insert(std::pair( + value.first, CreateValueTypeInternal(value))).first), true); + } } else { - return std::pair( - iterator(elements_.insert(std::pair( - value.first, CreateValueTypeInternal(value))).first), true); + std::pair p = + elements_->insert(value.first); + if (p.second) { + p.first->value() = CreateValueTypeInternal(value); + } + return std::pair(iterator(p.first), p.second); } } template @@ -739,33 +1566,31 @@ class Map { } } - // Erase + // Erase and clear size_type erase(const key_type& key) { - typename InnerMap::iterator it = elements_.find(key); - if (it == elements_.end()) { + iterator it = find(key); + if (it == end()) { return 0; } else { - if (arena_ == NULL) delete it->second; - elements_.erase(it); + erase(it); return 1; } } - void erase(iterator pos) { - if (arena_ == NULL) delete pos.it_->second; - elements_.erase(pos.it_); + iterator erase(iterator pos) { + if (arena_ == NULL) delete pos.operator->(); + iterator i = pos++; + if (old_style_) + deprecated_elements_->erase(i.dit_); + else + elements_->erase(i.it_); + return pos; } void erase(iterator first, iterator last) { - for (iterator it = first; it != last;) { - if (arena_ == NULL) delete it.it_->second; - elements_.erase((it++).it_); + while (first != last) { + first = erase(first); } } - void clear() { - for (iterator it = begin(); it != end(); ++it) { - if (arena_ == NULL) delete it.it_->second; - } - elements_.clear(); - } + void clear() { erase(begin(), end()); } // Assign Map& operator=(const Map& other) { @@ -776,6 +1601,13 @@ class Map { return *this; } + // Access to hasher. Currently this returns a copy, but it may + // be modified to return a const reference in the future. + hasher hash_function() const { + return old_style_ ? deprecated_elements_->hash_function() + : elements_->hash_function(); + } + private: // Set default enum value only for proto2 map field whose value is enum type. void SetDefaultEnumValue(int default_enum_value) { @@ -810,9 +1642,15 @@ class Map { } Arena* arena_; - Allocator allocator_; - InnerMap elements_; int default_enum_value_; + // The following is a tagged union because we support two map styles + // for now. + // TODO(gpike): get rid of the old style. + const bool old_style_; + union { + InnerMap* elements_; + DeprecatedInnerMap* deprecated_elements_; + }; friend class ::google::protobuf::Arena; typedef void InternalArenaConstructable_; @@ -833,6 +1671,12 @@ struct hash { size_t operator()(const google::protobuf::MapKey& map_key) const { switch (map_key.type()) { + case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: + case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: + case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: + case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Unsupported"; + break; case google::protobuf::FieldDescriptor::CPPTYPE_STRING: return hash()(map_key.GetStringValue()); case google::protobuf::FieldDescriptor::CPPTYPE_INT64: @@ -845,11 +1689,6 @@ struct hash { return hash< ::google::protobuf::uint32>()(map_key.GetUInt32Value()); case google::protobuf::FieldDescriptor::CPPTYPE_BOOL: return hash()(map_key.GetBoolValue()); - case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: - case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: - case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: - case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Can't get here."; } GOOGLE_LOG(FATAL) << "Can't get here."; return 0; @@ -857,26 +1696,7 @@ struct hash { bool operator()(const google::protobuf::MapKey& map_key1, const google::protobuf::MapKey& map_key2) const { - switch (map_key1.type()) { -#define COMPARE_CPPTYPE(CPPTYPE, CPPTYPE_METHOD) \ - case google::protobuf::FieldDescriptor::CPPTYPE_##CPPTYPE: \ - return map_key1.Get##CPPTYPE_METHOD##Value() < \ - map_key2.Get##CPPTYPE_METHOD##Value(); - COMPARE_CPPTYPE(STRING, String) - COMPARE_CPPTYPE(INT64, Int64) - COMPARE_CPPTYPE(INT32, Int32) - COMPARE_CPPTYPE(UINT64, UInt64) - COMPARE_CPPTYPE(UINT32, UInt32) - COMPARE_CPPTYPE(BOOL, Bool) -#undef COMPARE_CPPTYPE - case google::protobuf::FieldDescriptor::CPPTYPE_DOUBLE: - case google::protobuf::FieldDescriptor::CPPTYPE_FLOAT: - case google::protobuf::FieldDescriptor::CPPTYPE_ENUM: - case google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE: - GOOGLE_LOG(FATAL) << "Can't get here."; - } - GOOGLE_LOG(FATAL) << "Can't get here."; - return true; + return map_key1 < map_key2; } }; GOOGLE_PROTOBUF_HASH_NAMESPACE_DECLARATION_END diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 451b02e8..1f3de4fa 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -28,12 +28,16 @@ // (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 +#include #include #include #ifndef _SHARED_PTR_H #include #endif +#include #include +#include #include #include @@ -62,6 +66,7 @@ #include #include #include +#include #include #include #include @@ -79,10 +84,11 @@ namespace internal { // Map API Test ===================================================== -class MapImplTest : public ::testing::Test { +// Parameterized tests on whether to use old style maps. +class MapImplTest : public testing::TestWithParam { protected: MapImplTest() - : map_ptr_(new Map), + : map_ptr_(new Map(GetParam())), map_(*map_ptr_), const_map_(*map_ptr_) { EXPECT_TRUE(map_.empty()); @@ -159,7 +165,7 @@ class MapImplTest : public ::testing::Test { const Map& const_map_; }; -TEST_F(MapImplTest, OperatorBracket) { +TEST_P(MapImplTest, OperatorBracket) { int32 key = 0; int32 value1 = 100; int32 value2 = 101; @@ -173,7 +179,7 @@ TEST_F(MapImplTest, OperatorBracket) { ExpectSingleElement(key, value2); } -TEST_F(MapImplTest, OperatorBracketNonExist) { +TEST_P(MapImplTest, OperatorBracketNonExist) { int32 key = 0; int32 default_value = 0; @@ -181,7 +187,7 @@ TEST_F(MapImplTest, OperatorBracketNonExist) { ExpectSingleElement(key, default_value); } -TEST_F(MapImplTest, MutableAt) { +TEST_P(MapImplTest, MutableAt) { int32 key = 0; int32 value1 = 100; int32 value2 = 101; @@ -195,15 +201,15 @@ TEST_F(MapImplTest, MutableAt) { #ifdef PROTOBUF_HAS_DEATH_TEST -TEST_F(MapImplTest, MutableAtNonExistDeathTest) { +TEST_P(MapImplTest, MutableAtNonExistDeathTest) { EXPECT_DEATH(map_.at(0), ""); } -TEST_F(MapImplTest, ImmutableAtNonExistDeathTest) { +TEST_P(MapImplTest, ImmutableAtNonExistDeathTest) { EXPECT_DEATH(const_map_.at(0), ""); } -TEST_F(MapImplTest, UsageErrors) { +TEST_P(MapImplTest, UsageErrors) { MapKey key; key.SetInt64Value(1); EXPECT_DEATH(key.GetUInt64Value(), @@ -220,23 +226,23 @@ TEST_F(MapImplTest, UsageErrors) { #endif // PROTOBUF_HAS_DEATH_TEST -TEST_F(MapImplTest, CountNonExist) { +TEST_P(MapImplTest, CountNonExist) { EXPECT_EQ(0, map_.count(0)); } -TEST_F(MapImplTest, MutableFindNonExist) { +TEST_P(MapImplTest, MutableFindNonExist) { EXPECT_TRUE(map_.end() == map_.find(0)); } -TEST_F(MapImplTest, ImmutableFindNonExist) { +TEST_P(MapImplTest, ImmutableFindNonExist) { EXPECT_TRUE(const_map_.end() == const_map_.find(0)); } -TEST_F(MapImplTest, ConstEnd) { +TEST_P(MapImplTest, ConstEnd) { EXPECT_TRUE(const_map_.end() == const_map_.cend()); } -TEST_F(MapImplTest, GetReferenceFromIterator) { +TEST_P(MapImplTest, GetReferenceFromIterator) { for (int i = 0; i < 10; i++) { map_[i] = i; } @@ -259,7 +265,7 @@ TEST_F(MapImplTest, GetReferenceFromIterator) { } } -TEST_F(MapImplTest, IteratorBasic) { +TEST_P(MapImplTest, IteratorBasic) { map_[0] = 0; // Default constructible (per forward iterator requirements). @@ -281,6 +287,281 @@ TEST_F(MapImplTest, IteratorBasic) { EXPECT_TRUE(it == cit); } +template +static int64 median(Iterator i0, Iterator i1) { + vector v(i0, i1); + std::nth_element(v.begin(), v.begin() + v.size() / 2, v.end()); + return v[v.size() / 2]; +} + +static int64 Now() { + return google::protobuf::util::TimeUtil::TimestampToNanoseconds( + google::protobuf::util::TimeUtil::GetCurrentTime()); +} + +// A naive begin() implementation will cause begin() to get slower and slower +// if one erases elements at the "front" of the hash map, and we'd like to +// avoid that, as std::unordered_map does. +TEST_P(MapImplTest, BeginIsFast) { + if (GetParam()) return; + Map map(false); // This test uses new-style maps only. + const int kTestSize = 250000; + for (int i = 0; i < kTestSize; i++) { + map[i] = i; + } + vector times; + // We're going to do map.erase(map.begin()) over and over again. But, + // just in case one iteration is fast compared to the granularity of + // our time keeping, we measure kChunkSize iterations per outer-loop iter. + const int kChunkSize = 1000; + GOOGLE_CHECK_EQ(kTestSize % kChunkSize, 0); + do { + const int64 start = Now(); + for (int i = 0; i < kChunkSize; i++) { + map.erase(map.begin()); + } + const int64 end = Now(); + if (end > start) { + times.push_back(end - start); + } + } while (!map.empty()); + if (times.size() < .99 * kTestSize / kChunkSize) { + GOOGLE_LOG(WARNING) << "Now() isn't helping us measure time"; + return; + } + int64 x0 = median(times.begin(), times.begin() + 9); + int64 x1 = median(times.begin() + times.size() - 9, times.end()); + GOOGLE_LOG(INFO) << "x0=" << x0 << ", x1=" << x1; + // x1 will greatly exceed x0 if the code we just executed took O(n^2) time. + // And we'll probably time out and never get here. So, this test is + // intentionally loose: we check that x0 and x1 are within a factor of 8. + EXPECT_GE(x1, x0 / 8); + EXPECT_GE(x0, x1 / 8); +} + +// Try to create kTestSize keys that will land in just a few buckets, and +// time the insertions, to get a rough estimate of whether an O(n^2) worst case +// was triggered. This test is a hacky, but probably better than nothing. +TEST_P(MapImplTest, HashFlood) { + const int kTestSize = 1024; // must be a power of 2 + std::set s; + for (int i = 0; s.size() < kTestSize; i++) { + if ((map_.hash_function()(i) & (kTestSize - 1)) < 3) { + s.insert(i); + } + } + // Create hash table with kTestSize entries that hash flood a table with + // 1024 (or 512 or 2048 or ...) entries. This assumes that map_ uses powers + // of 2 for table sizes, and that it's sufficient to "flood" with respect to + // the low bits of the output of map_.hash_function(). + vector times; + std::set::iterator it = s.begin(); + int count = 0; + do { + const int64 start = Now(); + map_[*it] = 0; + const int64 end = Now(); + if (end > start) { + times.push_back(end - start); + } + ++count; + ++it; + } while (it != s.end()); + if (times.size() < .99 * count) return; + int64 x0 = median(times.begin(), times.begin() + 9); + int64 x1 = median(times.begin() + times.size() - 9, times.end()); + // x1 will greatly exceed x0 if the code we just executed took O(n^2) time. + // But we want to allow O(n log n). A factor of 20 should be generous enough. + EXPECT_LE(x1, x0 * 20); +} + +// Arbitrary odd integers for creating test data. +static int k0 = 812398771; +static int k1 = 1312938717; +static int k2 = 1321555333; + +template +static void TestValidityForAllKeysExcept(int key_to_avoid, + const T& check_map, + const U& map) { + typedef typename U::value_type value_type; // a key-value pair + for (typename U::const_iterator it = map.begin(); it != map.end(); ++it) { + const int key = it->first; + if (key == key_to_avoid) continue; + // All iterators relevant to this key, whether old (from check_map) or new, + // must point to the same memory. So, test pointer equality here. + const value_type* check_val = &*check_map.find(key)->second; + EXPECT_EQ(check_val, &*it); + EXPECT_EQ(check_val, &*map.find(key)); + } +} + +// EXPECT i0 and i1 to be the same. Advancing them should have the same effect, +// too. +template +static void TestEqualIterators(Iter i0, Iter i1, Iter end) { + const int kMaxAdvance = 10; + for (int i = 0; i < kMaxAdvance; i++) { + EXPECT_EQ(i0 == end, i1 == end); + if (i0 == end) return; + EXPECT_EQ(&*i0, &*i1) << "iter " << i; + ++i0; + ++i1; + } +} + +template +static void TestOldVersusNewIterator(int skip, Map* m) { + const int initial_size = m->size(); + IteratorType it = m->begin(); + for (int i = 0; i < skip && it != m->end(); it++, i++) {} + if (it == m->end()) return; + const IteratorType old = it; + GOOGLE_LOG(INFO) << "skip=" << skip << ", old->first=" << old->first; + const int target_size = + initial_size < 100 ? initial_size * 5 : initial_size * 5 / 4; + for (int i = 0; m->size() <= target_size; i++) { + (*m)[i] = 0; + } + // Iterator 'old' should still work just fine despite the growth of *m. + const IteratorType after_growth = m->find(old->first); + TestEqualIterators(old, after_growth, m->end()); + + // Now shrink the number of elements. Do this with a mix of erases and + // inserts to increase the chance that the hashtable will resize to a lower + // number of buckets. (But, in any case, the test is still useful.) + for (int i = 0; i < 2 * (target_size - initial_size); i++) { + if (i != old->first) { + m->erase(i); + } + if (((i ^ m->begin()->first) & 15) == 0) { + (*m)[i * 342] = i; + } + } + // Now, the table has grown and shrunk; test again. + TestEqualIterators(old, m->find(old->first), m->end()); + TestEqualIterators(old, after_growth, m->end()); +} + +// Create and test an n-element Map, with emphasis on iterator correctness. +static void StressTestIterators(int n, bool test_old_style_proto2_maps) { + GOOGLE_LOG(INFO) << "StressTestIterators " << n; + GOOGLE_CHECK_GT(n, 0); + // Create a random-looking map of size n. Use non-negative integer keys. + Map m(test_old_style_proto2_maps); + uint32 frog = 123987 + n; + int last_key = 0; + int counter = 0; + while (m.size() < n) { + frog *= static_cast(k0); + frog ^= frog >> 17; + frog += counter++; + last_key = + static_cast(frog) >= 0 ? static_cast(frog) : last_key ^ 1; + GOOGLE_DCHECK_GE(last_key, 0); + m[last_key] = last_key ^ 1; + } + // Test it. + ASSERT_EQ(n, m.size()); + // Create maps of pointers and iterators. + // These should remain valid even if we modify m. + hash_map::value_type*> mp(n); + hash_map::iterator> mi(n); + for (Map::iterator it = m.begin(); it != m.end(); ++it) { + mp[it->first] = &*it; + mi[it->first] = it; + } + ASSERT_EQ(m.size(), mi.size()); + ASSERT_EQ(m.size(), mp.size()); + m.erase(last_key); + ASSERT_EQ(n - 1, m.size()); + TestValidityForAllKeysExcept(last_key, mp, m); + TestValidityForAllKeysExcept(last_key, mi, m); + + m[last_key] = 0; + ASSERT_EQ(n, m.size()); + // Test old iterator vs new iterator, with table modification in between. + TestOldVersusNewIterator::const_iterator>(n % 3, &m); + TestOldVersusNewIterator::iterator>(n % (1 + (n / 40)), &m); + // Finally, ensure erase(iterator) doesn't reorder anything, becuase that is + // what its documentation says. + m[last_key] = m[last_key ^ 999] = 0; + vector::iterator> v; + v.reserve(m.size()); + int position_of_last_key = 0; + for (Map::iterator it = m.begin(); it != m.end(); ++it) { + if (it->first == last_key) { + position_of_last_key = v.size(); + } + v.push_back(it); + } + ASSERT_EQ(m.size(), v.size()); + const Map::iterator erase_result = m.erase(m.find(last_key)); + int index = 0; + for (Map::iterator it = m.begin(); it != m.end(); ++it, ++index) { + if (index == position_of_last_key) { + EXPECT_EQ(&*erase_result, &*v[++index]); + } + ASSERT_EQ(&*it, &*v[index]); + } +} + +TEST_P(MapImplTest, IteratorInvalidation) { + // As multiple underlying hash_map implementations do not follow the + // validation requirement, the test is disabled for old-style maps. + if (GetParam()) return; + // Create a set of pseudo-random sizes to test. +#ifndef NDEBUG + const int kMaxSizeToTest = 100 * 1000; +#else + const int kMaxSizeToTest = 1000 * 1000; +#endif + std::set s; + int n = kMaxSizeToTest; + int frog = k1 + n; + while (n > 1 && s.size() < 25) { + s.insert(n); + n = static_cast(n * 100 / (101.0 + (frog & 63))); + frog *= k2; + frog ^= frog >> 17; + } + // Ensure we test a few small sizes. + s.insert(1); + s.insert(2); + s.insert(3); + // Now, the real work. + for (std::set::iterator i = s.begin(); i != s.end(); ++i) { + StressTestIterators(*i, GetParam()); + } +} + +// Test that erase() revalidates iterators. +TEST_P(MapImplTest, EraseRevalidates) { + // As multiple underlying hash_map implementations do not follow the + // validation requirement, the test is disabled for old-style maps. + if (GetParam()) return; + map_[3] = map_[13] = map_[20] = 0; + const int initial_size = map_.size(); + EXPECT_EQ(3, initial_size); + vector::iterator> v; + for (Map::iterator it = map_.begin(); it != map_.end(); ++it) { + v.push_back(it); + } + EXPECT_EQ(initial_size, v.size()); + for (int i = 0; map_.size() <= initial_size * 20; i++) { + map_[i] = 0; + } + const int larger_size = map_.size(); + // We've greatly increased the size of the map, so it is highly likely that + // the following will corrupt m if erase() doesn't properly revalidate + // iterators passed to it. Finishing this routine without crashing indicates + // success. + for (int i = 0; i < v.size(); i++) { + map_.erase(v[i]); + } + EXPECT_EQ(larger_size - v.size(), map_.size()); +} + template bool IsConstHelper(T& /*t*/) { // NOLINT. We want to catch non-const refs here. return false; @@ -290,7 +571,7 @@ bool IsConstHelper(const T& /*t*/) { return true; } -TEST_F(MapImplTest, IteratorConstness) { +TEST_P(MapImplTest, IteratorConstness) { map_[0] = 0; EXPECT_TRUE(IsConstHelper(*map_.cbegin())); EXPECT_TRUE(IsConstHelper(*const_map_.begin())); @@ -303,14 +584,14 @@ bool IsForwardIteratorHelper(T /*t*/) { return false; } -TEST_F(MapImplTest, IteratorCategory) { +TEST_P(MapImplTest, IteratorCategory) { EXPECT_TRUE(IsForwardIteratorHelper( std::iterator_traits::iterator>::iterator_category())); EXPECT_TRUE(IsForwardIteratorHelper(std::iterator_traits< Map::const_iterator>::iterator_category())); } -TEST_F(MapImplTest, InsertSingle) { +TEST_P(MapImplTest, InsertSingle) { int32 key = 0; int32 value1 = 100; int32 value2 = 101; @@ -335,7 +616,7 @@ TEST_F(MapImplTest, InsertSingle) { EXPECT_FALSE(result2.second); } -TEST_F(MapImplTest, InsertByIterator) { +TEST_P(MapImplTest, InsertByIterator) { int32 key1 = 0; int32 key2 = 1; int32 value1a = 100; @@ -358,7 +639,7 @@ TEST_F(MapImplTest, InsertByIterator) { ExpectElements(map1); } -TEST_F(MapImplTest, EraseSingleByKey) { +TEST_P(MapImplTest, EraseSingleByKey) { int32 key = 0; int32 value = 100; @@ -376,7 +657,7 @@ TEST_F(MapImplTest, EraseSingleByKey) { EXPECT_EQ(0, map_.erase(key)); } -TEST_F(MapImplTest, EraseMutipleByKey) { +TEST_P(MapImplTest, EraseMutipleByKey) { // erase in one specific order to trigger corner cases for (int i = 0; i < 5; i++) { map_[i] = i; @@ -403,7 +684,7 @@ TEST_F(MapImplTest, EraseMutipleByKey) { EXPECT_TRUE(map_.end() == map_.find(2)); } -TEST_F(MapImplTest, EraseSingleByIterator) { +TEST_P(MapImplTest, EraseSingleByIterator) { int32 key = 0; int32 value = 100; @@ -418,7 +699,7 @@ TEST_F(MapImplTest, EraseSingleByIterator) { EXPECT_TRUE(map_.begin() == map_.end()); } -TEST_F(MapImplTest, ValidIteratorAfterErase) { +TEST_P(MapImplTest, ValidIteratorAfterErase) { for (int i = 0; i < 10; i++) { map_[i] = i; } @@ -438,7 +719,7 @@ TEST_F(MapImplTest, ValidIteratorAfterErase) { EXPECT_EQ(5, map_.size()); } -TEST_F(MapImplTest, EraseByIterator) { +TEST_P(MapImplTest, EraseByIterator) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -459,7 +740,7 @@ TEST_F(MapImplTest, EraseByIterator) { EXPECT_TRUE(map_.begin() == map_.end()); } -TEST_F(MapImplTest, Clear) { +TEST_P(MapImplTest, Clear) { int32 key = 0; int32 value = 100; @@ -474,7 +755,7 @@ TEST_F(MapImplTest, Clear) { EXPECT_TRUE(map_.begin() == map_.end()); } -TEST_F(MapImplTest, CopyConstructor) { +static void CopyConstructorHelper(Arena* arena, Map* m) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -484,16 +765,25 @@ TEST_F(MapImplTest, CopyConstructor) { map[key1] = value1; map[key2] = value2; - map_.insert(map.begin(), map.end()); + m->insert(map.begin(), map.end()); - Map other(map_); + Map other(*m); EXPECT_EQ(2, other.size()); EXPECT_EQ(value1, other.at(key1)); EXPECT_EQ(value2, other.at(key2)); } -TEST_F(MapImplTest, IterConstructor) { +TEST_P(MapImplTest, CopyConstructorWithArena) { + Arena a; + CopyConstructorHelper(&a, &map_); +} + +TEST_P(MapImplTest, CopyConstructorWithoutArena) { + CopyConstructorHelper(NULL, &map_); +} + +TEST_P(MapImplTest, IterConstructor) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -503,14 +793,15 @@ TEST_F(MapImplTest, IterConstructor) { map[key1] = value1; map[key2] = value2; - Map new_map(map.begin(), map.end()); + Map new_map(map.begin(), map.end(), + GetParam()); EXPECT_EQ(2, new_map.size()); EXPECT_EQ(value1, new_map.at(key1)); EXPECT_EQ(value2, new_map.at(key2)); } -TEST_F(MapImplTest, Assigner) { +TEST_P(MapImplTest, Assigner) { int32 key1 = 0; int32 key2 = 1; int32 value1 = 100; @@ -522,7 +813,7 @@ TEST_F(MapImplTest, Assigner) { map_.insert(map.begin(), map.end()); - Map other; + Map other(GetParam()); int32 key_other = 123; int32 value_other = 321; other[key_other] = value_other; @@ -540,9 +831,16 @@ TEST_F(MapImplTest, Assigner) { EXPECT_EQ(2, other.size()); EXPECT_EQ(value1, other.at(key1)); EXPECT_EQ(value2, other.at(key2)); + + // Try assignment to a map with a different choice of "style." + Map m(!GetParam()); + m = other; + EXPECT_EQ(2, m.size()); + EXPECT_EQ(value1, m.at(key1)); + EXPECT_EQ(value2, m.at(key2)); } -TEST_F(MapImplTest, Rehash) { +TEST_P(MapImplTest, Rehash) { const int test_size = 50; std::map reference_map; for (int i = 0; i < test_size; i++) { @@ -559,7 +857,7 @@ TEST_F(MapImplTest, Rehash) { EXPECT_TRUE(map_.empty()); } -TEST_F(MapImplTest, EqualRange) { +TEST_P(MapImplTest, EqualRange) { int key = 100, key_missing = 101; map_[key] = 100; @@ -583,14 +881,14 @@ TEST_F(MapImplTest, EqualRange) { EXPECT_TRUE(const_map_.end() == const_range.second); } -TEST_F(MapImplTest, ConvertToStdMap) { +TEST_P(MapImplTest, ConvertToStdMap) { map_[100] = 101; std::map std_map(map_.begin(), map_.end()); EXPECT_EQ(1, std_map.size()); EXPECT_EQ(101, std_map[100]); } -TEST_F(MapImplTest, ConvertToStdVectorOfPairs) { +TEST_P(MapImplTest, ConvertToStdVectorOfPairs) { map_[100] = 101; std::vector > std_vec(map_.begin(), map_.end()); EXPECT_EQ(1, std_vec.size()); @@ -598,6 +896,8 @@ TEST_F(MapImplTest, ConvertToStdVectorOfPairs) { EXPECT_EQ(101, std_vec[0].second); } +INSTANTIATE_TEST_CASE_P(BoolSequence, MapImplTest, testing::Bool()); + // Map Field Reflection Test ======================================== static int Func(int i, int j) { diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 032748bd..d62ca79c 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -69,7 +69,7 @@ void Message::MergeFrom(const Message& from) { GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) << ": Tried to merge from a message with a different type. " "to: " << descriptor->full_name() << ", " - "from:" << from.GetDescriptor()->full_name(); + "from: " << from.GetDescriptor()->full_name(); ReflectionOps::Merge(from, this); } @@ -82,7 +82,7 @@ void Message::CopyFrom(const Message& from) { GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor) << ": Tried to copy from a message with a different type. " "to: " << descriptor->full_name() << ", " - "from:" << from.GetDescriptor()->full_name(); + "from: " << from.GetDescriptor()->full_name(); ReflectionOps::Copy(from, this); } diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 5bd8bcfb..fe124c45 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -62,13 +62,15 @@ namespace { // provide a useful error message. void ByteSizeConsistencyError(int byte_size_before_serialization, int byte_size_after_serialization, - int bytes_produced_by_serialization) { + int bytes_produced_by_serialization, + const MessageLite& message) { GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) - << "Protocol message was modified concurrently during serialization."; + << message.GetTypeName() + << " was modified concurrently during serialization."; GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) << "Byte size calculation and serialization were inconsistent. This " "may indicate a bug in protocol buffers or it may be caused by " - "concurrent modification of the message."; + "concurrent modification of " << message.GetTypeName() << "."; GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; } @@ -248,7 +250,7 @@ bool MessageLite::SerializePartialToCodedStream( if (buffer != NULL) { uint8* end = SerializeWithCachedSizesToArray(buffer); if (end - buffer != size) { - ByteSizeConsistencyError(size, ByteSize(), end - buffer); + ByteSizeConsistencyError(size, ByteSize(), end - buffer, *this); } return true; } else { @@ -261,7 +263,7 @@ bool MessageLite::SerializePartialToCodedStream( if (final_byte_count - original_byte_count != size) { ByteSizeConsistencyError(size, ByteSize(), - final_byte_count - original_byte_count); + final_byte_count - original_byte_count, *this); } return true; @@ -299,7 +301,7 @@ bool MessageLite::AppendPartialToString(string* output) const { reinterpret_cast(io::mutable_string_data(output) + old_size); uint8* end = SerializeWithCachedSizesToArray(start); if (end - start != byte_size) { - ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this); } return true; } @@ -325,7 +327,7 @@ bool MessageLite::SerializePartialToArray(void* data, int size) const { uint8* start = reinterpret_cast(data); uint8* end = SerializeWithCachedSizesToArray(start); if (end - start != byte_size) { - ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + ByteSizeConsistencyError(byte_size, ByteSize(), end - start, *this); } return true; } diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc index 2d4780fe..d668a1a6 100644 --- a/src/google/protobuf/message_unittest.cc +++ b/src/google/protobuf/message_unittest.cc @@ -55,6 +55,7 @@ #include #include +#include #include #include diff --git a/src/google/protobuf/metadata.h b/src/google/protobuf/metadata.h index 219645d3..fdee150b 100644 --- a/src/google/protobuf/metadata.h +++ b/src/google/protobuf/metadata.h @@ -56,7 +56,7 @@ namespace internal { // The tagged pointer uses the LSB to disambiguate cases, and uses bit 0 == 0 to // indicate an arena pointer and bit 0 == 1 to indicate a UFS+Arena-container // pointer. -class InternalMetadataWithArena { +class LIBPROTOBUF_EXPORT InternalMetadataWithArena { public: InternalMetadataWithArena() : ptr_(NULL) {} explicit InternalMetadataWithArena(Arena* arena) diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index 949e0a23..77004f59 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -52,8 +52,8 @@ void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) { } Rep* old_rep = rep_; Arena* arena = GetArenaNoVirtual(); - new_size = max(kMinRepeatedFieldAllocationSize, - max(total_size_ * 2, new_size)); + new_size = std::max(kMinRepeatedFieldAllocationSize, + std::max(total_size_ * 2, new_size)); GOOGLE_CHECK_LE(new_size, (std::numeric_limits::max() - kRepHeaderSize) / sizeof(old_rep->elements[0])) diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 5447fa42..deeb7d50 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -244,7 +244,7 @@ class RepeatedField { int total_size_; struct Rep { Arena* arena; - Element elements[1]; + Element elements[1]; }; // We can not use sizeof(Rep) - sizeof(Element) due to the trailing padding on // the struct. We can not use sizeof(Arena*) as well because there might be @@ -272,6 +272,22 @@ class RepeatedField { inline Arena* GetArenaNoVirtual() const { return (rep_ == NULL) ? NULL : rep_->arena; } + + // Internal helper to delete all elements and deallocate the storage. + // If Element has a trivial destructor (for example, if it's a fundamental + // type, like int32), the loop will be removed by the optimizer. + void InternalDeallocate(Rep* rep, int size) { + if (rep != NULL) { + Element* e = &rep->elements[0]; + Element* limit = &rep->elements[size]; + for (; e < limit; e++) { + e->Element::~Element(); + } + if (rep->arena == NULL) { + delete[] reinterpret_cast(rep); + } + } + } }; template @@ -836,6 +852,15 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Add an already-allocated object, skipping arena-ownership checks. The user // must guarantee that the given object is in the same arena as this // RepeatedPtrField. + // It is also useful in legacy code that uses temporary ownership to avoid + // copies. Example: + // RepeatedPtrField temp_field; + // temp_field.AddAllocated(new T); + // ... // Do something with temp_field + // temp_field.ExtractSubrange(0, temp_field.size(), NULL); + // If you put temp_field on the arena this fails, because the ownership + // transfers to the arena at the "AddAllocated" call and is not released + // anymore causing a double delete. UnsafeArenaAddAllocated prevents this. void UnsafeArenaAddAllocated(Element* value); // Remove the last element and return it. Works only when operating on an @@ -992,19 +1017,8 @@ RepeatedField::RepeatedField(Iter begin, const Iter& end) template RepeatedField::~RepeatedField() { // See explanation in Reserve(): we need to invoke destructors here for the - // case that Element has a non-trivial destructor. If Element has a trivial - // destructor (for example, if it's a primitive type, like int32), this entire - // loop will be removed by the optimizer. - if (rep_ != NULL) { - Element* e = &rep_->elements[0]; - Element* limit = &rep_->elements[total_size_]; - for (; e < limit; e++) { - e->Element::~Element(); - } - if (rep_->arena == NULL) { - delete[] reinterpret_cast(rep_); - } - } + // case that Element has a non-trivial destructor. + InternalDeallocate(rep_, total_size_); } template @@ -1240,8 +1254,8 @@ void RepeatedField::Reserve(int new_size) { if (total_size_ >= new_size) return; Rep* old_rep = rep_; Arena* arena = GetArenaNoVirtual(); - new_size = max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, - max(total_size_ * 2, new_size)); + new_size = std::max(google::protobuf::internal::kMinRepeatedFieldAllocationSize, + std::max(total_size_ * 2, new_size)); GOOGLE_CHECK_LE(static_cast(new_size), (std::numeric_limits::max() - kRepHeaderSize) / sizeof(Element)) @@ -1274,18 +1288,10 @@ void RepeatedField::Reserve(int new_size) { if (current_size_ > 0) { MoveArray(rep_->elements, old_rep->elements, current_size_); } - if (old_rep) { - // Likewise, we need to invoke destructors on the old array. If Element has - // no destructor, this loop will disappear. - e = &old_rep->elements[0]; - limit = &old_rep->elements[old_total_size]; - for (; e < limit; e++) { - e->Element::~Element(); - } - if (arena == NULL) { - delete[] reinterpret_cast(old_rep); - } - } + + // Likewise, we need to invoke destructors on the old array. + InternalDeallocate(old_rep, old_total_size); + } template @@ -2380,6 +2386,37 @@ template class AllocatedRepeatedPtrFieldBackInsertIterator private: RepeatedPtrField* field_; }; + +// Almost identical to AllocatedRepeatedPtrFieldBackInsertIterator. This one +// uses the UnsafeArenaAddAllocated instead. +template +class UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator + : public std::iterator { + public: + explicit UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator( + ::google::protobuf::RepeatedPtrField* const mutable_field) + : field_(mutable_field) { + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator=( + T const* const ptr_to_value) { + field_->UnsafeArenaAddAllocated(const_cast(ptr_to_value)); + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator*() { + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator++() { + return *this; + } + UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator& operator++( + int /* unused */) { + return *this; + } + + private: + ::google::protobuf::RepeatedPtrField* field_; +}; + } // namespace internal // Provides a back insert iterator for RepeatedField instances, @@ -2414,6 +2451,25 @@ AllocatedRepeatedPtrFieldBackInserter( mutable_field); } +// Similar to AllocatedRepeatedPtrFieldBackInserter, using +// UnsafeArenaAddAllocated instead of AddAllocated. +// This is slightly faster if that matters. It is also useful in legacy code +// that uses temporary ownership to avoid copies. Example: +// RepeatedPtrField temp_field; +// temp_field.AddAllocated(new T); +// ... // Do something with temp_field +// temp_field.ExtractSubrange(0, temp_field.size(), NULL); +// If you put temp_field on the arena this fails, because the ownership +// transfers to the arena at the "AddAllocated" call and is not released anymore +// causing a double delete. Using UnsafeArenaAddAllocated prevents this. +template +internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator +UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( + ::google::protobuf::RepeatedPtrField* const mutable_field) { + return internal::UnsafeArenaAllocatedRepeatedPtrFieldBackInsertIterator( + mutable_field); +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index b45664b0..39b24b33 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -1522,6 +1522,44 @@ TEST_F(RepeatedFieldInsertionIteratorsTest, EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); } +TEST_F(RepeatedFieldInsertionIteratorsTest, + UnsafeArenaAllocatedRepeatedPtrFieldWithStringIntData) { + vector data; + TestAllTypes goldenproto; + for (int i = 0; i < 10; ++i) { + Nested* new_data = new Nested; + new_data->set_bb(i); + data.push_back(new_data); + + new_data = goldenproto.add_repeated_nested_message(); + new_data->set_bb(i); + } + TestAllTypes testproto; + std::copy(data.begin(), data.end(), + UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( + testproto.mutable_repeated_nested_message())); + EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); +} + +TEST_F(RepeatedFieldInsertionIteratorsTest, + UnsafeArenaAllocatedRepeatedPtrFieldWithString) { + vector data; + TestAllTypes goldenproto; + for (int i = 0; i < 10; ++i) { + string* new_data = new string; + *new_data = "name-" + SimpleItoa(i); + data.push_back(new_data); + + new_data = goldenproto.add_repeated_string(); + *new_data = "name-" + SimpleItoa(i); + } + TestAllTypes testproto; + std::copy(data.begin(), data.end(), + UnsafeArenaAllocatedRepeatedPtrFieldBackInserter( + testproto.mutable_repeated_string())); + EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString()); +} + } // namespace } // namespace protobuf diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc index e020597a..9e5b086b 100644 --- a/src/google/protobuf/struct.pb.cc +++ b/src/google/protobuf/struct.pb.cc @@ -166,9 +166,11 @@ void protobuf_AddDesc_google_2fprotobuf_2fstruct_2eproto() { "\000\0220\n\nlist_value\030\006 \001(\0132\032.google.protobuf." "ListValueH\000B\006\n\004kind\"3\n\tListValue\022&\n\006valu" "es\030\001 \003(\0132\026.google.protobuf.Value*\033\n\tNull" - "Value\022\016\n\nNULL_VALUE\020\000BN\n\023com.google.prot" - "obufB\013StructProtoP\001\240\001\001\242\002\003GPB\252\002\036Google.Pr" - "otobuf.WellKnownTypesb\006proto3", 589); + "Value\022\016\n\nNULL_VALUE\020\000B\201\001\n\023com.google.pro" + "tobufB\013StructProtoP\001Z1github.com/golang/" + "protobuf/ptypes/struct;structpb\240\001\001\242\002\003GPB" + "\252\002\036Google.Protobuf.WellKnownTypesb\006proto" + "3", 641); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/struct.proto", &protobuf_RegisterTypes); Struct::default_instance_ = new Struct(); diff --git a/src/google/protobuf/struct.proto b/src/google/protobuf/struct.proto index 8562e2c1..beeba811 100644 --- a/src/google/protobuf/struct.proto +++ b/src/google/protobuf/struct.proto @@ -33,6 +33,7 @@ syntax = "proto3"; package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; +option go_package = "github.com/golang/protobuf/ptypes/struct;structpb"; option java_package = "com.google.protobuf"; option java_outer_classname = "StructProto"; option java_multiple_files = true; @@ -49,7 +50,7 @@ option objc_class_prefix = "GPB"; // // The JSON representation for `Struct` is JSON object. message Struct { - // Map of dynamically typed values. + // Unordered map of dynamically typed values. map fields = 1; } diff --git a/src/google/protobuf/stubs/hash.h b/src/google/protobuf/stubs/hash.h index 58334322..bbd8ee65 100755 --- a/src/google/protobuf/stubs/hash.h +++ b/src/google/protobuf/stubs/hash.h @@ -214,6 +214,8 @@ class hash_map : public std::map { hash_map(int a = 0, const HashFcn& b = HashFcn(), const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) : BaseClass(b, d) {} + + HashFcn hash_function() const { return HashFcn(); } }; template { public: hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } }; #elif defined(_MSC_VER) && !defined(_STLPORT_VERSION) @@ -257,6 +261,8 @@ class hash_map hash_map(int a = 0, const HashFcn& b = HashFcn(), const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } }; template , @@ -266,6 +272,8 @@ class hash_set Key, HashFcn, EqualKey> { public: hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } }; #else @@ -315,6 +323,8 @@ class hash_map hash_map(int a = 0, const HashFcn& b = HashFcn(), const EqualKey& c = EqualKey(), const Alloc& d = Alloc()) : BaseClass(a, b, c, d) {} + + HashFcn hash_function() const { return HashFcn(); } }; template , @@ -324,6 +334,8 @@ class hash_set Key, HashFcn, EqualKey> { public: hash_set(int = 0) {} + + HashFcn hash_function() const { return HashFcn(); } }; #endif // !GOOGLE_PROTOBUF_MISSING_HASH diff --git a/src/google/protobuf/stubs/logging.h b/src/google/protobuf/stubs/logging.h index 3108db8c..f69605d9 100644 --- a/src/google/protobuf/stubs/logging.h +++ b/src/google/protobuf/stubs/logging.h @@ -174,7 +174,7 @@ T* CheckNotNull(const char* /* file */, int /* line */, #ifdef NDEBUG -#define GOOGLE_DLOG GOOGLE_LOG_IF(INFO, false) +#define GOOGLE_DLOG(LEVEL) GOOGLE_LOG_IF(LEVEL, false) #define GOOGLE_DCHECK(EXPRESSION) while(false) GOOGLE_CHECK(EXPRESSION) #define GOOGLE_DCHECK_OK(E) GOOGLE_DCHECK(::google::protobuf::internal::IsOk(E)) diff --git a/src/google/protobuf/stubs/mathutil.h b/src/google/protobuf/stubs/mathutil.h index 3a1ef8a8..27956a8e 100644 --- a/src/google/protobuf/stubs/mathutil.h +++ b/src/google/protobuf/stubs/mathutil.h @@ -83,7 +83,7 @@ class MathUtil { if (value == T(0) || ::google::protobuf::internal::IsNan(value)) { return value; } - return value > T(0) ? value : -value; + return value > T(0) ? 1 : -1; } template diff --git a/src/google/protobuf/stubs/stringpiece.h b/src/google/protobuf/stubs/stringpiece.h index ec3ffd5b..91671659 100644 --- a/src/google/protobuf/stubs/stringpiece.h +++ b/src/google/protobuf/stubs/stringpiece.h @@ -435,6 +435,44 @@ inline bool operator>=(StringPiece x, StringPiece y) { // allow StringPiece to be logged extern std::ostream& operator<<(std::ostream& o, StringPiece piece); +namespace internal { +// StringPiece is not a POD and can not be used in an union (pre C++11). We +// need a POD version of it. +struct StringPiecePod { + // Create from a StringPiece. + static StringPiecePod CreateFromStringPiece(StringPiece str) { + StringPiecePod pod; + pod.data_ = str.data(); + pod.size_ = str.size(); + return pod; + } + + // Cast to StringPiece. + operator StringPiece() const { return StringPiece(data_, size_); } + + bool operator==(const char* value) const { + return StringPiece(data_, size_) == StringPiece(value); + } + + char operator[](stringpiece_ssize_type i) const { + assert(0 <= i); + assert(i < size_); + return data_[i]; + } + + const char* data() const { return data_; } + + stringpiece_ssize_type size() const { + return size_; + } + + std::string ToString() const { return std::string(data_, size_); } + private: + const char* data_; + stringpiece_ssize_type size_; +}; + +} // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index 27d47575..8bdd6110 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -648,6 +648,9 @@ struct LIBPROTOBUF_EXPORT AlphaNum { AlphaNum(StringPiece str) : piece_data_(str.data()), piece_size_(str.size()) {} + AlphaNum(internal::StringPiecePod str) + : piece_data_(str.data()), piece_size_(str.size()) {} + size_t size() const { return piece_size_; } const char *data() const { return piece_data_; } @@ -847,6 +850,11 @@ LIBPROTOBUF_EXPORT void Base64Escape(const unsigned char* src, int szsrc, LIBPROTOBUF_EXPORT void WebSafeBase64Escape(const unsigned char* src, int szsrc, string* dest, bool do_padding); +inline bool IsValidCodePoint(uint32 code_point) { + return code_point < 0xD800 || + (code_point >= 0xE000 && code_point <= 0x10FFFF); +} + static const int UTFmax = 4; // ---------------------------------------------------------------------- // EncodeAsUTF8Char() diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index b0a5ce63..1ed74391 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -91,7 +91,10 @@ inline bool GetAnyFieldDescriptors(const Message& message, string Message::DebugString() const { string debug_string; - TextFormat::PrintToString(*this, &debug_string); + TextFormat::Printer printer; + printer.SetExpandAny(true); + + printer.PrintToString(*this, &debug_string); return debug_string; } @@ -101,6 +104,7 @@ string Message::ShortDebugString() const { TextFormat::Printer printer; printer.SetSingleLineMode(true); + printer.SetExpandAny(true); printer.PrintToString(*this, &debug_string); // Single line mode currently might have an extra space at the end. @@ -117,6 +121,7 @@ string Message::Utf8DebugString() const { TextFormat::Printer printer; printer.SetUseUtf8StringEscaping(true); + printer.SetExpandAny(true); printer.PrintToString(*this, &debug_string); @@ -1153,10 +1158,10 @@ class TextFormat::Printer::TextGenerator { } // Print text to the output stream. - void Print(const char* text, int size) { - int pos = 0; // The number of bytes we've written so far. + void Print(const char* text, size_t size) { + size_t pos = 0; // The number of bytes we've written so far. - for (int i = 0; i < size; i++) { + for (size_t i = 0; i < size; i++) { if (text[i] == '\n') { // Saw newline. If there is more text, we may need to insert an indent // here. So, write what we have so far, including the '\n'. @@ -1181,7 +1186,7 @@ class TextFormat::Printer::TextGenerator { private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextGenerator); - void Write(const char* data, int size) { + void Write(const char* data, size_t size) { if (failed_) return; if (size == 0) return; diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 8d61be19..f97658fd 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -44,6 +44,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc index c1c4402c..1393cc95 100644 --- a/src/google/protobuf/timestamp.pb.cc +++ b/src/google/protobuf/timestamp.pb.cc @@ -83,9 +83,10 @@ void protobuf_AddDesc_google_2fprotobuf_2ftimestamp_2eproto() { ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( "\n\037google/protobuf/timestamp.proto\022\017googl" "e.protobuf\"+\n\tTimestamp\022\017\n\007seconds\030\001 \001(\003" - "\022\r\n\005nanos\030\002 \001(\005BT\n\023com.google.protobufB\016" - "TimestampProtoP\001\240\001\001\370\001\001\242\002\003GPB\252\002\036Google.Pr" - "otobuf.WellKnownTypesb\006proto3", 189); + "\022\r\n\005nanos\030\002 \001(\005B\201\001\n\023com.google.protobufB" + "\016TimestampProtoP\001Z+github.com/golang/pro" + "tobuf/ptypes/timestamp\240\001\001\370\001\001\242\002\003GPB\252\002\036Goo" + "gle.Protobuf.WellKnownTypesb\006proto3", 235); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/timestamp.proto", &protobuf_RegisterTypes); Timestamp::default_instance_ = new Timestamp(); diff --git a/src/google/protobuf/timestamp.proto b/src/google/protobuf/timestamp.proto index b51fc3fa..7992a858 100644 --- a/src/google/protobuf/timestamp.proto +++ b/src/google/protobuf/timestamp.proto @@ -34,6 +34,7 @@ package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/timestamp"; option java_package = "com.google.protobuf"; option java_outer_classname = "TimestampProto"; option java_multiple_files = true; diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index 85fe6153..da56ae0a 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -696,6 +696,7 @@ message TestRequiredOneof { } } + // Test messages for packed fields message TestPackedTypes { diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto index 662c0e46..41ed845f 100644 --- a/src/google/protobuf/unittest_lite.proto +++ b/src/google/protobuf/unittest_lite.proto @@ -43,8 +43,10 @@ option java_package = "com.google.protobuf"; // Same as TestAllTypes but with the lite runtime. message TestAllTypesLite { + message NestedMessage { optional int32 bb = 1; + optional int64 cc = 2; } enum NestedEnum { @@ -159,6 +161,7 @@ message TestAllTypesLite { NestedMessage oneof_nested_message = 112; string oneof_string = 113; bytes oneof_bytes = 114; + NestedMessage oneof_lazy_nested_message = 115 [lazy = true]; } } diff --git a/src/google/protobuf/util/field_comparator.h b/src/google/protobuf/util/field_comparator.h index 8b83c69f..1b4d65b0 100644 --- a/src/google/protobuf/util/field_comparator.h +++ b/src/google/protobuf/util/field_comparator.h @@ -91,9 +91,9 @@ class LIBPROTOBUF_EXPORT FieldComparator { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldComparator); }; -// Basic implementation of FieldComparator. Supports four modes of floating +// Basic implementation of FieldComparator. Supports three modes of floating // point value comparison: exact, approximate using MathUtil::AlmostEqual -// method, and arbitrarilly precise using MathUtil::WithinFractionOrMargin. +// method, and arbitrarily precise using MathUtil::WithinFractionOrMargin. class LIBPROTOBUF_EXPORT DefaultFieldComparator : public FieldComparator { public: enum FloatComparison { diff --git a/src/google/protobuf/util/field_comparator_test.cc b/src/google/protobuf/util/field_comparator_test.cc index 23f7d51d..6fd631d8 100644 --- a/src/google/protobuf/util/field_comparator_test.cc +++ b/src/google/protobuf/util/field_comparator_test.cc @@ -42,7 +42,6 @@ // and the opensource version gtest.h header includes cmath transitively // somehow. #include - namespace google { namespace protobuf { namespace util { diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc index c59f43aa..547c9fb5 100644 --- a/src/google/protobuf/util/field_mask_util.cc +++ b/src/google/protobuf/util/field_mask_util.cc @@ -52,6 +52,82 @@ void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) { } } +bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) { + output->clear(); + bool after_underscore = false; + for (int i = 0; i < input.size(); ++i) { + if (input[i] >= 'A' && input[i] <= 'Z') { + // The field name must not contain uppercase letters. + return false; + } + if (after_underscore) { + if (input[i] >= 'a' && input[i] <= 'z') { + output->push_back(input[i] + 'A' - 'a'); + after_underscore = false; + } else { + // The character after a "_" must be a lowercase letter. + return false; + } + } else if (input[i] == '_') { + after_underscore = true; + } else { + output->push_back(input[i]); + } + } + if (after_underscore) { + // Trailing "_". + return false; + } + return true; +} + +bool FieldMaskUtil::CamelCaseToSnakeCase(StringPiece input, string* output) { + output->clear(); + for (int i = 0; i < input.size(); ++i) { + if (input[i] == '_') { + // The field name must not contain "_"s. + return false; + } + if (input[i] >= 'A' && input[i] <= 'Z') { + output->push_back('_'); + output->push_back(input[i] + 'a' - 'A'); + } else { + output->push_back(input[i]); + } + } + return true; +} + +bool FieldMaskUtil::ToJsonString(const FieldMask& mask, string* out) { + out->clear(); + for (int i = 0; i < mask.paths_size(); ++i) { + const string& path = mask.paths(i); + string camelcase_path; + if (!SnakeCaseToCamelCase(path, &camelcase_path)) { + return false; + } + if (i > 0) { + out->push_back(','); + } + out->append(camelcase_path); + } + return true; +} + +bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) { + out->Clear(); + vector paths = Split(str, ","); + for (int i = 0; i < paths.size(); ++i) { + if (paths[i].empty()) continue; + string snakecase_path; + if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) { + return false; + } + out->add_paths(snakecase_path); + } + return true; +} + bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor, StringPiece path) { vector parts = Split(path, "."); diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h index 92f69893..644161b9 100644 --- a/src/google/protobuf/util/field_mask_util.h +++ b/src/google/protobuf/util/field_mask_util.h @@ -45,11 +45,18 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { typedef google::protobuf::FieldMask FieldMask; public: - // Converts FieldMask to/from string, formatted according to proto3 JSON - // spec for FieldMask (e.g., "foo,bar,baz.quz"). + // Converts FieldMask to/from string, formatted by separating each path + // with a comma (e.g., "foo_bar,baz.quz"). static string ToString(const FieldMask& mask); static void FromString(StringPiece str, FieldMask* out); + // Converts FieldMask to/from string, formatted according to proto3 JSON + // spec for FieldMask (e.g., "fooBar,baz.quz"). If the field name is not + // style conforming (i.e., not snake_case when converted to string, or not + // camelCase when converted from string), the conversion will fail. + static bool ToJsonString(const FieldMask& mask, string* out); + static bool FromJsonString(StringPiece str, FieldMask* out); + // Checks whether the given path is valid for type T. template static bool IsValidPath(StringPiece path) { @@ -105,6 +112,35 @@ class LIBPROTOBUF_EXPORT FieldMaskUtil { const MergeOptions& options, Message* destination); private: + friend class SnakeCaseCamelCaseTest; + // Converts a field name from snake_case to camelCase: + // 1. Every character after "_" will be converted to uppercase. + // 2. All "_"s are removed. + // The conversion will fail if: + // 1. The field name contains uppercase letters. + // 2. Any character after a "_" is not a lowercase letter. + // If the conversion succeeds, it's guaranteed that the resulted + // camelCase name will yield the original snake_case name when + // converted using CamelCaseToSnakeCase(). + // + // Note that the input can contain characters not allowed in C identifiers. + // For example, "foo_bar,baz_quz" will be converted to "fooBar,bazQuz" + // successfully. + static bool SnakeCaseToCamelCase(StringPiece input, string* output); + // Converts a field name from camelCase to snake_case: + // 1. Every uppercase letter is converted to lowercase with a additional + // preceding "-". + // The conversion will fail if: + // 1. The field name contains "_"s. + // If the conversion succeeds, it's guaranteed that the resulted + // snake_case name will yield the original camelCase name when + // converted using SnakeCaseToCamelCase(). + // + // Note that the input can contain characters not allowed in C identifiers. + // For example, "fooBar,bazQuz" will be converted to "foo_bar,baz_quz" + // successfully. + static bool CamelCaseToSnakeCase(StringPiece input, string* output); + static bool InternalIsValidPath(const Descriptor* descriptor, StringPiece path); diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc index a9523250..b3787857 100644 --- a/src/google/protobuf/util/field_mask_util_test.cc +++ b/src/google/protobuf/util/field_mask_util_test.cc @@ -30,6 +30,8 @@ #include +#include +#include #include #include #include @@ -38,8 +40,77 @@ namespace google { namespace protobuf { namespace util { + +class SnakeCaseCamelCaseTest : public ::testing::Test { + protected: + string SnakeCaseToCamelCase(const string& input) { + string output; + if (FieldMaskUtil::SnakeCaseToCamelCase(input, &output)) { + return output; + } else { + return "#FAIL#"; + } + } + + string CamelCaseToSnakeCase(const string& input) { + string output; + if (FieldMaskUtil::CamelCaseToSnakeCase(input, &output)) { + return output; + } else { + return "#FAIL#"; + } + } +}; + namespace { +TEST_F(SnakeCaseCamelCaseTest, SnakeToCamel) { + EXPECT_EQ("fooBar", SnakeCaseToCamelCase("foo_bar")); + EXPECT_EQ("FooBar", SnakeCaseToCamelCase("_foo_bar")); + EXPECT_EQ("foo3Bar", SnakeCaseToCamelCase("foo3_bar")); + // No uppercase letter is allowed. + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("Foo")); + // Any character after a "_" must be a lowercase letter. + // 1. "_" cannot be followed by another "_". + // 2. "_" cannot be followed by a digit. + // 3. "_" cannot appear as the last character. + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo__bar")); + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_3bar")); + EXPECT_EQ("#FAIL#", SnakeCaseToCamelCase("foo_bar_")); +} + +TEST_F(SnakeCaseCamelCaseTest, CamelToSnake) { + EXPECT_EQ("foo_bar", CamelCaseToSnakeCase("fooBar")); + EXPECT_EQ("_foo_bar", CamelCaseToSnakeCase("FooBar")); + EXPECT_EQ("foo3_bar", CamelCaseToSnakeCase("foo3Bar")); + // "_"s are not allowed. + EXPECT_EQ("#FAIL#", CamelCaseToSnakeCase("foo_bar")); +} + +TEST_F(SnakeCaseCamelCaseTest, RoundTripTest) { + // Enumerates all possible snake_case names and test that converting it to + // camelCase and then to snake_case again will yield the original name. + string name = "___abc123"; + std::sort(name.begin(), name.end()); + do { + string camelName = SnakeCaseToCamelCase(name); + if (camelName != "#FAIL#") { + EXPECT_EQ(name, CamelCaseToSnakeCase(camelName)); + } + } while (std::next_permutation(name.begin(), name.end())); + + // Enumerates all possible camelCase names and test that converting it to + // snake_case and then to camelCase again will yield the original name. + name = "abcABC123"; + std::sort(name.begin(), name.end()); + do { + string camelName = CamelCaseToSnakeCase(name); + if (camelName != "#FAIL#") { + EXPECT_EQ(name, SnakeCaseToCamelCase(camelName)); + } + } while (std::next_permutation(name.begin(), name.end())); +} + using protobuf_unittest::TestAllTypes; using protobuf_unittest::NestedTestAllTypes; using google::protobuf::FieldMask; @@ -47,20 +118,43 @@ using google::protobuf::FieldMask; TEST(FieldMaskUtilTest, StringFormat) { FieldMask mask; EXPECT_EQ("", FieldMaskUtil::ToString(mask)); - mask.add_paths("foo"); - EXPECT_EQ("foo", FieldMaskUtil::ToString(mask)); - mask.add_paths("bar"); - EXPECT_EQ("foo,bar", FieldMaskUtil::ToString(mask)); + mask.add_paths("foo_bar"); + EXPECT_EQ("foo_bar", FieldMaskUtil::ToString(mask)); + mask.add_paths("baz_quz"); + EXPECT_EQ("foo_bar,baz_quz", FieldMaskUtil::ToString(mask)); FieldMaskUtil::FromString("", &mask); EXPECT_EQ(0, mask.paths_size()); - FieldMaskUtil::FromString("foo", &mask); + FieldMaskUtil::FromString("fooBar", &mask); EXPECT_EQ(1, mask.paths_size()); - EXPECT_EQ("foo", mask.paths(0)); - FieldMaskUtil::FromString("foo,bar", &mask); + EXPECT_EQ("fooBar", mask.paths(0)); + FieldMaskUtil::FromString("fooBar,bazQuz", &mask); EXPECT_EQ(2, mask.paths_size()); - EXPECT_EQ("foo", mask.paths(0)); - EXPECT_EQ("bar", mask.paths(1)); + EXPECT_EQ("fooBar", mask.paths(0)); + EXPECT_EQ("bazQuz", mask.paths(1)); +} + +TEST(FieldMaskUtilTest, JsonStringFormat) { + FieldMask mask; + string value; + EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); + EXPECT_EQ("", value); + mask.add_paths("foo_bar"); + EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); + EXPECT_EQ("fooBar", value); + mask.add_paths("bar_quz"); + EXPECT_TRUE(FieldMaskUtil::ToJsonString(mask, &value)); + EXPECT_EQ("fooBar,barQuz", value); + + FieldMaskUtil::FromJsonString("", &mask); + EXPECT_EQ(0, mask.paths_size()); + FieldMaskUtil::FromJsonString("fooBar", &mask); + EXPECT_EQ(1, mask.paths_size()); + EXPECT_EQ("foo_bar", mask.paths(0)); + FieldMaskUtil::FromJsonString("fooBar,bazQuz", &mask); + EXPECT_EQ(2, mask.paths_size()); + EXPECT_EQ("foo_bar", mask.paths(0)); + EXPECT_EQ("baz_quz", mask.paths(1)); } TEST(FieldMaskUtilTest, TestIsVaildPath) { diff --git a/src/google/protobuf/util/internal/constants.h b/src/google/protobuf/util/internal/constants.h index 0cb8f6e1..e556888c 100644 --- a/src/google/protobuf/util/internal/constants.h +++ b/src/google/protobuf/util/internal/constants.h @@ -43,13 +43,23 @@ namespace converter { const char kTypeServiceBaseUrl[] = "type.googleapis.com"; // Format string for RFC3339 timestamp formatting. -const char kRfc3339TimeFormat[] = "%Y-%m-%dT%H:%M:%S"; +const char kRfc3339TimeFormat[] = "%E4Y-%m-%dT%H:%M:%S"; -// Minimum seconds allowed in a google.protobuf.TimeStamp or Duration value. -const int64 kMinSeconds = -315576000000; +// Same as above, but the year value is not zero-padded i.e. this accepts +// timestamps like "1-01-0001T23:59:59Z" instead of "0001-01-0001T23:59:59Z". +const char kRfc3339TimeFormatNoPadding[] = "%Y-%m-%dT%H:%M:%S"; -// Maximum seconds allowed in a google.protobuf.TimeStamp or Duration value. -const int64 kMaxSeconds = 315576000000; +// Minimun seconds allowed in a google.protobuf.Timestamp value. +const int64 kTimestampMinSeconds = -62135596800; + +// Maximum seconds allowed in a google.protobuf.Timestamp value. +const int64 kTimestampMaxSeconds = 253402300799; + +// Minimum seconds allowed in a google.protobuf.Duration value. +const int64 kDurationMinSeconds = -315576000000; + +// Maximum seconds allowed in a google.protobuf.Duration value. +const int64 kDurationMaxSeconds = 315576000000; // Nano seconds in a second. const int32 kNanosPerSecond = 1000000000; diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc index b557429f..72c0aca6 100644 --- a/src/google/protobuf/util/internal/datapiece.cc +++ b/src/google/protobuf/util/internal/datapiece.cc @@ -47,6 +47,7 @@ using google::protobuf::EnumDescriptor; using google::protobuf::EnumValueDescriptor; ; ; +; using util::error::Code; using util::Status; using util::StatusOr; @@ -248,11 +249,8 @@ StatusOr DataPiece::ToBytes() const { if (type_ == TYPE_BYTES) return str_.ToString(); if (type_ == TYPE_STRING) { string decoded; - if (!WebSafeBase64Unescape(str_, &decoded)) { - if (!Base64Unescape(str_, &decoded)) { - return InvalidArgument( - ValueAsStringOrDefault("Invalid data in input.")); - } + if (!DecodeBase64(str_, &decoded)) { + return InvalidArgument(ValueAsStringOrDefault("Invalid data in input.")); } return decoded; } else { @@ -313,11 +311,49 @@ StatusOr DataPiece::GenericConvert() const { template StatusOr DataPiece::StringToNumber(bool (*func)(StringPiece, To*)) const { + if (str_.size() > 0 && (str_[0] == ' ' || str_[str_.size() - 1] == ' ')) { + return InvalidArgument(StrCat("\"", str_, "\"")); + } To result; if (func(str_, &result)) return result; return InvalidArgument(StrCat("\"", str_.ToString(), "\"")); } +bool DataPiece::DecodeBase64(StringPiece src, string* dest) const { + // Try web-safe decode first, if it fails, try the non-web-safe decode. + if (WebSafeBase64Unescape(src, dest)) { + if (use_strict_base64_decoding_) { + // In strict mode, check if the escaped version gives us the same value as + // unescaped. + string encoded; + // WebSafeBase64Escape does no padding by default. + WebSafeBase64Escape(*dest, &encoded); + // Remove trailing padding '=' characters before comparison. + StringPiece src_no_padding(src, 0, src.ends_with("=") + ? src.find_last_not_of('=') + 1 + : src.length()); + return encoded == src_no_padding; + } + return true; + } + + if (Base64Unescape(src, dest)) { + if (use_strict_base64_decoding_) { + string encoded; + Base64Escape( + reinterpret_cast(dest->data()), dest->length(), + &encoded, false); + StringPiece src_no_padding(src, 0, src.ends_with("=") + ? src.find_last_not_of('=') + 1 + : src.length()); + return encoded == src_no_padding; + } + return true; + } + + return false; +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h index f22bfe70..8b2e35d3 100644 --- a/src/google/protobuf/util/internal/datapiece.h +++ b/src/google/protobuf/util/internal/datapiece.h @@ -83,12 +83,15 @@ class LIBPROTOBUF_EXPORT DataPiece { explicit DataPiece(const double value) : type_(TYPE_DOUBLE), double_(value) {} explicit DataPiece(const float value) : type_(TYPE_FLOAT), float_(value) {} explicit DataPiece(const bool value) : type_(TYPE_BOOL), bool_(value) {} - explicit DataPiece(StringPiece value) + DataPiece(StringPiece value, bool use_strict_base64_decoding) : type_(TYPE_STRING), - str_(StringPiecePod::CreateFromStringPiece(value)) {} + str_(StringPiecePod::CreateFromStringPiece(value)), + use_strict_base64_decoding_(use_strict_base64_decoding) {} // Constructor for bytes. The second parameter is not used. - explicit DataPiece(StringPiece value, bool dummy) - : type_(TYPE_BYTES), str_(StringPiecePod::CreateFromStringPiece(value)) {} + DataPiece(StringPiece value, bool dummy, bool use_strict_base64_decoding) + : type_(TYPE_BYTES), + str_(StringPiecePod::CreateFromStringPiece(value)), + use_strict_base64_decoding_(use_strict_base64_decoding) {} DataPiece(const DataPiece& r) : type_(r.type_), str_(r.str_) {} DataPiece& operator=(const DataPiece& x) { type_ = x.type_; @@ -165,32 +168,13 @@ class LIBPROTOBUF_EXPORT DataPiece { template util::StatusOr StringToNumber(bool (*func)(StringPiece, To*)) const; + // Decodes a base64 string. Returns true on success. + bool DecodeBase64(StringPiece src, string* dest) const; + // Data type for this piece of data. Type type_; - // StringPiece is not a POD and can not be used in an union (pre C++11). We - // need a POD version of it. - struct StringPiecePod { - const char* data; - int size; - - // Create from a StringPiece. - static StringPiecePod CreateFromStringPiece(StringPiece str) { - StringPiecePod pod; - pod.data = str.data(); - pod.size = str.size(); - return pod; - } - - // Cast to StringPiece. - operator StringPiece() const { return StringPiece(data, size); } - - bool operator==(const char* value) const { - return StringPiece(data, size) == StringPiece(value); - } - - string ToString() const { return string(data, size); } - }; + typedef ::google::protobuf::internal::StringPiecePod StringPiecePod; // Stored piece of data. union { @@ -203,6 +187,9 @@ class LIBPROTOBUF_EXPORT DataPiece { bool bool_; StringPiecePod str_; }; + + // Uses a stricter version of base64 decoding for byte fields. + bool use_strict_base64_decoding_; }; } // namespace converter diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.cc b/src/google/protobuf/util/internal/default_value_objectwriter.cc index a63e560d..21d7a2e4 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.cc +++ b/src/google/protobuf/util/internal/default_value_objectwriter.cc @@ -51,7 +51,7 @@ template T ConvertTo(StringPiece value, StatusOr (DataPiece::*converter_fn)() const, T default_value) { if (value.empty()) return default_value; - StatusOr result = (DataPiece(value).*converter_fn)(); + StatusOr result = (DataPiece(value, true).*converter_fn)(); return result.ok() ? result.ValueOrDie() : default_value; } } // namespace @@ -64,6 +64,7 @@ DefaultValueObjectWriter::DefaultValueObjectWriter( type_(type), current_(NULL), root_(NULL), + field_scrub_callback_(NULL), ow_(ow) {} DefaultValueObjectWriter::~DefaultValueObjectWriter() { @@ -153,7 +154,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderString( // Since StringPiece is essentially a pointer, takes a copy of "value" to // avoid ownership issues. string_values_.push_back(new string(value.ToString())); - RenderDataPiece(name, DataPiece(*string_values_.back())); + RenderDataPiece(name, DataPiece(*string_values_.back(), true)); } return this; } @@ -163,7 +164,7 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderBytes( if (current_ == NULL) { ow_->RenderBytes(name, value); } else { - RenderDataPiece(name, DataPiece(value)); + RenderDataPiece(name, DataPiece(value, false, true)); } return this; } @@ -178,16 +179,25 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::RenderNull( return this; } +void DefaultValueObjectWriter::RegisterFieldScrubCallBack( + FieldScrubCallBackPtr field_scrub_callback) { + field_scrub_callback_.reset(field_scrub_callback.release()); +} + DefaultValueObjectWriter::Node::Node(const string& name, const google::protobuf::Type* type, NodeKind kind, const DataPiece& data, - bool is_placeholder) + bool is_placeholder, + const vector& path, + FieldScrubCallBack* field_scrub_callback) : name_(name), type_(type), kind_(kind), is_any_(false), data_(data), - is_placeholder_(is_placeholder) {} + is_placeholder_(is_placeholder), + path_(path), + field_scrub_callback_(field_scrub_callback) {} DefaultValueObjectWriter::Node* DefaultValueObjectWriter::Node::FindChild( StringPiece name) { @@ -291,6 +301,19 @@ void DefaultValueObjectWriter::Node::PopulateChildren( for (int i = 0; i < type_->fields_size(); ++i) { const google::protobuf::Field& field = type_->fields(i); + + // This code is checking if the field to be added to the tree should be + // scrubbed or not by calling the field_scrub_callback_ callback function. + vector path; + if (!path_.empty()) { + path.insert(path.begin(), path_.begin(), path_.end()); + } + path.push_back(field.name()); + if (field_scrub_callback_ != NULL && + field_scrub_callback_->Run(path, &field)) { + continue; + } + hash_map::iterator found = orig_children_map.find(field.name()); // If the child field has already been set, we just add it to the new list @@ -343,7 +366,7 @@ void DefaultValueObjectWriter::Node::PopulateChildren( field.json_name(), field_type, kind, kind == PRIMITIVE ? CreateDefaultDataPieceForField(field, typeinfo) : DataPiece::NullData(), - true)); + true, path, field_scrub_callback_)); new_children.push_back(child.release()); } // Adds all leftover nodes in children_ to the beginning of new_child. @@ -368,7 +391,8 @@ void DefaultValueObjectWriter::MaybePopulateChildrenOfAny(Node* node) { DataPiece DefaultValueObjectWriter::FindEnumDefault( const google::protobuf::Field& field, const TypeInfo* typeinfo) { - if (!field.default_value().empty()) return DataPiece(field.default_value()); + if (!field.default_value().empty()) + return DataPiece(field.default_value(), true); const google::protobuf::Enum* enum_type = typeinfo->GetEnumByTypeUrl(field.type_url()); @@ -379,7 +403,7 @@ DataPiece DefaultValueObjectWriter::FindEnumDefault( } // We treat the first value as the default if none is specified. return enum_type->enumvalue_size() > 0 - ? DataPiece(enum_type->enumvalue(0).name()) + ? DataPiece(enum_type->enumvalue(0).name(), true) : DataPiece::NullData(); } @@ -416,10 +440,10 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( ConvertTo(field.default_value(), &DataPiece::ToBool, false)); } case google::protobuf::Field_Kind_TYPE_STRING: { - return DataPiece(field.default_value()); + return DataPiece(field.default_value(), true); } case google::protobuf::Field_Kind_TYPE_BYTES: { - return DataPiece(field.default_value(), false); + return DataPiece(field.default_value(), false, true); } case google::protobuf::Field_Kind_TYPE_UINT32: case google::protobuf::Field_Kind_TYPE_FIXED32: { @@ -436,8 +460,9 @@ DataPiece DefaultValueObjectWriter::CreateDefaultDataPieceForField( DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( StringPiece name) { if (current_ == NULL) { + vector path; root_.reset(new Node(name.ToString(), &type_, OBJECT, DataPiece::NullData(), - false)); + false, path, field_scrub_callback_.get())); root_->PopulateChildren(typeinfo_); current_ = root_.get(); return this; @@ -451,7 +476,9 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartObject( name.ToString(), ((current_->kind() == LIST || current_->kind() == MAP) ? current_->type() : NULL), - OBJECT, DataPiece::NullData(), false)); + OBJECT, DataPiece::NullData(), false, + child == NULL ? current_->path() : child->path(), + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } @@ -480,8 +507,9 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::EndObject() { DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( StringPiece name) { if (current_ == NULL) { - root_.reset( - new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), false)); + vector path; + root_.reset(new Node(name.ToString(), &type_, LIST, DataPiece::NullData(), + false, path, field_scrub_callback_.get())); current_ = root_.get(); return this; } @@ -489,7 +517,9 @@ DefaultValueObjectWriter* DefaultValueObjectWriter::StartList( Node* child = current_->FindChild(name); if (child == NULL || child->kind() != LIST) { google::protobuf::scoped_ptr node( - new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false)); + new Node(name.ToString(), NULL, LIST, DataPiece::NullData(), false, + child == NULL ? current_->path() : child->path(), + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } @@ -545,7 +575,9 @@ void DefaultValueObjectWriter::RenderDataPiece(StringPiece name, if (child == NULL || child->kind() != PRIMITIVE) { // No children are found, creates a new child. google::protobuf::scoped_ptr node( - new Node(name.ToString(), NULL, PRIMITIVE, data, false)); + new Node(name.ToString(), NULL, PRIMITIVE, data, false, + child == NULL ? current_->path() : child->path(), + field_scrub_callback_.get())); child = node.get(); current_->AddChild(node.release()); } else { diff --git a/src/google/protobuf/util/internal/default_value_objectwriter.h b/src/google/protobuf/util/internal/default_value_objectwriter.h index 695b9dd8..1d85bed8 100644 --- a/src/google/protobuf/util/internal/default_value_objectwriter.h +++ b/src/google/protobuf/util/internal/default_value_objectwriter.h @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -59,6 +60,25 @@ namespace converter { // with their default values (0 for numbers, "" for strings, etc). class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { public: + // A Callback function to check whether a field needs to be scrubbed. + // + // Returns true if the field should not be present in the output. Returns + // false otherwise. + // + // The 'path' parameter is a vector of path to the field from root. For + // example: if a nested field "a.b.c" (b is the parent message field of c and + // a is the parent message field of b), then the vector should contain { "a", + // "b", "c" }. + // + // The Field* should point to the google::protobuf::Field of "c". + typedef ResultCallback2& /*path of the field*/, + const google::protobuf::Field* /*field*/> + FieldScrubCallBack; + + // A unique pointer to a DefaultValueObjectWriter::FieldScrubCallBack. + typedef google::protobuf::scoped_ptr FieldScrubCallBackPtr; + DefaultValueObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, ObjectWriter* ow); @@ -98,6 +118,10 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { virtual DefaultValueObjectWriter* RenderNull(StringPiece name); + // Register the callback for scrubbing of fields. Owership of + // field_scrub_callback pointer is also transferred to this class + void RegisterFieldScrubCallBack(FieldScrubCallBackPtr field_scrub_callback); + private: enum NodeKind { PRIMITIVE = 0, @@ -111,7 +135,8 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { class LIBPROTOBUF_EXPORT Node { public: Node(const string& name, const google::protobuf::Type* type, NodeKind kind, - const DataPiece& data, bool is_placeholder); + const DataPiece& data, bool is_placeholder, const vector& path, + FieldScrubCallBack* field_scrub_callback); virtual ~Node() { for (int i = 0; i < children_.size(); ++i) { delete children_[i]; @@ -137,17 +162,19 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // Accessors const string& name() const { return name_; } - const google::protobuf::Type* type() { return type_; } + const vector& path() const { return path_; } + + const google::protobuf::Type* type() const { return type_; } void set_type(const google::protobuf::Type* type) { type_ = type; } - NodeKind kind() { return kind_; } + NodeKind kind() const { return kind_; } - int number_of_children() { return children_.size(); } + int number_of_children() const { return children_.size(); } void set_data(const DataPiece& data) { data_ = data; } - bool is_any() { return is_any_; } + bool is_any() const { return is_any_; } void set_is_any(bool is_any) { is_any_ = is_any; } @@ -181,6 +208,15 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // the parent node's StartObject()/StartList() method is called with this // node's name. bool is_placeholder_; + + // Path of the field of this node + std::vector path_; + + // Pointer to function for determining whether a field needs to be scrubbed + // or not. This callback is owned by the creator of this node. + FieldScrubCallBack* field_scrub_callback_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node); }; // Populates children of "node" if it is an "any" Node and its real type has @@ -221,6 +257,10 @@ class LIBPROTOBUF_EXPORT DefaultValueObjectWriter : public ObjectWriter { // The stack to hold the path of Nodes from current_ to root_; std::stack stack_; + // Unique Pointer to function for determining whether a field needs to be + // scrubbed or not. + FieldScrubCallBackPtr field_scrub_callback_; + ObjectWriter* ow_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DefaultValueObjectWriter); diff --git a/src/google/protobuf/util/internal/json_objectwriter.cc b/src/google/protobuf/util/internal/json_objectwriter.cc index 94d2ab7a..b84210c1 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.cc +++ b/src/google/protobuf/util/internal/json_objectwriter.cc @@ -46,6 +46,7 @@ namespace util { namespace converter { using strings::ArrayByteSource; +; JsonObjectWriter::~JsonObjectWriter() { if (!element_->is_root()) { @@ -81,13 +82,11 @@ JsonObjectWriter* JsonObjectWriter::EndList() { return this; } -JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name, - bool value) { +JsonObjectWriter* JsonObjectWriter::RenderBool(StringPiece name, bool value) { return RenderSimple(name, value ? "true" : "false"); } -JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name, - int32 value) { +JsonObjectWriter* JsonObjectWriter::RenderInt32(StringPiece name, int32 value) { return RenderSimple(name, SimpleItoa(value)); } @@ -96,8 +95,7 @@ JsonObjectWriter* JsonObjectWriter::RenderUint32(StringPiece name, return RenderSimple(name, SimpleItoa(value)); } -JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name, - int64 value) { +JsonObjectWriter* JsonObjectWriter::RenderInt64(StringPiece name, int64 value) { WritePrefix(name); WriteChar('"'); stream_->WriteString(SimpleItoa(value)); @@ -124,8 +122,7 @@ JsonObjectWriter* JsonObjectWriter::RenderDouble(StringPiece name, return RenderString(name, DoubleAsString(value)); } -JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, - float value) { +JsonObjectWriter* JsonObjectWriter::RenderFloat(StringPiece name, float value) { if (MathLimits::IsFinite(value)) { return RenderSimple(name, SimpleFtoa(value)); } @@ -148,7 +145,12 @@ JsonObjectWriter* JsonObjectWriter::RenderBytes(StringPiece name, StringPiece value) { WritePrefix(name); string base64; - Base64Escape(value, &base64); + + if (use_websafe_base64_for_bytes_) + WebSafeBase64Escape(value.ToString(), &base64); + else + Base64Escape(value, &base64); + WriteChar('"'); // TODO(wpoon): Consider a ByteSink solution that writes the base64 bytes // directly to the stream, rather than first putting them diff --git a/src/google/protobuf/util/internal/json_objectwriter.h b/src/google/protobuf/util/internal/json_objectwriter.h index 761a0a10..cb7e2fb3 100644 --- a/src/google/protobuf/util/internal/json_objectwriter.h +++ b/src/google/protobuf/util/internal/json_objectwriter.h @@ -90,9 +90,10 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { JsonObjectWriter(StringPiece indent_string, google::protobuf::io::CodedOutputStream* out) : element_(new Element(NULL)), - stream_(out), sink_(out), - indent_string_(indent_string.ToString()) { - } + stream_(out), + sink_(out), + indent_string_(indent_string.ToString()), + use_websafe_base64_for_bytes_(false) {} virtual ~JsonObjectWriter(); // ObjectWriter methods. @@ -111,6 +112,10 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { virtual JsonObjectWriter* RenderBytes(StringPiece name, StringPiece value); virtual JsonObjectWriter* RenderNull(StringPiece name); + void set_use_websafe_base64_for_bytes(bool value) { + use_websafe_base64_for_bytes_ = value; + } + protected: class LIBPROTOBUF_EXPORT Element : public BaseElement { public: @@ -195,6 +200,10 @@ class LIBPROTOBUF_EXPORT JsonObjectWriter : public StructuredObjectWriter { ByteSinkWrapper sink_; const string indent_string_; + // Whether to use regular or websafe base64 encoding for byte fields. Defaults + // to regular base64 encoding. + bool use_websafe_base64_for_bytes_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(JsonObjectWriter); }; diff --git a/src/google/protobuf/util/internal/json_objectwriter_test.cc b/src/google/protobuf/util/internal/json_objectwriter_test.cc index 9d820162..b87b06ac 100644 --- a/src/google/protobuf/util/internal/json_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/json_objectwriter_test.cc @@ -58,7 +58,7 @@ class JsonObjectWriterTest : public ::testing::Test { string output_; StringOutputStream* const str_stream_; CodedOutputStream* const out_stream_; - ObjectWriter* ow_; + JsonObjectWriter* ow_; }; TEST_F(JsonObjectWriterTest, EmptyRootObject) { @@ -283,6 +283,30 @@ TEST_F(JsonObjectWriterTest, Stringification) { output_.substr(0, out_stream_->ByteCount())); } +TEST_F(JsonObjectWriterTest, TestRegularByteEncoding) { + ow_ = new JsonObjectWriter("", out_stream_); + ow_->StartObject("") + ->RenderBytes("bytes", "\x03\xef\xc0") + ->EndObject(); + + // Test that we get regular (non websafe) base64 encoding on byte fields by + // default. + EXPECT_EQ("{\"bytes\":\"A+/A\"}", + output_.substr(0, out_stream_->ByteCount())); +} + +TEST_F(JsonObjectWriterTest, TestWebsafeByteEncoding) { + ow_ = new JsonObjectWriter("", out_stream_); + ow_->set_use_websafe_base64_for_bytes(true); + ow_->StartObject("") + ->RenderBytes("bytes", "\x03\xef\xc0") + ->EndObject(); + + // Test that we get websafe base64 encoding when explicitly asked. + EXPECT_EQ("{\"bytes\":\"A-_A\"}", + output_.substr(0, out_stream_->ByteCount())); +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/json_stream_parser.cc b/src/google/protobuf/util/internal/json_stream_parser.cc index df916751..39be7b03 100644 --- a/src/google/protobuf/util/internal/json_stream_parser.cc +++ b/src/google/protobuf/util/internal/json_stream_parser.cc @@ -42,8 +42,9 @@ #include #include -#include #include +#include +#include namespace google { namespace protobuf { @@ -59,7 +60,7 @@ using util::error::INVALID_ARGUMENT; namespace converter { -// Number of digits in a unicode escape sequence (/uXXXX) +// Number of digits in an escaped UTF-16 code unit ('\\' 'u' X X X X) static const int kUnicodeEscapedLength = 6; // Length of the true, false, and null literals. @@ -419,9 +420,45 @@ util::Status JsonStreamParser::ParseUnicodeEscape() { } code = (code << 4) + hex_digit_to_int(p_.data()[i]); } + if (code >= JsonEscaping::kMinHighSurrogate && + code <= JsonEscaping::kMaxHighSurrogate) { + if (p_.length() < 2 * kUnicodeEscapedLength) { + if (!finishing_) { + return util::Status::CANCELLED; + } + if (!coerce_to_utf8_) { + return ReportFailure("Missing low surrogate."); + } + } else if (p_.data()[kUnicodeEscapedLength] == '\\' && + p_.data()[kUnicodeEscapedLength + 1] == 'u') { + uint32 low_code = 0; + for (int i = kUnicodeEscapedLength + 2; i < 2 * kUnicodeEscapedLength; + ++i) { + if (!isxdigit(p_.data()[i])) { + return ReportFailure("Invalid escape sequence."); + } + low_code = (low_code << 4) + hex_digit_to_int(p_.data()[i]); + } + if (low_code >= JsonEscaping::kMinLowSurrogate && + low_code <= JsonEscaping::kMaxLowSurrogate) { + // Convert UTF-16 surrogate pair to 21-bit Unicode codepoint. + code = (((code & 0x3FF) << 10) | (low_code & 0x3FF)) + + JsonEscaping::kMinSupplementaryCodePoint; + // Advance past the first code unit escape. + p_.remove_prefix(kUnicodeEscapedLength); + } else if (!coerce_to_utf8_) { + return ReportFailure("Invalid low surrogate."); + } + } else if (!coerce_to_utf8_) { + return ReportFailure("Missing low surrogate."); + } + } + if (!coerce_to_utf8_ && !IsValidCodePoint(code)) { + return ReportFailure("Invalid unicode code point."); + } char buf[UTFmax]; int len = EncodeAsUTF8Char(code, buf); - // Advance past the unicode escape. + // Advance past the [final] code unit escape. p_.remove_prefix(kUnicodeEscapedLength); parsed_storage_.append(buf, len); return util::Status::OK; @@ -473,7 +510,7 @@ util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { floating = true; continue; } - if (c == '+' || c == '-') continue; + if (c == '+' || c == '-' || c == 'x') continue; // Not a valid number character, break out. break; } @@ -499,6 +536,10 @@ util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { // Positive non-floating point number, parse as a uint64. if (!negative) { + // Octal/Hex numbers are not valid JSON values. + if (number.length() >= 2 && number[0] == '0') { + return ReportFailure("Octal/hex numbers are not valid JSON values."); + } if (!safe_strtou64(number, &result->uint_val)) { return ReportFailure("Unable to parse number."); } @@ -507,6 +548,10 @@ util::Status JsonStreamParser::ParseNumberHelper(NumberResult* result) { return util::Status::OK; } + // Octal/Hex numbers are not valid JSON values. + if (number.length() >= 3 && number[1] == '0') { + return ReportFailure("Octal/hex numbers are not valid JSON values."); + } // Negative non-floating point number, parse as an int64. if (!safe_strto64(number, &result->int_val)) { return ReportFailure("Unable to parse number."); @@ -677,8 +722,9 @@ util::Status JsonStreamParser::ReportFailure(StringPiece message) { static const int kContextLength = 20; const char* p_start = p_.data(); const char* json_start = json_.data(); - const char* begin = max(p_start - kContextLength, json_start); - const char* end = min(p_start + kContextLength, json_start + json_.size()); + const char* begin = std::max(p_start - kContextLength, json_start); + const char* end = + std::min(p_start + kContextLength, json_start + json_.size()); StringPiece segment(begin, end - begin); string location(p_start - begin, ' '); location.push_back('^'); @@ -706,8 +752,8 @@ void JsonStreamParser::SkipWhitespace() { void JsonStreamParser::Advance() { // Advance by moving one UTF8 character while making sure we don't go beyond // the length of StringPiece. - p_.remove_prefix( - min(p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length()))); + p_.remove_prefix(std::min( + p_.length(), UTF8FirstLetterNumBytes(p_.data(), p_.length()))); } util::Status JsonStreamParser::ParseKey() { diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc index 3414826e..4b691107 100644 --- a/src/google/protobuf/util/internal/json_stream_parser_test.cc +++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc @@ -124,8 +124,9 @@ class JsonStreamParserTest : public ::testing::Test { EXPECT_OK(result); } - void DoErrorTest(StringPiece json, int split, StringPiece error_prefix) { - util::Status result = RunTest(json, split); + void DoErrorTest(StringPiece json, int split, StringPiece error_prefix, + bool coerce_utf8 = false) { + util::Status result = RunTest(json, split, coerce_utf8); EXPECT_EQ(util::error::INVALID_ARGUMENT, result.error_code()); StringPiece error_message(result.error_message()); EXPECT_EQ(error_prefix, error_message.substr(0, error_prefix.size())); @@ -230,6 +231,32 @@ TEST_F(JsonStreamParserTest, SimpleUnsignedInt) { } } +TEST_F(JsonStreamParserTest, OctalNumberIsInvalid) { + StringPiece str = "01234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } + str = "-01234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } +} + +TEST_F(JsonStreamParserTest, HexNumberIsInvalid) { + StringPiece str = "0x1234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } + str = "-0x1234"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Octal/hex numbers are not valid JSON values."); + } + str = "12x34"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Unable to parse number."); + } +} + // - single and double quoted strings TEST_F(JsonStreamParserTest, EmptyDoubleQuotedString) { StringPiece str = "\"\""; @@ -351,19 +378,62 @@ TEST_F(JsonStreamParserTest, RejectNonUtf8WhenNotCoerced) { DoErrorTest("\xFF{}", 0, "Encountered non UTF-8 code points."); } -#ifndef _MSC_VER // - unicode handling in strings TEST_F(JsonStreamParserTest, UnicodeEscaping) { StringPiece str = "[\"\\u0639\\u0631\\u0628\\u0649\"]"; for (int i = 0; i <= str.length(); ++i) { - // TODO(xiaofeng): Figure out what default encoding to use for JSON strings. - // In protobuf we use UTF-8 for strings, but for JSON we probably should - // allow different encodings? - ow_.StartList("")->RenderString("", "\u0639\u0631\u0628\u0649")->EndList(); + ow_.StartList("") + ->RenderString("", "\xD8\xB9\xD8\xB1\xD8\xA8\xD9\x89") + ->EndList(); DoTest(str, i); } } -#endif + +// - unicode UTF-16 surrogate pair handling in strings +TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) { + StringPiece str = + "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\U0001F36F\"]"; + for (int i = 0; i <= str.length(); ++i) { + ow_.StartList("") + ->RenderString("", + "\xE0\xAF\xAE\xF0\x90\x87\xB1\xF0\x93\x86\xA4\xF0" + "\x9F\x90\x9D\xF0\x9F\x8D\xAF") + ->EndList(); + DoTest(str, i); + } +} + + +TEST_F(JsonStreamParserTest, UnicodeEscapingInvalidCodePointWhenNotCoerced) { + // A low surrogate alone. + StringPiece str = "[\"\\ude36\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid unicode code point."); + } +} + +TEST_F(JsonStreamParserTest, UnicodeEscapingMissingLowSurrogateWhenNotCoerced) { + // A high surrogate alone. + StringPiece str = "[\"\\ud83d\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Missing low surrogate."); + } + // A high surrogate with some trailing characters. + str = "[\"\\ud83d|ude36\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Missing low surrogate."); + } + // A high surrogate with half a low surrogate. + str = "[\"\\ud83d\\ude--\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid escape sequence."); + } + // Two high surrogates. + str = "[\"\\ud83d\\ud83d\"]"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid low surrogate."); + } +} // - ascii escaping (\b, \f, \n, \r, \t, \v) TEST_F(JsonStreamParserTest, AsciiEscaping) { @@ -629,6 +699,22 @@ TEST_F(JsonStreamParserTest, DoubleTooBig) { } */ +// invalid bare backslash. +TEST_F(JsonStreamParserTest, UnfinishedEscape) { + StringPiece str = "\"\\"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Closing quote expected in string."); + } +} + +// invalid bare backslash u. +TEST_F(JsonStreamParserTest, UnfinishedUnicodeEscape) { + StringPiece str = "\"\\u"; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Illegal hex string."); + } +} + // invalid unicode sequence. TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) { StringPiece str = "\"\\u12"; @@ -637,6 +723,15 @@ TEST_F(JsonStreamParserTest, UnicodeEscapeCutOff) { } } +// invalid unicode sequence (valid in modern EcmaScript but not in JSON). +TEST_F(JsonStreamParserTest, BracketedUnicodeEscape) { + StringPiece str = "\"\\u{1f36f}\""; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid escape sequence."); + } +} + + TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) { StringPiece str = "\"\\u12$4hello"; for (int i = 0; i <= str.length(); ++i) { @@ -644,6 +739,14 @@ TEST_F(JsonStreamParserTest, UnicodeEscapeInvalidCharacters) { } } +// invalid unicode sequence in low half surrogate: g is not a hex digit. +TEST_F(JsonStreamParserTest, UnicodeEscapeLowHalfSurrogateInvalidCharacters) { + StringPiece str = "\"\\ud800\\udcfg\""; + for (int i = 0; i <= str.length(); ++i) { + DoErrorTest(str, i, "Invalid escape sequence."); + } +} + // Extra commas with an object or array. TEST_F(JsonStreamParserTest, ExtraCommaInObject) { StringPiece str = "{'k1': true,,'k2': false}"; diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h index e695f45e..9f07363d 100644 --- a/src/google/protobuf/util/internal/object_writer.h +++ b/src/google/protobuf/util/internal/object_writer.h @@ -105,10 +105,27 @@ class LIBPROTOBUF_EXPORT ObjectWriter { static void RenderDataPieceTo(const DataPiece& data, StringPiece name, ObjectWriter* ow); + // Indicates whether this ObjectWriter has completed writing the root message, + // usually this means writing of one complete object. Subclasses must override + // this behavior appropriately. + virtual bool done() { return false; } + + void set_use_strict_base64_decoding(bool value) { + use_strict_base64_decoding_ = value; + } + + bool use_strict_base64_decoding() const { + return use_strict_base64_decoding_; + } + protected: - ObjectWriter() {} + ObjectWriter() : use_strict_base64_decoding_(true) {} private: + // If set to true, we use the stricter version of base64 decoding for byte + // fields by making sure decoded version encodes back to the original string. + bool use_strict_base64_decoding_; + // Do not add any data members to this class. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ObjectWriter); }; diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc index 47e0009e..36b79410 100644 --- a/src/google/protobuf/util/internal/proto_writer.cc +++ b/src/google/protobuf/util/internal/proto_writer.cc @@ -447,9 +447,7 @@ ProtoWriter* ProtoWriter::StartObject(StringPiece name) { return this; } - WriteTag(*field); - element_.reset(new ProtoElement(element_.release(), field, *type, false)); - return this; + return StartObjectField(*field, *type); } ProtoWriter* ProtoWriter::EndObject() { @@ -488,8 +486,7 @@ ProtoWriter* ProtoWriter::StartList(StringPiece name) { return this; } - element_.reset(new ProtoElement(element_.release(), field, *type, true)); - return this; + return StartListField(*field, *type); } ProtoWriter* ProtoWriter::EndList() { @@ -518,98 +515,7 @@ ProtoWriter* ProtoWriter::RenderDataPiece(StringPiece name, return this; } - // Pushing a ProtoElement and then pop it off at the end for 2 purposes: - // error location reporting and required field accounting. - element_.reset(new ProtoElement(element_.release(), field, *type, false)); - - if (field->kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN || - field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { - InvalidValue(field->type_url().empty() - ? google::protobuf::Field_Kind_Name(field->kind()) - : field->type_url(), - data.ValueAsStringOrDefault("")); - element_.reset(element()->pop()); - return this; - } - - switch (field->kind()) { - case google::protobuf::Field_Kind_TYPE_INT32: { - status = WriteInt32(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SFIXED32: { - status = WriteSFixed32(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SINT32: { - status = WriteSInt32(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_FIXED32: { - status = WriteFixed32(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_UINT32: { - status = WriteUInt32(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_INT64: { - status = WriteInt64(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SFIXED64: { - status = WriteSFixed64(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_SINT64: { - status = WriteSInt64(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_FIXED64: { - status = WriteFixed64(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_UINT64: { - status = WriteUInt64(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_DOUBLE: { - status = WriteDouble(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_FLOAT: { - status = WriteFloat(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_BOOL: { - status = WriteBool(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_BYTES: { - status = WriteBytes(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_STRING: { - status = WriteString(field->number(), data, stream_.get()); - break; - } - case google::protobuf::Field_Kind_TYPE_ENUM: { - status = WriteEnum(field->number(), data, - typeinfo_->GetEnumByTypeUrl(field->type_url()), - stream_.get()); - break; - } - default: // TYPE_GROUP or TYPE_MESSAGE - status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie()); - } - - if (!status.ok()) { - InvalidValue(google::protobuf::Field_Kind_Name(field->kind()), - status.error_message()); - } - - element_.reset(element()->pop()); - return this; + return RenderPrimitiveField(*field, *type, data); } bool ProtoWriter::ValidOneof(const google::protobuf::Field& field, @@ -635,6 +541,118 @@ bool ProtoWriter::IsRepeated(const google::protobuf::Field& field) { google::protobuf::Field_Cardinality_CARDINALITY_REPEATED; } +ProtoWriter* ProtoWriter::StartObjectField(const google::protobuf::Field& field, + const google::protobuf::Type& type) { + WriteTag(field); + element_.reset(new ProtoElement(element_.release(), &field, type, false)); + return this; +} + +ProtoWriter* ProtoWriter::StartListField(const google::protobuf::Field& field, + const google::protobuf::Type& type) { + element_.reset(new ProtoElement(element_.release(), &field, type, true)); + return this; +} + +ProtoWriter* ProtoWriter::RenderPrimitiveField( + const google::protobuf::Field& field, const google::protobuf::Type& type, + const DataPiece& data) { + Status status; + + // Pushing a ProtoElement and then pop it off at the end for 2 purposes: + // error location reporting and required field accounting. + element_.reset(new ProtoElement(element_.release(), &field, type, false)); + + if (field.kind() == google::protobuf::Field_Kind_TYPE_UNKNOWN || + field.kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) { + InvalidValue(field.type_url().empty() + ? google::protobuf::Field_Kind_Name(field.kind()) + : field.type_url(), + data.ValueAsStringOrDefault("")); + element_.reset(element()->pop()); + return this; + } + + switch (field.kind()) { + case google::protobuf::Field_Kind_TYPE_INT32: { + status = WriteInt32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SFIXED32: { + status = WriteSFixed32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SINT32: { + status = WriteSInt32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_FIXED32: { + status = WriteFixed32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_UINT32: { + status = WriteUInt32(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_INT64: { + status = WriteInt64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SFIXED64: { + status = WriteSFixed64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_SINT64: { + status = WriteSInt64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_FIXED64: { + status = WriteFixed64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_UINT64: { + status = WriteUInt64(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_DOUBLE: { + status = WriteDouble(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_FLOAT: { + status = WriteFloat(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_BOOL: { + status = WriteBool(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_BYTES: { + status = WriteBytes(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_STRING: { + status = WriteString(field.number(), data, stream_.get()); + break; + } + case google::protobuf::Field_Kind_TYPE_ENUM: { + status = WriteEnum(field.number(), data, + typeinfo_->GetEnumByTypeUrl(field.type_url()), + stream_.get()); + break; + } + default: // TYPE_GROUP or TYPE_MESSAGE + status = Status(INVALID_ARGUMENT, data.ToString().ValueOrDie()); + } + + if (!status.ok()) { + InvalidValue(google::protobuf::Field_Kind_Name(field.kind()), + status.error_message()); + } + + element_.reset(element()->pop()); + return this; +} + const google::protobuf::Field* ProtoWriter::BeginNamed(StringPiece name, bool is_list) { if (invalid_depth_ > 0) { diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h index e631e56f..957565e7 100644 --- a/src/google/protobuf/util/internal/proto_writer.h +++ b/src/google/protobuf/util/internal/proto_writer.h @@ -106,10 +106,12 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { return RenderDataPiece(name, DataPiece(value)); } virtual ProtoWriter* RenderString(StringPiece name, StringPiece value) { - return RenderDataPiece(name, DataPiece(value)); + return RenderDataPiece(name, + DataPiece(value, use_strict_base64_decoding())); } virtual ProtoWriter* RenderBytes(StringPiece name, StringPiece value) { - return RenderDataPiece(name, DataPiece(value, false)); + return RenderDataPiece( + name, DataPiece(value, false, use_strict_base64_decoding())); } virtual ProtoWriter* RenderNull(StringPiece name) { return RenderDataPiece(name, DataPiece::NullData()); @@ -126,7 +128,7 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { } // When true, we finished writing to output a complete message. - bool done() const { return done_; } + bool done() { return done_; } // Returns the proto stream object. google::protobuf::io::CodedOutputStream* stream() { return stream_.get(); } @@ -266,6 +268,19 @@ class LIBPROTOBUF_EXPORT ProtoWriter : public StructuredObjectWriter { // Returns true if the field is repeated. bool IsRepeated(const google::protobuf::Field& field); + // Starts an object given the field and the enclosing type. + ProtoWriter* StartObjectField(const google::protobuf::Field& field, + const google::protobuf::Type& type); + + // Starts a list given the field and the enclosing type. + ProtoWriter* StartListField(const google::protobuf::Field& field, + const google::protobuf::Type& type); + + // Renders a primitve field given the field and the enclosing type. + ProtoWriter* RenderPrimitiveField(const google::protobuf::Field& field, + const google::protobuf::Type& type, + const DataPiece& value); + private: // Variables for describing the structure of the input tree: // master_type_: descriptor for the whole protobuf message. diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 034d616f..297c011a 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -83,6 +83,29 @@ const google::protobuf::EnumValue* FindEnumValueByNumber( // Utility function to format nanos. const string FormatNanos(uint32 nanos); + +StatusOr MapKeyDefaultValueAsString( + const google::protobuf::Field& field) { + switch (field.kind()) { + case google::protobuf::Field_Kind_TYPE_BOOL: + return string("false"); + case google::protobuf::Field_Kind_TYPE_INT32: + case google::protobuf::Field_Kind_TYPE_INT64: + case google::protobuf::Field_Kind_TYPE_UINT32: + case google::protobuf::Field_Kind_TYPE_UINT64: + case google::protobuf::Field_Kind_TYPE_SINT32: + case google::protobuf::Field_Kind_TYPE_SINT64: + case google::protobuf::Field_Kind_TYPE_SFIXED32: + case google::protobuf::Field_Kind_TYPE_SFIXED64: + case google::protobuf::Field_Kind_TYPE_FIXED32: + case google::protobuf::Field_Kind_TYPE_FIXED64: + return string("0"); + case google::protobuf::Field_Kind_TYPE_STRING: + return string(); + default: + return Status(util::error::INTERNAL, "Invalid map key type."); + } +} } // namespace @@ -92,14 +115,19 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( : stream_(stream), typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), own_typeinfo_(true), - type_(type) { + type_(type), + use_lower_camel_for_enums_(false) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; } ProtoStreamObjectSource::ProtoStreamObjectSource( google::protobuf::io::CodedInputStream* stream, const TypeInfo* typeinfo, const google::protobuf::Type& type) - : stream_(stream), typeinfo_(typeinfo), own_typeinfo_(false), type_(type) { + : stream_(stream), + typeinfo_(typeinfo), + own_typeinfo_(false), + type_(type), + use_lower_camel_for_enums_(false) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; } @@ -238,9 +266,21 @@ StatusOr ProtoStreamObjectSource::RenderMap( map_key = ReadFieldValueAsString(*field); } else if (field->number() == 2) { if (map_key.empty()) { - return Status(util::error::INTERNAL, "Map key must be non-empty"); + // An absent map key is treated as the default. + const google::protobuf::Field* key_field = + FindFieldByNumber(*field_type, 1); + if (key_field == NULL) { + // The Type info for this map entry is incorrect. It should always + // have a field named "key" and with field number 1. + return Status(util::error::INTERNAL, "Invalid map entry."); + } + ASSIGN_OR_RETURN(map_key, MapKeyDefaultValueAsString(*key_field)); } RETURN_IF_ERROR(RenderField(field, map_key, ow)); + } else { + // The Type info for this map entry is incorrect. It should contain + // exactly two fields with field number 1 and 2. + return Status(util::error::INTERNAL, "Invalid map entry."); } } stream_->PopLimit(old_limit); @@ -266,7 +306,7 @@ Status ProtoStreamObjectSource::RenderTimestamp( pair p = os->ReadSecondsAndNanos(type); int64 seconds = p.first; int32 nanos = p.second; - if (seconds > kMaxSeconds || seconds < kMinSeconds) { + if (seconds > kTimestampMaxSeconds || seconds < kTimestampMinSeconds) { return Status( util::error::INTERNAL, StrCat("Timestamp seconds exceeds limit for field: ", field_name)); @@ -290,7 +330,7 @@ Status ProtoStreamObjectSource::RenderDuration( pair p = os->ReadSecondsAndNanos(type); int64 seconds = p.first; int32 nanos = p.second; - if (seconds > kMaxSeconds || seconds < kMinSeconds) { + if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds) { return Status( util::error::INTERNAL, StrCat("Duration seconds exceeds limit for field: ", field_name)); @@ -807,7 +847,10 @@ Status ProtoStreamObjectSource::RenderNonMessageField( const google::protobuf::EnumValue* enum_value = FindEnumValueByNumber(*en, buffer32); if (enum_value != NULL) { - ow->RenderString(field_name, enum_value->name()); + if (use_lower_camel_for_enums_) + ow->RenderString(field_name, ToCamelCase(enum_value->name())); + else + ow->RenderString(field_name, enum_value->name()); } } else { GOOGLE_LOG(INFO) << "Unknown enum skipped: " << field->type_url(); diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index 78defa1d..17e03b73 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -82,6 +82,34 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { virtual util::Status NamedWriteTo(StringPiece name, ObjectWriter* ow) const; + // Sets whether or not to use lowerCamelCase casing for enum values. If set to + // false, enum values are output without any case conversions. + // + // For example, if we have an enum: + // enum Type { + // ACTION_AND_ADVENTURE = 1; + // } + // Type type = 20; + // + // And this option is set to true. Then the rendered "type" field will have + // the string "actionAndAdventure". + // { + // ... + // "type": "actionAndAdventure", + // ... + // } + // + // If set to false, the rendered "type" field will have the string + // "ACTION_AND_ADVENTURE". + // { + // ... + // "type": "ACTION_AND_ADVENTURE", + // ... + // } + void set_use_lower_camel_for_enums(bool value) { + use_lower_camel_for_enums_ = value; + } + protected: // Writes a proto2 Message to the ObjectWriter. When the given end_tag is // found this method will complete, allowing it to be used for parsing both @@ -237,6 +265,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { const google::protobuf::Type& type_; + // Whether to render enums using lowerCamelCase. Defaults to false. + bool use_lower_camel_for_enums_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource); }; diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc index 561f6763..1b32c803 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -75,6 +76,8 @@ using google::protobuf::testing::PackedPrimitive; using google::protobuf::testing::Primitive; using google::protobuf::testing::more_author; using google::protobuf::testing::maps::MapOut; +using google::protobuf::testing::maps::MapOutWireFormat; +using google::protobuf::testing::timestampduration::TimestampDuration; using google::protobuf::testing::anys::AnyOut; using google::protobuf::testing::anys::AnyM; using google::protobuf::testing::FieldMaskTest; @@ -92,7 +95,11 @@ string GetTypeUrl(const Descriptor* descriptor) { class ProtostreamObjectSourceTest : public ::testing::TestWithParam { protected: - ProtostreamObjectSourceTest() : helper_(GetParam()), mock_(), ow_(&mock_) { + ProtostreamObjectSourceTest() + : helper_(GetParam()), + mock_(), + ow_(&mock_), + use_lower_camel_for_enums_(false) { helper_.ResetTypeInfo(Book::descriptor()); } @@ -112,6 +119,7 @@ class ProtostreamObjectSourceTest google::protobuf::scoped_ptr os( helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor))); + if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true); return os->WriteTo(&mock_); } @@ -256,10 +264,13 @@ class ProtostreamObjectSourceTest return primitive; } + void UseLowerCamelForEnums() { use_lower_camel_for_enums_ = true; } + testing::TypeInfoTestHelper helper_; ::testing::NiceMock mock_; ExpectingObjectWriter ow_; + bool use_lower_camel_for_enums_; }; INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, @@ -461,6 +472,25 @@ TEST_P(ProtostreamObjectSourceTest, DoTest(book, Book::descriptor()); } +TEST_P(ProtostreamObjectSourceTest, LowerCamelEnumOutputTest) { + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + + UseLowerCamelForEnums(); + + ow_.StartObject("")->RenderString("type", "actionAndAdventure")->EndObject(); + DoTest(book, Book::descriptor()); +} + +TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) { + Book book; + book.set_type(Book::ACTION_AND_ADVENTURE); + ow_.StartObject("") + ->RenderString("type", "ACTION_AND_ADVENTURE") + ->EndObject(); + DoTest(book, Book::descriptor()); +} + class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest { protected: ProtostreamObjectSourceMapsTest() { @@ -541,6 +571,67 @@ TEST_P(ProtostreamObjectSourceMapsTest, MapsTest) { DoTest(out, MapOut::descriptor()); } +TEST_P(ProtostreamObjectSourceMapsTest, MissingKeysTest) { + // MapOutWireFormat has the same wire representation with MapOut but uses + // repeated message fields to represent map fields so we can intentionally + // leave out the key field or the value field of a map entry. + MapOutWireFormat out; + // Create some map entries without keys. They will be rendered with the + // default values ("" for strings, "0" for integers, etc.). + // { + // "map1": { + // "": { + // "foo": "foovalue" + // } + // }, + // "map2": { + // "": { + // "map1": { + // "nested_key1": { + // "foo": "nested_foo" + // } + // } + // } + // }, + // "map3": { + // "0": "one one one" + // }, + // "map4": { + // "false": "bool" + // } + // } + out.add_map1()->mutable_value()->set_foo("foovalue"); + MapOut* nested = out.add_map2()->mutable_value(); + (*nested->mutable_map1())["nested_key1"].set_foo("nested_foo"); + out.add_map3()->set_value("one one one"); + out.add_map4()->set_value("bool"); + + ow_.StartObject("") + ->StartObject("map1") + ->StartObject("") + ->RenderString("foo", "foovalue") + ->EndObject() + ->EndObject() + ->StartObject("map2") + ->StartObject("") + ->StartObject("map1") + ->StartObject("nested_key1") + ->RenderString("foo", "nested_foo") + ->EndObject() + ->EndObject() + ->EndObject() + ->EndObject() + ->StartObject("map3") + ->RenderString("0", "one one one") + ->EndObject() + ->StartObject("map4") + ->RenderString("false", "bool") + ->EndObject() + ->EndObject(); + + DoTest(out, MapOut::descriptor()); +} + class ProtostreamObjectSourceAnysTest : public ProtostreamObjectSourceTest { protected: ProtostreamObjectSourceAnysTest() { @@ -824,6 +915,63 @@ TEST_P(ProtostreamObjectSourceFieldMaskTest, FieldMaskRenderSuccess) { DoTest(out, FieldMaskTest::descriptor()); } +class ProtostreamObjectSourceTimestampTest + : public ProtostreamObjectSourceTest { + protected: + ProtostreamObjectSourceTimestampTest() { + helper_.ResetTypeInfo(TimestampDuration::descriptor()); + } +}; + +INSTANTIATE_TEST_CASE_P(DifferentTypeInfoSourceTest, + ProtostreamObjectSourceTimestampTest, + ::testing::Values( + testing::USE_TYPE_RESOLVER)); + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampBelowMinTest) { + TimestampDuration out; + google::protobuf::Timestamp* ts = out.mutable_ts(); + // Min allowed seconds - 1 + ts->set_seconds(kTimestampMinSeconds - 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidTimestampAboveMaxTest) { + TimestampDuration out; + google::protobuf::Timestamp* ts = out.mutable_ts(); + // Max allowed seconds + 1 + ts->set_seconds(kTimestampMaxSeconds + 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationBelowMinTest) { + TimestampDuration out; + google::protobuf::Duration* dur = out.mutable_dur(); + // Min allowed seconds - 1 + dur->set_seconds(kDurationMinSeconds - 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + +TEST_P(ProtostreamObjectSourceTimestampTest, InvalidDurationAboveMaxTest) { + TimestampDuration out; + google::protobuf::Duration* dur = out.mutable_dur(); + // Min allowed seconds + 1 + dur->set_seconds(kDurationMaxSeconds + 1); + ow_.StartObject(""); + + Status status = ExecuteTest(out, TimestampDuration::descriptor()); + EXPECT_EQ(util::error::INTERNAL, status.error_code()); +} + } // namespace converter } // namespace util } // namespace protobuf diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index 786bf0be..94ddb428 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -58,17 +58,20 @@ using util::StatusOr; ProtoStreamObjectWriter::ProtoStreamObjectWriter( TypeResolver* type_resolver, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener) + strings::ByteSink* output, ErrorListener* listener, + const ProtoStreamObjectWriter::Options& options) : ProtoWriter(type_resolver, type, output, listener), master_type_(type), - current_(NULL) {} + current_(NULL), + options_(options) {} ProtoStreamObjectWriter::ProtoStreamObjectWriter( const TypeInfo* typeinfo, const google::protobuf::Type& type, strings::ByteSink* output, ErrorListener* listener) : ProtoWriter(typeinfo, type, output, listener), master_type_(type), - current_(NULL) {} + current_(NULL), + options_(ProtoStreamObjectWriter::Options::Defaults()) {} ProtoStreamObjectWriter::~ProtoStreamObjectWriter() { if (current_ == NULL) return; @@ -439,7 +442,8 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject( // name): // { "key": "", "value": { Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", DataPiece(name)); + ProtoWriter::RenderDataPiece("key", + DataPiece(name, use_strict_base64_decoding())); Push("value", Item::MESSAGE, true, false); // Make sure we are valid so far after starting map fields. @@ -604,7 +608,8 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartList(StringPiece name) { // Render // { "key": "", "value": { Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", DataPiece(name)); + ProtoWriter::RenderDataPiece("key", + DataPiece(name, use_strict_base64_decoding())); Push("value", Item::MESSAGE, true, false); // Make sure we are valid after pushing all above items. @@ -758,8 +763,36 @@ Status ProtoStreamObjectWriter::RenderStructValue(ProtoStreamObjectWriter* ow, string struct_field_name; switch (data.type()) { // Our JSON parser parses numbers as either int64, uint64, or double. - case DataPiece::TYPE_INT64: - case DataPiece::TYPE_UINT64: + case DataPiece::TYPE_INT64: { + // If the option to treat integers as strings is set, then render them as + // strings. Otherwise, fallback to rendering them as double. + if (ow->options_.struct_integers_as_strings) { + StatusOr int_value = data.ToInt64(); + if (int_value.ok()) { + ow->ProtoWriter::RenderDataPiece( + "string_value", + DataPiece(SimpleItoa(int_value.ValueOrDie()), true)); + return Status::OK; + } + } + struct_field_name = "number_value"; + break; + } + case DataPiece::TYPE_UINT64: { + // If the option to treat integers as strings is set, then render them as + // strings. Otherwise, fallback to rendering them as double. + if (ow->options_.struct_integers_as_strings) { + StatusOr int_value = data.ToUint64(); + if (int_value.ok()) { + ow->ProtoWriter::RenderDataPiece( + "string_value", + DataPiece(SimpleItoa(int_value.ValueOrDie()), true)); + return Status::OK; + } + } + struct_field_name = "number_value"; + break; + } case DataPiece::TYPE_DOUBLE: { struct_field_name = "number_value"; break; @@ -812,7 +845,7 @@ Status ProtoStreamObjectWriter::RenderTimestamp(ProtoStreamObjectWriter* ow, static inline util::Status RenderOneFieldPath(ProtoStreamObjectWriter* ow, StringPiece path) { ow->ProtoWriter::RenderDataPiece( - "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase))); + "paths", DataPiece(ConvertFieldMaskPath(path, &ToSnakeCase), true)); return Status::OK; } @@ -871,7 +904,7 @@ Status ProtoStreamObjectWriter::RenderDuration(ProtoStreamObjectWriter* ow, nanos = sign * nanos; int64 seconds = sign * unsigned_seconds; - if (seconds > kMaxSeconds || seconds < kMinSeconds || + if (seconds > kDurationMaxSeconds || seconds < kDurationMinSeconds || nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { return Status(INVALID_ARGUMENT, "Duration value exceeds limits"); } @@ -925,7 +958,8 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( // Render an item in repeated map list. // { "key": "", "value": Push("", Item::MESSAGE, false, false); - ProtoWriter::RenderDataPiece("key", DataPiece(name)); + ProtoWriter::RenderDataPiece("key", + DataPiece(name, use_strict_base64_decoding())); field = Lookup("value"); if (field == NULL) { GOOGLE_LOG(DFATAL) << "Map does not have a value field."; diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index 08ac6e33..96ea3f2b 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -74,10 +74,30 @@ class ObjectLocationTracker; // It also supports streaming. class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { public: + // Options that control ProtoStreamObjectWriter class's behavior. + struct Options { + // Treats integer inputs in google.protobuf.Struct as strings. Normally, + // integer values are returned in double field "number_value" of + // google.protobuf.Struct. However, this can cause precision loss for + // int64/uint64 inputs. This option is provided for cases that want to + // preserve integer precision. + bool struct_integers_as_strings; + + Options() : struct_integers_as_strings(false) {} + + // Default instance of Options with all options set to defaults. + static const Options& Defaults() { + static Options defaults; + return defaults; + } + }; + // Constructor. Does not take ownership of any parameter passed in. ProtoStreamObjectWriter(TypeResolver* type_resolver, const google::protobuf::Type& type, - strings::ByteSink* output, ErrorListener* listener); + strings::ByteSink* output, ErrorListener* listener, + const ProtoStreamObjectWriter::Options& options = + ProtoStreamObjectWriter::Options::Defaults()); virtual ~ProtoStreamObjectWriter(); // ObjectWriter methods. @@ -301,6 +321,9 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { // The current element, variable for internal state processing. google::protobuf::scoped_ptr current_; + // Reference to the options that control this class's behavior. + const ProtoStreamObjectWriter::Options options_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectWriter); }; diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index 5f9ffb95..41eaebc0 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -90,6 +90,12 @@ string GetTypeUrl(const Descriptor* descriptor) { } } // namespace +#if __cplusplus >= 201103L + using std::get; +#else + using std::tr1::get; +#endif + class BaseProtoStreamObjectWriterTest : public ::testing::TestWithParam { protected: @@ -122,7 +128,13 @@ class BaseProtoStreamObjectWriterTest GOOGLE_CHECK(!descriptors.empty()) << "Must have at least one descriptor!"; helper_.ResetTypeInfo(descriptors); ow_.reset(helper_.NewProtoWriter(GetTypeUrl(descriptors[0]), output_.get(), - &listener_)); + &listener_, options_)); + } + + void ResetTypeInfo(const Descriptor* descriptor) { + vector descriptors; + descriptors.push_back(descriptor); + ResetTypeInfo(descriptors); } virtual ~BaseProtoStreamObjectWriterTest() {} @@ -155,16 +167,12 @@ class BaseProtoStreamObjectWriterTest MockErrorListener listener_; google::protobuf::scoped_ptr output_; google::protobuf::scoped_ptr ow_; + ProtoStreamObjectWriter::Options options_; }; MATCHER_P(HasObjectLocation, expected, "Verifies the expected object location") { - string actual; -#if __cplusplus >= 201103L - actual = std::get<0>(arg).ToString(); -#else - actual = std::tr1::get<0>(arg).ToString(); -#endif + string actual = get<0>(arg).ToString(); if (actual.compare(expected) == 0) return true; *result_listener << "actual location is: " << actual; return false; @@ -289,8 +297,7 @@ TEST_P(ProtoStreamObjectWriterTest, PrimitiveFromStringConversion) { full.add_rep_double(-8.05L); full.add_rep_bool(false); - ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()), - output_.get(), &listener_)); + ResetTypeInfo(Primitive::descriptor()); ow_->StartObject("") ->RenderString("fix32", "101") @@ -363,8 +370,7 @@ TEST_P(ProtoStreamObjectWriterTest, InfinityInputTest) { full.set_float_(std::numeric_limits::infinity()); full.set_str("-Infinity"); - ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()), - output_.get(), &listener_)); + ResetTypeInfo(Primitive::descriptor()); EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"), StringPiece("\"Infinity\""))) @@ -397,8 +403,7 @@ TEST_P(ProtoStreamObjectWriterTest, NaNInputTest) { full.set_float_(std::numeric_limits::quiet_NaN()); full.set_str("NaN"); - ow_.reset(helper_.NewProtoWriter(GetTypeUrl(Primitive::descriptor()), - output_.get(), &listener_)); + ResetTypeInfo(Primitive::descriptor()); EXPECT_CALL(listener_, InvalidValue(_, StringPiece("TYPE_INT32"), StringPiece("\"NaN\""))) @@ -887,6 +892,124 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseTimestamp) { CheckOutput(timestamp); } +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampYearNotZeroPadded) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(-61665654145); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "15-11-23T03:37:35.033155Z") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampYearZeroPadded) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(-61665654145); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "0015-11-23T03:37:35.033155Z") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampWithPositiveOffset) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(1448249855); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "2015-11-23T11:47:35.033155+08:10") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + ParseTimestampWithNegativeOffset) { + TimestampDuration timestamp; + google::protobuf::Timestamp* ts = timestamp.mutable_ts(); + ts->set_seconds(1448249855); + ts->set_nanos(33155000); + + ow_->StartObject("") + ->RenderString("ts", "2015-11-22T19:47:35.033155-07:50") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset1) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+"))); + + ow_->StartObject("")->RenderString("ts", "2016-03-07T15:14:23+")->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset2) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+08-10"))); + + ow_->StartObject("") + ->RenderString("ts", "2016-03-07T15:14:23+08-10") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset3) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+24:10"))); + + ow_->StartObject("") + ->RenderString("ts", "2016-03-07T15:14:23+24:10") + ->EndObject(); + CheckOutput(timestamp); +} + +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, + TimestampWithInvalidOffset4) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "2016-03-07T15:14:23+04:60"))); + + ow_->StartObject("") + ->RenderString("ts", "2016-03-07T15:14:23+04:60") + ->EndObject(); + CheckOutput(timestamp); +} + TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError1) { TimestampDuration timestamp; @@ -937,10 +1060,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError4) { InvalidValue(_, StringPiece("type.googleapis.com/google.protobuf.Timestamp"), StringPiece("Field 'ts', Invalid time format: " - "-8032-10-18T00:00:00.000Z"))); + "-8031-10-18T00:00:00.000Z"))); ow_->StartObject("") - ->RenderString("ts", "-8032-10-18T00:00:00.000Z") + ->RenderString("ts", "-8031-10-18T00:00:00.000Z") ->EndObject(); CheckOutput(timestamp); } @@ -996,6 +1119,22 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError7) { CheckOutput(timestamp); } +TEST_P(ProtoStreamObjectWriterTimestampDurationTest, InvalidTimestampError8) { + TimestampDuration timestamp; + + EXPECT_CALL( + listener_, + InvalidValue(_, + StringPiece("type.googleapis.com/google.protobuf.Timestamp"), + StringPiece("Field 'ts', Invalid time format: " + "0-12-31T23:59:59.000Z"))); + + ow_->StartObject("") + ->RenderString("ts", "0-12-31T23:59:59.000Z") + ->EndObject(); + CheckOutput(timestamp); +} + TEST_P(ProtoStreamObjectWriterTimestampDurationTest, ParseDuration) { TimestampDuration duration; google::protobuf::Duration* dur = duration.mutable_dur(); @@ -1105,7 +1244,10 @@ TEST_P(ProtoStreamObjectWriterTimestampDurationTest, class ProtoStreamObjectWriterStructTest : public BaseProtoStreamObjectWriterTest { protected: - ProtoStreamObjectWriterStructTest() { + ProtoStreamObjectWriterStructTest() { ResetProtoWriter(); } + + // Resets ProtoWriter with current set of options and other state. + void ResetProtoWriter() { vector descriptors; descriptors.push_back(StructType::descriptor()); descriptors.push_back(google::protobuf::Struct::descriptor()); @@ -1201,6 +1343,28 @@ TEST_P(ProtoStreamObjectWriterStructTest, RepeatedStructMapObjectKeyTest) { ->EndObject(); } +TEST_P(ProtoStreamObjectWriterStructTest, OptionStructIntAsStringsTest) { + StructType struct_type; + google::protobuf::Struct* s = struct_type.mutable_object(); + s->mutable_fields()->operator[]("k1").set_number_value(123); + s->mutable_fields()->operator[]("k2").set_bool_value(true); + s->mutable_fields()->operator[]("k3").set_string_value("-222222222"); + s->mutable_fields()->operator[]("k4").set_string_value("33333333"); + + options_.struct_integers_as_strings = true; + ResetProtoWriter(); + + ow_->StartObject("") + ->StartObject("object") + ->RenderDouble("k1", 123) + ->RenderBool("k2", true) + ->RenderInt64("k3", -222222222) + ->RenderUint64("k4", 33333333) + ->EndObject() + ->EndObject(); + CheckOutput(struct_type); +} + class ProtoStreamObjectWriterMapTest : public BaseProtoStreamObjectWriterTest { protected: ProtoStreamObjectWriterMapTest() diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto index 82b81760..101a2bf0 100644 --- a/src/google/protobuf/util/internal/testdata/books.proto +++ b/src/google/protobuf/util/internal/testdata/books.proto @@ -56,6 +56,13 @@ message Book { optional Publisher publisher = 9; repeated Label labels = 10; + enum Type { + FICTION = 1; + KIDS = 2; + ACTION_AND_ADVENTURE = 3; + } + optional Type type = 11; + extensions 200 to 499; } diff --git a/src/google/protobuf/util/internal/type_info_test_helper.cc b/src/google/protobuf/util/internal/type_info_test_helper.cc index 1b9c5154..49e18ed0 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.cc +++ b/src/google/protobuf/util/internal/type_info_test_helper.cc @@ -102,13 +102,13 @@ ProtoStreamObjectSource* TypeInfoTestHelper::NewProtoSource( } ProtoStreamObjectWriter* TypeInfoTestHelper::NewProtoWriter( - const string& type_url, strings::ByteSink* output, - ErrorListener* listener) { + const string& type_url, strings::ByteSink* output, ErrorListener* listener, + const ProtoStreamObjectWriter::Options& options) { const google::protobuf::Type* type = typeinfo_->GetTypeByTypeUrl(type_url); switch (type_) { case USE_TYPE_RESOLVER: { return new ProtoStreamObjectWriter(type_resolver_.get(), *type, output, - listener); + listener, options); } } GOOGLE_LOG(FATAL) << "Can not reach here."; diff --git a/src/google/protobuf/util/internal/type_info_test_helper.h b/src/google/protobuf/util/internal/type_info_test_helper.h index 6916a73b..1a279849 100644 --- a/src/google/protobuf/util/internal/type_info_test_helper.h +++ b/src/google/protobuf/util/internal/type_info_test_helper.h @@ -39,8 +39,8 @@ #include #include -#include #include +#include #include #include #include @@ -77,9 +77,9 @@ class TypeInfoTestHelper { ProtoStreamObjectSource* NewProtoSource(io::CodedInputStream* coded_input, const string& type_url); - ProtoStreamObjectWriter* NewProtoWriter(const string& type_url, - strings::ByteSink* output, - ErrorListener* listener); + ProtoStreamObjectWriter* NewProtoWriter( + const string& type_url, strings::ByteSink* output, + ErrorListener* listener, const ProtoStreamObjectWriter::Options& options); DefaultValueObjectWriter* NewDefaultValueWriter(const string& type_url, ObjectWriter* writer); diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc index 1ddf2487..ee7a51fc 100644 --- a/src/google/protobuf/util/internal/utility.cc +++ b/src/google/protobuf/util/internal/utility.cc @@ -222,6 +222,7 @@ string ToCamelCase(const StringPiece input) { if (!result.empty() && is_cap && (!was_cap || (i + 1 < input.size() && ascii_islower(input[i + 1])))) { first_word = false; + result.push_back(input[i]); } else { result.push_back(ascii_tolower(input[i])); continue; @@ -231,9 +232,13 @@ string ToCamelCase(const StringPiece input) { if (ascii_islower(input[i])) { result.push_back(ascii_toupper(input[i])); continue; + } else { + result.push_back(input[i]); + continue; } + } else { + result.push_back(ascii_tolower(input[i])); } - result.push_back(input[i]); } return result; } diff --git a/src/google/protobuf/util/json_util.cc b/src/google/protobuf/util/json_util.cc index c3b8d502..2659320a 100644 --- a/src/google/protobuf/util/json_util.cc +++ b/src/google/protobuf/util/json_util.cc @@ -102,6 +102,42 @@ util::Status BinaryToJsonString(TypeResolver* resolver, options); } +namespace { +class StatusErrorListener : public converter::ErrorListener { + public: + StatusErrorListener() : status_(util::Status::OK) {} + virtual ~StatusErrorListener() {} + + util::Status GetStatus() { return status_; } + + virtual void InvalidName(const converter::LocationTrackerInterface& loc, + StringPiece unknown_name, StringPiece message) { + status_ = util::Status(util::error::INVALID_ARGUMENT, + loc.ToString() + ": " + message.ToString()); + } + + virtual void InvalidValue(const converter::LocationTrackerInterface& loc, + StringPiece type_name, StringPiece value) { + status_ = + util::Status(util::error::INVALID_ARGUMENT, + loc.ToString() + ": invalid value " + value.ToString() + + " for type " + type_name.ToString()); + } + + virtual void MissingField(const converter::LocationTrackerInterface& loc, + StringPiece missing_name) { + status_ = util::Status( + util::error::INVALID_ARGUMENT, + loc.ToString() + ": missing field " + missing_name.ToString()); + } + + private: + util::Status status_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StatusErrorListener); +}; +} // namespace + util::Status JsonToBinaryStream(TypeResolver* resolver, const string& type_url, io::ZeroCopyInputStream* json_input, @@ -109,7 +145,7 @@ util::Status JsonToBinaryStream(TypeResolver* resolver, google::protobuf::Type type; RETURN_IF_ERROR(resolver->ResolveMessageType(type_url, &type)); internal::ZeroCopyStreamByteSink sink(binary_output); - converter::NoopErrorListener listener; + StatusErrorListener listener; converter::ProtoStreamObjectWriter proto_writer(resolver, type, &sink, &listener); @@ -123,7 +159,7 @@ util::Status JsonToBinaryStream(TypeResolver* resolver, } RETURN_IF_ERROR(parser.FinishParse()); - return util::Status::OK; + return listener.GetStatus(); } util::Status JsonToBinaryString(TypeResolver* resolver, diff --git a/src/google/protobuf/util/json_util_test.cc b/src/google/protobuf/util/json_util_test.cc index da68495f..a4d3cc98 100644 --- a/src/google/protobuf/util/json_util_test.cc +++ b/src/google/protobuf/util/json_util_test.cc @@ -77,8 +77,11 @@ class JsonUtilTest : public testing::Test { bool FromJson(const string& json, Message* message) { string binary; - GOOGLE_CHECK_OK(JsonToBinaryString( - resolver_.get(), GetTypeUrl(message->GetDescriptor()), json, &binary)); + if (!JsonToBinaryString(resolver_.get(), + GetTypeUrl(message->GetDescriptor()), json, &binary) + .ok()) { + return false; + } return message->ParseFromString(binary); } @@ -99,28 +102,36 @@ TEST_F(JsonUtilTest, TestWhitespaces) { ToJson(m, options)); } -// TODO(skarvaje): Uncomment after cl/96232915 is submitted. -// TEST_F(JsonUtilTest, TestDefaultValues) { - // TestMessage m; - // JsonOptions options; - // EXPECT_EQ("{}", ToJson(m, options)); - // options.always_print_primitive_fields = true; - // EXPECT_EQ( - // "{\"boolValue\":false," - // "\"int32Value\":0," - // "\"int64Value\":\"0\"," - // "\"uint32Value\":0," - // "\"uint64Value\":\"0\"," - // "\"floatValue\":0," - // "\"doubleValue\":0," - // "\"stringValue\":\"\"," - // "\"bytesValue\":\"\"," - // // TODO(xiaofeng): The default enum value should be FOO. I believe - // // this is a bug in DefaultValueObjectWriter. - // "\"enumValue\":null" - // "}", - // ToJson(m, options)); -// } +TEST_F(JsonUtilTest, TestDefaultValues) { + TestMessage m; + JsonOptions options; + EXPECT_EQ("{}", ToJson(m, options)); + options.always_print_primitive_fields = true; + EXPECT_EQ( + "{\"boolValue\":false," + "\"int32Value\":0," + "\"int64Value\":\"0\"," + "\"uint32Value\":0," + "\"uint64Value\":\"0\"," + "\"floatValue\":0," + "\"doubleValue\":0," + "\"stringValue\":\"\"," + "\"bytesValue\":\"\"," + "\"enumValue\":\"FOO\"," + "\"repeatedBoolValue\":[]," + "\"repeatedInt32Value\":[]," + "\"repeatedInt64Value\":[]," + "\"repeatedUint32Value\":[]," + "\"repeatedUint64Value\":[]," + "\"repeatedFloatValue\":[]," + "\"repeatedDoubleValue\":[]," + "\"repeatedStringValue\":[]," + "\"repeatedBytesValue\":[]," + "\"repeatedEnumValue\":[]," + "\"repeatedMessageValue\":[]" + "}", + ToJson(m, options)); +} TEST_F(JsonUtilTest, ParseMessage) { // Some random message but good enough to verify that the parsing warpper @@ -158,6 +169,15 @@ TEST_F(JsonUtilTest, ParseMap) { EXPECT_EQ(message.DebugString(), other.DebugString()); } +TEST_F(JsonUtilTest, TestParseErrors) { + TestMessage m; + JsonOptions options; + // Parsing should fail if the field name can not be recognized. + EXPECT_FALSE(FromJson("{\"unknownName\":0}", &m)); + // Parsing should fail if the value is invalid. + EXPECT_FALSE(FromJson("{\"int32Value\":2147483648}", &m)); +} + typedef pair Segment; // A ZeroCopyOutputStream that writes to multiple buffers. class SegmentedZeroCopyOutputStream : public io::ZeroCopyOutputStream { diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index 0f879dc7..b2b3242a 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -1021,7 +1022,7 @@ bool MessageDifferencer::UnpackAny(const Message& any, any.GetDescriptor()->file()->pool()->FindMessageTypeByName( full_type_name); if (desc == NULL) { - GOOGLE_LOG(ERROR) << "Proto type '" << full_type_name << "' not found"; + GOOGLE_DLOG(ERROR) << "Proto type '" << full_type_name << "' not found"; return false; } @@ -1031,7 +1032,7 @@ bool MessageDifferencer::UnpackAny(const Message& any, data->reset(dynamic_message_factory_->GetPrototype(desc)->New()); string serialized_value = reflection->GetString(any, value_field); if (!(*data)->ParseFromString(serialized_value)) { - GOOGLE_LOG(ERROR) << "Failed to parse value for " << full_type_name; + GOOGLE_DLOG(ERROR) << "Failed to parse value for " << full_type_name; return false; } return true; diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 7f1093c8..f2517074 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -412,7 +412,7 @@ void WireFormatLite::WriteString(int field_number, const string& value, io::CodedOutputStream* output) { // String is for UTF-8 text only WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteString(value); } @@ -421,14 +421,14 @@ void WireFormatLite::WriteStringMaybeAliased( io::CodedOutputStream* output) { // String is for UTF-8 text only WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteRawMaybeAliased(value.data(), value.size()); } void WireFormatLite::WriteBytes(int field_number, const string& value, io::CodedOutputStream* output) { WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteString(value); } @@ -436,7 +436,7 @@ void WireFormatLite::WriteBytesMaybeAliased( int field_number, const string& value, io::CodedOutputStream* output) { WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - GOOGLE_CHECK(value.size() <= kint32max); + GOOGLE_CHECK_LE(value.size(), kint32max); output->WriteVarint32(value.size()); output->WriteRawMaybeAliased(value.data(), value.size()); } diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index 79493ca0..7bce21cf 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -274,8 +274,8 @@ inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive( // The number of bytes each type occupies on the wire. const int per_value_size = tag_size + sizeof(value); - int elements_available = min(values->Capacity() - values->size(), - size / per_value_size); + int elements_available = + std::min(values->Capacity() - values->size(), size / per_value_size); int num_read = 0; while (num_read < elements_available && (buffer = io::CodedInputStream::ExpectTagFromArray( @@ -367,7 +367,7 @@ inline bool WireFormatLite::ReadPackedFixedSizePrimitive( bytes_limit = input->BytesUntilLimit(); } else { bytes_limit = - min(bytes_limit, static_cast(input->BytesUntilLimit())); + std::min(bytes_limit, static_cast(input->BytesUntilLimit())); } if (bytes_limit >= new_bytes) { // Fast-path that pre-allocates *values to the final size. diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 15c37556..4e4add66 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -45,6 +45,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index 212dd219..204c8029 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -263,10 +263,11 @@ void protobuf_AddDesc_google_2fprotobuf_2fwrappers_2eproto() { "e\030\001 \001(\004\"\033\n\nInt32Value\022\r\n\005value\030\001 \001(\005\"\034\n\013" "UInt32Value\022\r\n\005value\030\001 \001(\r\"\032\n\tBoolValue\022" "\r\n\005value\030\001 \001(\010\"\034\n\013StringValue\022\r\n\005value\030\001" - " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014BS\n\023com" - ".google.protobufB\rWrappersProtoP\001\240\001\001\370\001\001\242" - "\002\003GPB\252\002\036Google.Protobuf.WellKnownTypesb\006" - "proto3", 406); + " \001(\t\"\033\n\nBytesValue\022\r\n\005value\030\001 \001(\014B\177\n\023com" + ".google.protobufB\rWrappersProtoP\001Z*githu" + "b.com/golang/protobuf/ptypes/wrappers\240\001\001" + "\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTyp" + "esb\006proto3", 450); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/wrappers.proto", &protobuf_RegisterTypes); DoubleValue::default_instance_ = new DoubleValue(); diff --git a/src/google/protobuf/wrappers.proto b/src/google/protobuf/wrappers.proto index 040d8a24..4828ad9a 100644 --- a/src/google/protobuf/wrappers.proto +++ b/src/google/protobuf/wrappers.proto @@ -39,6 +39,7 @@ package google.protobuf; option csharp_namespace = "Google.Protobuf.WellKnownTypes"; option cc_enable_arenas = true; +option go_package = "github.com/golang/protobuf/ptypes/wrappers"; option java_package = "com.google.protobuf"; option java_outer_classname = "WrappersProto"; option java_multiple_files = true; From 955841e620e2a70532c9ba6312e41676f1c92e6c Mon Sep 17 00:00:00 2001 From: Adam Michalik Date: Wed, 30 Mar 2016 12:54:40 -0700 Subject: [PATCH 036/123] Replace #include with #include iostream is not actually necessary here, and it introduces unnecessary static initializers. --- src/google/protobuf/stubs/int128.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/google/protobuf/stubs/int128.cc b/src/google/protobuf/stubs/int128.cc index d80c64f2..3a36b4b1 100644 --- a/src/google/protobuf/stubs/int128.cc +++ b/src/google/protobuf/stubs/int128.cc @@ -31,7 +31,7 @@ #include #include -#include // NOLINT(readability/streams) +#include // NOLINT(readability/streams) #include namespace google { From ca0461c1863bff4f9d33dcd352c66dc12d969560 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 31 Mar 2016 07:12:17 +0100 Subject: [PATCH 037/123] Introduce a new nuget package, Google.Protobuf.Tools, basically to contain protoc on multiple platforms. I've moved both protoc.exe and the proto files out of Google.Protobuf. The .proto files aren't a slam-dunk, but it feels like they belong with protoc as you'd *use* them with protoc. It's not clear to me whether we really need both an x86 and x64 version of protoc.exe, as x86 would work on 64-bit Windows anyway. Discuss :) --- csharp/Google.Protobuf.Tools.nuspec | 38 +++++++++++++++++++ .../Google.Protobuf/Google.Protobuf.nuspec | 14 ------- 2 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 csharp/Google.Protobuf.Tools.nuspec diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec new file mode 100644 index 00000000..4b008b6f --- /dev/null +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -0,0 +1,38 @@ + + + + Google.Protobuf.Tools + Google Protocol Buffers tools +

Tools for Protocol Buffers - Google's data interchange format. + See project site for more info. + 3.0.0-beta2 + Google Inc. + protobuf-packages + https://github.com/google/protobuf/blob/master/LICENSE + https://github.com/google/protobuf + false + Tools for Protocol Buffers + Copyright 2015, Google Inc. + Protocol Buffers Binary Serialization Format Google proto proto3 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec index d5302544..f51bc89a 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec +++ b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec @@ -23,7 +23,6 @@ - @@ -49,18 +48,5 @@ - - - - - - - - - - - - - \ No newline at end of file From dfd47600d1d197024a5c346a88cc3bfc52218c94 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Thu, 31 Mar 2016 10:46:55 +0100 Subject: [PATCH 038/123] Remove duplicate line --- csharp/Google.Protobuf.Tools.nuspec | 1 - 1 file changed, 1 deletion(-) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 4b008b6f..2b66b081 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -31,7 +31,6 @@ - From 9e7fa0678dca7b5f8f089b9aff80168e9c200258 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 13:17:45 -0700 Subject: [PATCH 039/123] Temporarily disable begin is fast test. --- src/google/protobuf/map_test.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 1f3de4fa..cda713f0 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -303,7 +303,8 @@ static int64 Now() { // if one erases elements at the "front" of the hash map, and we'd like to // avoid that, as std::unordered_map does. TEST_P(MapImplTest, BeginIsFast) { - if (GetParam()) return; + // Disable this test for both new and old implementations. + if (/*GetParam()*/true) return; Map map(false); // This test uses new-style maps only. const int kTestSize = 250000; for (int i = 0; i < kTestSize; i++) { From 94aa50ffd6e8994c1ec9c09cc596ec77692e6be7 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 13:18:03 -0700 Subject: [PATCH 040/123] Fix breakage of referring to table_ in static func Referencing data member table_ in static functions break certain platforms. Change it to refer to the declare type void** instead. --- src/google/protobuf/map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index b5f34042..3ee4ea76 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -935,7 +935,7 @@ class Map { const hasher& hash_function() const { return *this; } static size_type max_size() { - return static_cast(1) << (sizeof(table_) >= 8 ? 60 : 28); + return static_cast(1) << (sizeof(void**) >= 8 ? 60 : 28); } size_type size() const { return num_elements_; } bool empty() const { return size() == 0; } From fc7eeda69c970a1f893acc17c69ed2def1611c25 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 13:36:32 -0700 Subject: [PATCH 041/123] Fix json_format.py in py26 --- python/google/protobuf/json_format.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py index 4342755a..7921556e 100644 --- a/python/google/protobuf/json_format.py +++ b/python/google/protobuf/json_format.py @@ -271,8 +271,10 @@ def _ListValueMessageToJsonObject(message, unused_including_default=False): def _StructMessageToJsonObject(message, unused_including_default=False): """Converts Struct message according to Proto3 JSON Specification.""" fields = message.fields - return {key: _ValueMessageToJsonObject(fields[key]) - for key in fields} + ret = {} + for key in fields: + ret[key] = _ValueMessageToJsonObject(fields[key]) + return ret def _IsWrapperMessage(message_descriptor): From 5805c2dfb78a3cb38d297d3f102649cc1b7a6310 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 13:50:38 -0700 Subject: [PATCH 042/123] Fix javanano package --- src/google/protobuf/compiler/javanano/javanano_generator.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc index a342e6bb..7c3a0421 100644 --- a/src/google/protobuf/compiler/javanano/javanano_generator.cc +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -68,6 +68,9 @@ void UpdateParamsRecursively(Params& params, } if (file->options().has_java_package()) { string result = file->options().java_package(); + if (!result.empty()) { + result += "."; + } result += "nano"; params.set_java_package( file->name(), result); From 1283625b0f0b395a59d6d72b06bc7a62479b2d26 Mon Sep 17 00:00:00 2001 From: Manjunath Kudlur Date: Thu, 31 Mar 2016 09:53:00 -0700 Subject: [PATCH 043/123] Added an API to allow oversize protos when using C++ extension in Python --- .../google/protobuf/internal/message_test.py | 59 +++++++++++++++++++ python/google/protobuf/pyext/message.cc | 46 +++++++++++---- 2 files changed, 94 insertions(+), 11 deletions(-) diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py index d03f2d25..ee6b944a 100755 --- a/python/google/protobuf/internal/message_test.py +++ b/python/google/protobuf/internal/message_test.py @@ -57,7 +57,11 @@ try: except ImportError: import unittest from google.protobuf.internal import _parameterized +from google.protobuf import descriptor_pb2 +from google.protobuf import descriptor_pool from google.protobuf import map_unittest_pb2 +from google.protobuf import message_factory +from google.protobuf import text_format from google.protobuf import unittest_pb2 from google.protobuf import unittest_proto3_arena_pb2 from google.protobuf.internal import any_test_pb2 @@ -1776,5 +1780,60 @@ class PackedFieldTest(unittest.TestCase): b'\x70\x01') self.assertEqual(golden_data, message.SerializeToString()) + +@unittest.skipIf(api_implementation.Type() != 'cpp', + 'explicit tests of the C++ implementation') +class OversizeProtosTest(unittest.TestCase): + + def setUp(self): + self.file_desc = """ + name: "f/f.msg2" + package: "f" + message_type { + name: "msg1" + field { + name: "payload" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_STRING + } + } + message_type { + name: "msg2" + field { + name: "field" + number: 1 + label: LABEL_OPTIONAL + type: TYPE_MESSAGE + type_name: "msg1" + } + } + """ + pool = descriptor_pool.DescriptorPool() + desc = descriptor_pb2.FileDescriptorProto() + text_format.Parse(self.file_desc, desc) + pool.Add(desc) + self.proto_cls = message_factory.MessageFactory(pool).GetPrototype( + pool.FindMessageTypeByName('f.msg2')) + self.p = self.proto_cls() + self.p.field.payload = 'c' * (1024 * 1024 * 64 + 1) + self.p_serialized = self.p.SerializeToString() + + def testAssertOversizeProto(self): + from google.protobuf.pyext._message import SetAllowOversizeProtos + SetAllowOversizeProtos(False) + q = self.proto_cls() + try: + q.ParseFromString(self.p_serialized) + except message.DecodeError as e: + self.assertEqual(str(e), 'Error parsing message') + + def testSucceedOversizeProto(self): + from google.protobuf.pyext._message import SetAllowOversizeProtos + SetAllowOversizeProtos(True) + q = self.proto_cls() + q.ParseFromString(self.p_serialized) + self.assertEqual(self.p.field.payload, q.field.payload) + if __name__ == '__main__': unittest.main() diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 60ec9c1b..7d3e8c37 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -1911,6 +1911,30 @@ static PyObject* CopyFrom(CMessage* self, PyObject* arg) { Py_RETURN_NONE; } +// Protobuf has a 64MB limit built in, this variable will override this. Please +// do not enable this unless you fully understand the implications: protobufs +// must all be kept in memory at the same time, so if they grow too big you may +// get OOM errors. The protobuf APIs do not provide any tools for processing +// protobufs in chunks. If you have protos this big you should break them up if +// it is at all convenient to do so. +static bool allow_oversize_protos = false; + +// Provide a method in the module to set allow_oversize_protos to a boolean +// value. This method returns the newly value of allow_oversize_protos. +static PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) { + if (!arg || !PyBool_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "Argument to SetAllowOversizeProtos must be boolean"); + return NULL; + } + allow_oversize_protos = PyObject_IsTrue(arg); + if (allow_oversize_protos) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + static PyObject* MergeFromString(CMessage* self, PyObject* arg) { const void* data; Py_ssize_t data_length; @@ -1921,15 +1945,9 @@ static PyObject* MergeFromString(CMessage* self, PyObject* arg) { AssureWritable(self); io::CodedInputStream input( reinterpret_cast(data), data_length); -#if PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS - // Protobuf has a 64MB limit built in, this code will override this. Please do - // not enable this unless you fully understand the implications: protobufs - // must all be kept in memory at the same time, so if they grow too big you - // may get OOM errors. The protobuf APIs do not provide any tools for - // processing protobufs in chunks. If you have protos this big you should - // break them up if it is at all convenient to do so. - input.SetTotalBytesLimit(INT_MAX, INT_MAX); -#endif // PROTOBUF_PYTHON_ALLOW_OVERSIZE_PROTOS + if (allow_oversize_protos) { + input.SetTotalBytesLimit(INT_MAX, INT_MAX); + } PyDescriptorPool* pool = GetDescriptorPoolForMessage(self); input.SetExtensionRegistry(pool->pool, pool->message_factory); bool success = self->message->MergePartialFromCodedStream(&input); @@ -3046,6 +3064,11 @@ bool InitProto2MessageModule(PyObject *m) { } // namespace python } // namespace protobuf +static PyMethodDef ModuleMethods[] = { + {"SetAllowOversizeProtos", + (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos, + METH_O, "Enable/disable oversize proto parsing."}, +}; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef _module = { @@ -3053,7 +3076,7 @@ static struct PyModuleDef _module = { "_message", google::protobuf::python::module_docstring, -1, - NULL, + ModuleMethods, /* m_methods */ NULL, NULL, NULL, @@ -3072,7 +3095,8 @@ extern "C" { #if PY_MAJOR_VERSION >= 3 m = PyModule_Create(&_module); #else - m = Py_InitModule3("_message", NULL, google::protobuf::python::module_docstring); + m = Py_InitModule3("_message", ModuleMethods, + google::protobuf::python::module_docstring); #endif if (m == NULL) { return INITFUNC_ERRORVAL; From cbfd9d43c829c412fe53cf003c78f51c8a307240 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 14:47:24 -0700 Subject: [PATCH 044/123] Remove export macros for classes nested in a template class. --- src/google/protobuf/map.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 3ee4ea76..023ed971 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -663,7 +663,7 @@ class Map { // custom class here and for Node, below, to ensure that k_ is at offset 0, // allowing safe conversion from pointer to Node to pointer to Key, and vice // versa when appropriate. - class LIBPROTOBUF_EXPORT KeyValuePair { + class KeyValuePair { public: KeyValuePair(const Key& k, value_type* v) : k_(k), v_(v) {} @@ -708,7 +708,7 @@ class Map { // 8. Mutations to a map do not invalidate the map's iterators, pointers to // elements, or references to elements. // 9. Except for erase(iterator), any non-const method can reorder iterators. - class LIBPROTOBUF_EXPORT InnerMap : private hasher { + class InnerMap : private hasher { public: typedef value_type* Value; @@ -1340,7 +1340,7 @@ class Map { public: // Iterators - class LIBPROTOBUF_EXPORT iterator_base { + class iterator_base { public: // We support "old style" and "new style" iterators for now. This is // temporary. Also, for "iterator()" we have an unknown category. From bc1f2e7e6e416aa3428817dd3e43e531e81b399d Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 15:17:40 -0700 Subject: [PATCH 045/123] Fix WIN32 build for map_test. stubs/common.h undefines the GetMessage macro introduced in windows.h map_test however include stubs/common.h before windows.h is transitively included. This hack force map_test.cc to include windows.h first, so we have a chance to undefine the GetMessage macro. --- src/google/protobuf/map_test.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index cda713f0..cfb3d001 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -28,6 +28,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// A hack to include windows.h first, which ensures the GetMessage macro can +// be undefined when we include +#if defined(_WIN32) +#include +#endif // _WIN32 + #include #include #include From 012ac9a0a6d025d3fd874414e8646ead0812aa7a Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 15:26:22 -0700 Subject: [PATCH 046/123] revert unexpected change for py26 --- python/google/protobuf/internal/proto_builder_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/google/protobuf/internal/proto_builder_test.py b/python/google/protobuf/internal/proto_builder_test.py index 880b570d..822ad895 100644 --- a/python/google/protobuf/internal/proto_builder_test.py +++ b/python/google/protobuf/internal/proto_builder_test.py @@ -36,7 +36,10 @@ try: from collections import OrderedDict except ImportError: from ordereddict import OrderedDict #PY26 -import unittest +try: + import unittest2 as unittest +except ImportError: + import unittest from google.protobuf import descriptor_pb2 from google.protobuf import descriptor_pool from google.protobuf import proto_builder From 7b1cbbd50ee1a750fdf6383dfd95216bc70a86bf Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 15:38:10 -0700 Subject: [PATCH 047/123] Fix signed-compare warning. --- python/google/protobuf/pyext/message.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index a8248888..df043818 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -2140,7 +2140,7 @@ static PyObject* ListFields(CMessage* self) { PyList_SET_ITEM(all_fields.get(), actual_size, t.release()); ++actual_size; } - if (actual_size != fields.size() && + if (static_cast(actual_size) != fields.size() && (PyList_SetSlice(all_fields.get(), actual_size, fields.size(), NULL) < 0)) { return NULL; From 1bf446c71e2f3c71e70ece2b97e8975084bf521b Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 15:48:25 -0700 Subject: [PATCH 048/123] Disable sign-compare warning. --- python/setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/setup.py b/python/setup.py index 6ea3bad7..5e146161 100755 --- a/python/setup.py +++ b/python/setup.py @@ -163,7 +163,9 @@ if __name__ == '__main__': warnings_as_errors = '--warnings_as_errors' if cpp_impl in sys.argv: sys.argv.remove(cpp_impl) - extra_compile_args = ['-Wno-write-strings', '-Wno-invalid-offsetof'] + extra_compile_args = ['-Wno-write-strings', + '-Wno-invalid-offsetof', + '-Wno-sign-compare'] test_conformance.target = 'test_python_cpp' if "clang" in os.popen('$CC --version 2> /dev/null').read(): From 203bb5eb33fca8d848c18e62a83d97b22bb08a79 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 31 Mar 2016 17:38:11 -0700 Subject: [PATCH 049/123] Fix re-definition issue of winsock.h and winsock2.h --- src/google/protobuf/map_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index cfb3d001..195971b5 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -31,6 +31,7 @@ // A hack to include windows.h first, which ensures the GetMessage macro can // be undefined when we include #if defined(_WIN32) +#define _WINSOCKAPI_ // to avoid re-definition in WinSock2.h #include #endif // _WIN32 From 46e088e2b6ec4af99065fd9407c7b767cd3da0a9 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Fri, 1 Apr 2016 17:17:49 +0100 Subject: [PATCH 050/123] Remove duplicate test cases. (NCrunch noticed these.) --- csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs | 1 - csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs index 42455043..344d727b 100644 --- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs @@ -321,7 +321,6 @@ namespace Google.Protobuf [TestCase("1970-01-01T00:00:00.001Z", 1000000)] [TestCase("1970-01-01T00:00:00.010Z", 10000000)] [TestCase("1970-01-01T00:00:00.100Z", 100000000)] - [TestCase("1970-01-01T00:00:00.100Z", 100000000)] [TestCase("1970-01-01T00:00:00.120Z", 120000000)] [TestCase("1970-01-01T00:00:00.123Z", 123000000)] [TestCase("1970-01-01T00:00:00.123400Z", 123400000)] diff --git a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs index a0a62227..527ab336 100644 --- a/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonTokenizerTest.cs @@ -249,7 +249,6 @@ namespace Google.Protobuf [TestCase("[,", 1)] [TestCase("{", 1)] [TestCase("{,", 1)] - [TestCase("{", 1)] [TestCase("{[", 1)] [TestCase("{{", 1)] [TestCase("{0", 1)] From 331cee502296b382ae42b499e2daab59488f91f8 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 1 Apr 2016 12:26:15 -0400 Subject: [PATCH 051/123] Add -position and -isAtEnd for use when manually parsing input streams. --- objectivec/GPBCodedInputStream.h | 9 +++++++++ objectivec/GPBCodedInputStream.m | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/objectivec/GPBCodedInputStream.h b/objectivec/GPBCodedInputStream.h index 06198883..d64b64e3 100644 --- a/objectivec/GPBCodedInputStream.h +++ b/objectivec/GPBCodedInputStream.h @@ -109,6 +109,15 @@ NS_ASSUME_NONNULL_BEGIN /// or until an endgroup tag, whichever comes first. - (void)skipMessage; +/// Check to see if the logical end of the stream has been reached. +/// +/// This can return NO when there is no more data, but the current parsing +/// expected more data. +- (BOOL)isAtEnd; + +/// The offset into the stream. +- (size_t)position; + /// Verifies that the last call to @c -readTag returned the given tag value. /// This is used to verify that a nested group ended with the correct end tag. /// Throws @c NSParseErrorException if value does not match the last tag. diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m index fd877838..eaa28e50 100644 --- a/objectivec/GPBCodedInputStream.m +++ b/objectivec/GPBCodedInputStream.m @@ -359,6 +359,14 @@ void GPBCodedInputStreamCheckLastTagWas(GPBCodedInputStreamState *state, } } +- (BOOL)isAtEnd { + return GPBCodedInputStreamIsAtEnd(&state_); +} + +- (size_t)position { + return state_.bufferPos; +} + - (double)readDouble { return GPBCodedInputStreamReadDouble(&state_); } From 3b6df0612d10bfeb90914fe5c13840f3968ba76a Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 1 Apr 2016 15:02:45 -0700 Subject: [PATCH 052/123] Allow bigobj for map_unittest --- cmake/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 15ae457a..f32a0e4e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -118,6 +118,8 @@ if (MSVC) # Build with multiple processes add_definitions(/MP) add_definitions(/wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305) + # Allow big object + add_definitions(/bigobj) string(REPLACE "/" "\\" PROTOBUF_SOURCE_WIN32_PATH ${protobuf_SOURCE_DIR}) string(REPLACE "/" "\\" PROTOBUF_BINARY_WIN32_PATH ${protobuf_BINARY_DIR}) configure_file(extract_includes.bat.in extract_includes.bat) From 93811ca9f78115a0fd59b3efa047fd8abf5ff602 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 1 Apr 2016 15:55:49 -0700 Subject: [PATCH 053/123] Do not let windows.h define min/max macros --- src/google/protobuf/map_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 195971b5..e833699a 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -32,6 +32,7 @@ // be undefined when we include #if defined(_WIN32) #define _WINSOCKAPI_ // to avoid re-definition in WinSock2.h +#define NOMINMAX // to avoid defining min/max macros #include #endif // _WIN32 From cf828deb9b5537c294e4a5628ef04fdbdfdcbb28 Mon Sep 17 00:00:00 2001 From: Manjunath Kudlur Date: Fri, 25 Mar 2016 10:58:46 -0700 Subject: [PATCH 054/123] Linking the cpp implementation extension statically with libprotobuf --- python/README.md | 12 ++---------- python/setup.py | 35 ++++++++++++++++++++++++++++------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/python/README.md b/python/README.md index 1b5b9dff..57acfd94 100644 --- a/python/README.md +++ b/python/README.md @@ -123,13 +123,5 @@ 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: -1) Install the C++ protobuf runtime library, please see instructions in the - parent directory. -2) Export an environment variable: - - $ export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=cpp - -You must set this variable at runtime, before running your program, otherwise -the pure-Python implementation will be used. In a future release, we will -change the default so that C++ implementation is used whenever it is available. +To use the C++ implementation, you need to install the C++ protobuf runtime +library, please see instructions in the parent directory. diff --git a/python/setup.py b/python/setup.py index 6ea3bad7..f5c00a72 100755 --- a/python/setup.py +++ b/python/setup.py @@ -157,13 +157,28 @@ class test_conformance(_build_py): status = subprocess.check_call(cmd, shell=True) +def get_option_from_sys_argv(option_str): + if option_str in sys.argv: + sys.argv.remove(option_str) + return True + return False + + if __name__ == '__main__': ext_module_list = [] - cpp_impl = '--cpp_implementation' warnings_as_errors = '--warnings_as_errors' - if cpp_impl in sys.argv: - sys.argv.remove(cpp_impl) + if get_option_from_sys_argv('--cpp_implementation'): + # Link libprotobuf.a and libprotobuf-lite.a statically with the + # extension. Note that those libraries have to be compiled with + # -fPIC for this to work. + compile_static_ext = get_option_from_sys_argv('--compile_static_extension') extra_compile_args = ['-Wno-write-strings', '-Wno-invalid-offsetof'] + libraries = ['protobuf'] + extra_objects = None + if compile_static_ext: + libraries = None + extra_objects = ['../src/.libs/libprotobuf.a', + '../src/.libs/libprotobuf-lite.a'] test_conformance.target = 'test_python_cpp' if "clang" in os.popen('$CC --version 2> /dev/null').read(): @@ -174,16 +189,22 @@ if __name__ == '__main__': sys.argv.remove(warnings_as_errors) # C++ implementation extension - ext_module_list.append( + ext_module_list.extend([ Extension( "google.protobuf.pyext._message", glob.glob('google/protobuf/pyext/*.cc'), include_dirs=[".", "../src"], - libraries=['protobuf'], + libraries=libraries, + extra_objects=extra_objects, library_dirs=['../src/.libs'], extra_compile_args=extra_compile_args, - ) - ) + ), + Extension( + "google.protobuf.internal._api_implementation", + glob.glob('google/protobuf/internal/api_implementation.cc'), + extra_compile_args=['-DPYTHON_PROTO2_CPP_IMPL_V2'], + ), + ]) os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'cpp' # Keep this list of dependencies in sync with tox.ini. From 89343d87c6a335be561fd17c8e40c72901d2f152 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 1 Apr 2016 16:44:46 -0700 Subject: [PATCH 055/123] Do not use C++11 unicode escape in unittest. For fixing MSVC --- src/google/protobuf/util/internal/json_stream_parser_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/google/protobuf/util/internal/json_stream_parser_test.cc b/src/google/protobuf/util/internal/json_stream_parser_test.cc index 4b691107..059ea6d8 100644 --- a/src/google/protobuf/util/internal/json_stream_parser_test.cc +++ b/src/google/protobuf/util/internal/json_stream_parser_test.cc @@ -392,7 +392,7 @@ TEST_F(JsonStreamParserTest, UnicodeEscaping) { // - unicode UTF-16 surrogate pair handling in strings TEST_F(JsonStreamParserTest, UnicodeSurrogatePairEscaping) { StringPiece str = - "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\U0001F36F\"]"; + "[\"\\u0bee\\ud800\\uddf1\\uD80C\\uDDA4\\uD83d\\udC1D\\uD83C\\uDF6F\"]"; for (int i = 0; i <= str.length(); ++i) { ow_.StartList("") ->RenderString("", From 268ce2818f11f50f93020f53c2322d45d966e85d Mon Sep 17 00:00:00 2001 From: Oleg Vereshko Date: Fri, 1 Apr 2016 14:01:17 +0300 Subject: [PATCH 056/123] Added deprecated option handling for objective-c generator --- .../compiler/objectivec/objectivec_enum.cc | 6 ++++-- .../compiler/objectivec/objectivec_field.cc | 17 +++++++++-------- .../compiler/objectivec/objectivec_file.cc | 10 ++++++++++ .../compiler/objectivec/objectivec_helpers.h | 16 ++++++++++++++++ .../compiler/objectivec/objectivec_message.cc | 3 ++- 5 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc index 3f81dcb8..e76f8e99 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_enum.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_enum.cc @@ -72,8 +72,9 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { "\n", "name", name_); - printer->Print("$comments$typedef GPB_ENUM($name$) {\n", + printer->Print("$comments$typedef$deprecated_attribute$ GPB_ENUM($name$) {\n", "comments", enum_comments, + "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_), "name", name_); printer->Indent(); @@ -99,8 +100,9 @@ void EnumGenerator::GenerateHeader(io::Printer* printer) { } printer->Print( - "$name$ = $value$,\n", + "$name$$deprecated_attribute$ = $value$,\n", "name", EnumValueName(all_values_[i]), + "deprecated_attribute", GetOptionalDeprecatedAttribute(all_values_[i]), "value", SimpleItoa(all_values_[i]->number())); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_field.cc b/src/google/protobuf/compiler/objectivec/objectivec_field.cc index 7bb9837d..66cb4a16 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_field.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_field.cc @@ -78,6 +78,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, classname + "_FieldNumber_" + capitalized_name; (*variables)["field_number"] = SimpleItoa(descriptor->number()); (*variables)["field_type"] = GetCapitalizedType(descriptor); + (*variables)["deprecated_attribute"] = GetOptionalDeprecatedAttribute(descriptor); std::vector field_flags; if (descriptor->is_repeated()) field_flags.push_back("GPBFieldRepeated"); if (descriptor->is_required()) field_flags.push_back("GPBFieldRequired"); @@ -266,12 +267,12 @@ void SingleFieldGenerator::GeneratePropertyDeclaration( printer->Print(variables_, "$comments$"); printer->Print( variables_, - "@property(nonatomic, readwrite) $property_type$ $name$;\n" + "@property(nonatomic, readwrite) $property_type$ $name$$deprecated_attribute$;\n" "\n"); if (WantsHasProperty()) { printer->Print( variables_, - "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); + "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); } } @@ -330,18 +331,18 @@ void ObjCObjFieldGenerator::GeneratePropertyDeclaration( printer->Print(variables_, "$comments$"); printer->Print( variables_, - "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$;\n"); + "@property(nonatomic, readwrite, $property_storage_attribute$, null_resettable) $property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n"); if (WantsHasProperty()) { printer->Print( variables_, "/// Test to see if @c $name$ has been set.\n" - "@property(nonatomic, readwrite) BOOL has$capitalized_name$;\n"); + "@property(nonatomic, readwrite) BOOL has$capitalized_name$$deprecated_attribute$;\n"); } if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 printer->Print(variables_, - "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + "- ($property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); } printer->Print("\n"); } @@ -385,14 +386,14 @@ void RepeatedFieldGenerator::GeneratePropertyDeclaration( variables_, "$comments$" "$array_comment$" - "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$;\n" + "@property(nonatomic, readwrite, strong, null_resettable) $array_property_type$ *$name$$storage_attribute$$deprecated_attribute$;\n" "/// The number of items in @c $name$ without causing the array to be created.\n" - "@property(nonatomic, readonly) NSUInteger $name$_Count;\n"); + "@property(nonatomic, readonly) NSUInteger $name$_Count$deprecated_attribute$;\n"); if (IsInitName(variables_.find("name")->second)) { // If property name starts with init we need to annotate it to get past ARC. // http://stackoverflow.com/questions/18723226/how-do-i-annotate-an-objective-c-property-with-an-objc-method-family/18723227#18723227 printer->Print(variables_, - "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE;\n"); + "- ($array_property_type$ *)$name$ GPB_METHOD_FAMILY_NONE$deprecated_attribute$;\n"); } printer->Print("\n"); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_file.cc b/src/google/protobuf/compiler/objectivec/objectivec_file.cc index c58e7530..ed4fc6a3 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_file.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_file.cc @@ -115,6 +115,9 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { printer->Print( "// @@protoc_insertion_point(imports)\n" "\n" + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" + "\n" "CF_EXTERN_C_BEGIN\n" "\n"); @@ -189,6 +192,8 @@ void FileGenerator::GenerateHeader(io::Printer *printer) { "\n" "CF_EXTERN_C_END\n" "\n" + "#pragma clang diagnostic pop\n" + "\n" "// @@protoc_insertion_point(global_scope)\n"); } @@ -216,6 +221,9 @@ void FileGenerator::GenerateSource(io::Printer *printer) { } printer->Print( "// @@protoc_insertion_point(imports)\n" + "\n" + "#pragma clang diagnostic push\n" + "#pragma clang diagnostic ignored \"-Wdeprecated-declarations\"\n" "\n"); printer->Print( @@ -342,6 +350,8 @@ void FileGenerator::GenerateSource(io::Printer *printer) { } printer->Print( + "\n" + "#pragma clang diagnostic pop\n" "\n" "// @@protoc_insertion_point(global_scope)\n"); } diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h index 0db9de94..3f56d94b 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.h +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.h @@ -133,6 +133,22 @@ enum ObjectiveCType { OBJECTIVECTYPE_MESSAGE }; +template +string GetOptionalDeprecatedAttribute(const TDescriptor* descriptor, bool preSpace = true, bool postNewline = false) { + if (descriptor->options().deprecated()) { + string result = "DEPRECATED_ATTRIBUTE"; + if (preSpace) { + result.insert(0, " "); + } + if (postNewline) { + result.append("\n"); + } + return result; + } else { + return ""; + } +} + string GetCapitalizedType(const FieldDescriptor* field); ObjectiveCType GetObjectiveCType(FieldDescriptor::Type field_type); diff --git a/src/google/protobuf/compiler/objectivec/objectivec_message.cc b/src/google/protobuf/compiler/objectivec/objectivec_message.cc index 3ebeeade..bf272596 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_message.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_message.cc @@ -321,8 +321,9 @@ void MessageGenerator::GenerateMessageHeader(io::Printer* printer) { } printer->Print( - "$comments$@interface $classname$ : GPBMessage\n\n", + "$comments$$deprecated_attribute$@interface $classname$ : GPBMessage\n\n", "classname", class_name_, + "deprecated_attribute", GetOptionalDeprecatedAttribute(descriptor_, false, true), "comments", message_comments); vector seen_oneofs(descriptor_->oneof_decl_count(), 0); From b56b461e4918992bfe122e7596f8620dcc3dd6de Mon Sep 17 00:00:00 2001 From: Andrew Harp Date: Mon, 4 Apr 2016 15:13:30 -0400 Subject: [PATCH 057/123] Do not link in pthread library for Android builds. This is required to allow Tensorflow to build on Android without hacks. Currently we create a dummy pthread library just to satisfy this dependency for a library that does not exist on Android. See https://github.com/google/protobuf/issues/1373 for more context. --- BUILD | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/BUILD b/BUILD index e35a2e8e..03582503 100644 --- a/BUILD +++ b/BUILD @@ -15,8 +15,18 @@ COPTS = [ "-Wno-error=unused-function", ] -# Bazel should provide portable link_opts for pthread. -LINK_OPTS = ["-lpthread"] +config_setting( + name = "android", + values = { + "crosstool_top": "//external:android/crosstool", + }, +) + +# Android builds do not need to link in a separate pthread library. +LINK_OPTS = select({ + "//tensorflow:android": [], + "//conditions:default": ["-lpthread"], +}) load( "protobuf", From 3b4e7dcf290b32695c13594e0e465de181ae87c0 Mon Sep 17 00:00:00 2001 From: Andrew Harp Date: Mon, 4 Apr 2016 16:13:31 -0400 Subject: [PATCH 058/123] Update BUILD --- BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD b/BUILD index 03582503..1615486f 100644 --- a/BUILD +++ b/BUILD @@ -24,7 +24,7 @@ config_setting( # Android builds do not need to link in a separate pthread library. LINK_OPTS = select({ - "//tensorflow:android": [], + ":android": [], "//conditions:default": ["-lpthread"], }) From 74d8b0bebc233331b1861354908f7fa0fde9d769 Mon Sep 17 00:00:00 2001 From: Gaurav Vaish Date: Thu, 24 Mar 2016 11:44:56 -0700 Subject: [PATCH 059/123] Added access_level for types * `csharp_options`: Added `Options` to encapsulate generator options. Supported options for now - file_extension, base_namespace * `{Blah}Generator`: Now accept `Options*` as parameter to constructor * `csharp_generator.cc`: Parse and populate options * `Makefile.am`: Added `csharp_options.h` * `extract_includes.bat.in`: Added `csharp_options.h` Refactoring code to two commits. This is the first commit --- cmake/extract_includes.bat.in | 1 + src/Makefile.am | 1 + .../protobuf/compiler/csharp/csharp_enum.cc | 4 +- .../protobuf/compiler/csharp/csharp_enum.h | 2 +- .../compiler/csharp/csharp_enum_field.cc | 9 +-- .../compiler/csharp/csharp_enum_field.h | 4 +- .../compiler/csharp/csharp_field_base.cc | 4 +- .../compiler/csharp/csharp_field_base.h | 2 +- .../compiler/csharp/csharp_generator.cc | 26 ++++---- .../compiler/csharp/csharp_helpers.cc | 27 +++++---- .../protobuf/compiler/csharp/csharp_helpers.h | 3 +- .../compiler/csharp/csharp_map_field.cc | 9 +-- .../compiler/csharp/csharp_map_field.h | 2 +- .../compiler/csharp/csharp_message.cc | 10 ++-- .../protobuf/compiler/csharp/csharp_message.h | 2 +- .../compiler/csharp/csharp_message_field.cc | 9 +-- .../compiler/csharp/csharp_message_field.h | 4 +- .../protobuf/compiler/csharp/csharp_options.h | 60 +++++++++++++++++++ .../compiler/csharp/csharp_primitive_field.cc | 9 +-- .../compiler/csharp/csharp_primitive_field.h | 6 +- .../csharp/csharp_reflection_class.cc | 10 ++-- .../compiler/csharp/csharp_reflection_class.h | 2 +- .../csharp/csharp_repeated_enum_field.cc | 4 +- .../csharp/csharp_repeated_enum_field.h | 2 +- .../csharp/csharp_repeated_message_field.cc | 8 +-- .../csharp/csharp_repeated_message_field.h | 4 +- .../csharp/csharp_repeated_primitive_field.cc | 4 +- .../csharp/csharp_repeated_primitive_field.h | 2 +- .../csharp/csharp_source_generator_base.cc | 10 +++- .../csharp/csharp_source_generator_base.h | 6 +- .../compiler/csharp/csharp_wrapper_field.cc | 9 +-- .../compiler/csharp/csharp_wrapper_field.h | 6 +- 32 files changed, 177 insertions(+), 84 deletions(-) create mode 100644 src/google/protobuf/compiler/csharp/csharp_options.h diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in index b593e0c9..c76973c9 100644 --- a/cmake/extract_includes.bat.in +++ b/cmake/extract_includes.bat.in @@ -23,6 +23,7 @@ copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\command_line_ copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_generator.h include\google\protobuf\compiler\csharp\csharp_generator.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_names.h include\google\protobuf\compiler\csharp\csharp_names.h +copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_options.h include\google\protobuf\compiler\csharp\csharp_options.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_names.h include\google\protobuf\compiler\java\java_names.h diff --git a/src/Makefile.am b/src/Makefile.am index 073673a5..2ba0ef9b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -455,6 +455,7 @@ libprotoc_la_SOURCES = \ google/protobuf/compiler/csharp/csharp_message.h \ google/protobuf/compiler/csharp/csharp_message_field.cc \ google/protobuf/compiler/csharp/csharp_message_field.h \ + google/protobuf/compiler/csharp/csharp_options.h \ google/protobuf/compiler/csharp/csharp_primitive_field.cc \ google/protobuf/compiler/csharp/csharp_primitive_field.h \ google/protobuf/compiler/csharp/csharp_reflection_class.cc \ diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc index 56681989..9616f172 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc @@ -49,8 +49,8 @@ namespace protobuf { namespace compiler { namespace csharp { -EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) : - SourceGeneratorBase(descriptor->file()), +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Options* options) : + SourceGeneratorBase(descriptor->file(), options), descriptor_(descriptor) { } diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.h b/src/google/protobuf/compiler/csharp/csharp_enum.h index 2cf2fad4..8925cdf2 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum.h +++ b/src/google/protobuf/compiler/csharp/csharp_enum.h @@ -43,7 +43,7 @@ namespace csharp { class EnumGenerator : public SourceGeneratorBase { public: - EnumGenerator(const EnumDescriptor* descriptor); + EnumGenerator(const EnumDescriptor* descriptor, const Options* options); ~EnumGenerator(); void Generate(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc index d38fb1ed..53c4589b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc @@ -38,6 +38,7 @@ #include #include +#include #include namespace google { @@ -46,8 +47,8 @@ namespace compiler { namespace csharp { EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : PrimitiveFieldGenerator(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) { } EnumFieldGenerator::~EnumFieldGenerator() { @@ -81,8 +82,8 @@ void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) { } EnumOneofFieldGenerator::EnumOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options) { } EnumOneofFieldGenerator::~EnumOneofFieldGenerator() { diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h index 08364157..7e38d6e6 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h @@ -43,7 +43,7 @@ namespace csharp { class EnumFieldGenerator : public PrimitiveFieldGenerator { public: - EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~EnumFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -57,7 +57,7 @@ class EnumFieldGenerator : public PrimitiveFieldGenerator { class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator { public: - EnumOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~EnumOneofFieldGenerator(); virtual void GenerateParsingCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc index 5df43d3f..d8566613 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -100,8 +100,8 @@ void FieldGeneratorBase::SetCommonOneofFieldVariables( } FieldGeneratorBase::FieldGeneratorBase(const FieldDescriptor* descriptor, - int fieldOrdinal) - : SourceGeneratorBase(descriptor->file()), + int fieldOrdinal, const Options* options) + : SourceGeneratorBase(descriptor->file(), options), descriptor_(descriptor), fieldOrdinal_(fieldOrdinal) { SetCommonFieldVariables(&variables_); diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h index d83543bd..40f36042 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -44,7 +44,7 @@ namespace csharp { class FieldGeneratorBase : public SourceGeneratorBase { public: - FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal); + FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal, const Options* options); ~FieldGeneratorBase(); virtual void GenerateCloningCode(io::Printer* printer) = 0; diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc index 825de542..567f827e 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -41,6 +41,7 @@ #include #include #include +#include #include using google::protobuf::internal::scoped_ptr; @@ -51,8 +52,9 @@ namespace compiler { namespace csharp { void GenerateFile(const google::protobuf::FileDescriptor* file, - io::Printer* printer) { - ReflectionClassGenerator reflectionClassGenerator(file); + io::Printer* printer, + const Options* options) { + ReflectionClassGenerator reflectionClassGenerator(file, options); reflectionClassGenerator.Generate(printer); } @@ -71,15 +73,14 @@ bool Generator::Generate( return false; } - std::string file_extension = ".cs"; - std::string base_namespace = ""; - bool generate_directories = false; + struct Options cli_options; + for (int i = 0; i < options.size(); i++) { if (options[i].first == "file_extension") { - file_extension = options[i].second; + cli_options.file_extension = options[i].second; } else if (options[i].first == "base_namespace") { - base_namespace = options[i].second; - generate_directories = true; + cli_options.base_namespace = options[i].second; + cli_options.generate_directories = true; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -87,7 +88,12 @@ bool Generator::Generate( } string filename_error = ""; - std::string filename = GetOutputFile(file, file_extension, generate_directories, base_namespace, &filename_error); + std::string filename = GetOutputFile(file, + cli_options.file_extension, + cli_options.generate_directories, + cli_options.base_namespace, + &filename_error); + if (filename.empty()) { *error = filename_error; return false; @@ -96,7 +102,7 @@ bool Generator::Generate( generator_context->Open(filename)); io::Printer printer(output.get(), '$'); - GenerateFile(file, &printer); + GenerateFile(file, &printer, &cli_options); return true; } diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index c51fe44b..3c1cd4b7 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -351,49 +352,49 @@ std::string FileDescriptorToBase64(const FileDescriptor* descriptor) { } FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) { + int fieldOrdinal, const Options* options) { switch (descriptor->type()) { case FieldDescriptor::TYPE_GROUP: case FieldDescriptor::TYPE_MESSAGE: if (descriptor->is_repeated()) { if (descriptor->is_map()) { - return new MapFieldGenerator(descriptor, fieldOrdinal); + return new MapFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal); + return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal, options); } } else { if (IsWrapperType(descriptor)) { if (descriptor->containing_oneof()) { - return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal); + return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new WrapperFieldGenerator(descriptor, fieldOrdinal); + return new WrapperFieldGenerator(descriptor, fieldOrdinal, options); } } else { if (descriptor->containing_oneof()) { - return new MessageOneofFieldGenerator(descriptor, fieldOrdinal); + return new MessageOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new MessageFieldGenerator(descriptor, fieldOrdinal); + return new MessageFieldGenerator(descriptor, fieldOrdinal, options); } } } case FieldDescriptor::TYPE_ENUM: if (descriptor->is_repeated()) { - return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal); + return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal, options); } else { if (descriptor->containing_oneof()) { - return new EnumOneofFieldGenerator(descriptor, fieldOrdinal); + return new EnumOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new EnumFieldGenerator(descriptor, fieldOrdinal); + return new EnumFieldGenerator(descriptor, fieldOrdinal, options); } } default: if (descriptor->is_repeated()) { - return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal); + return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal, options); } else { if (descriptor->containing_oneof()) { - return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal); + return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options); } else { - return new PrimitiveFieldGenerator(descriptor, fieldOrdinal); + return new PrimitiveFieldGenerator(descriptor, fieldOrdinal, options); } } } diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index e96e7938..beead038 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -46,6 +46,7 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; class FieldGeneratorBase; // TODO: start using this enum. @@ -95,7 +96,7 @@ std::string StringToBase64(const std::string& input); std::string FileDescriptorToBase64(const FileDescriptor* descriptor); -FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options* options); // Determines whether the given message is a map entry message, i.e. one implicitly created // by protoc due to a map field. diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc index 15c68b3f..8bf4f462 100644 --- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc @@ -48,8 +48,9 @@ namespace compiler { namespace csharp { MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + int fieldOrdinal, + const Options* options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } MapFieldGenerator::~MapFieldGenerator() { @@ -62,8 +63,8 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) { descriptor_->message_type()->FindFieldByName("value"); variables_["key_type_name"] = type_name(key_descriptor); variables_["value_type_name"] = type_name(value_descriptor); - scoped_ptr key_generator(CreateFieldGenerator(key_descriptor, 1)); - scoped_ptr value_generator(CreateFieldGenerator(value_descriptor, 2)); + scoped_ptr key_generator(CreateFieldGenerator(key_descriptor, 1, this->options())); + scoped_ptr value_generator(CreateFieldGenerator(value_descriptor, 2, this->options())); printer->Print( variables_, diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.h b/src/google/protobuf/compiler/csharp/csharp_map_field.h index f33fe1c3..c7ebd0bd 100644 --- a/src/google/protobuf/compiler/csharp/csharp_map_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_map_field.h @@ -43,7 +43,7 @@ namespace csharp { class MapFieldGenerator : public FieldGeneratorBase { public: - MapFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + MapFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options* options); ~MapFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index e0230a24..3b54040d 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -60,8 +60,8 @@ bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { return d1->number() < d2->number(); } -MessageGenerator::MessageGenerator(const Descriptor* descriptor) - : SourceGeneratorBase(descriptor->file()), +MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Options* options) + : SourceGeneratorBase(descriptor->file(), options), descriptor_(descriptor) { // sorted field names @@ -214,13 +214,13 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Print("public static partial class Types {\n"); printer->Indent(); for (int i = 0; i < descriptor_->enum_type_count(); i++) { - EnumGenerator enumGenerator(descriptor_->enum_type(i)); + EnumGenerator enumGenerator(descriptor_->enum_type(i), this->options()); enumGenerator.Generate(printer); } for (int i = 0; i < descriptor_->nested_type_count(); i++) { // Don't generate nested types for maps... if (!IsMapEntryMessage(descriptor_->nested_type(i))) { - MessageGenerator messageGenerator(descriptor_->nested_type(i)); + MessageGenerator messageGenerator(descriptor_->nested_type(i), this->options()); messageGenerator.Generate(printer); } } @@ -490,7 +490,7 @@ int MessageGenerator::GetFieldOrdinal(const FieldDescriptor* descriptor) { FieldGeneratorBase* MessageGenerator::CreateFieldGeneratorInternal( const FieldDescriptor* descriptor) { - return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor)); + return CreateFieldGenerator(descriptor, GetFieldOrdinal(descriptor), this->options()); } } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_message.h b/src/google/protobuf/compiler/csharp/csharp_message.h index f0c49ac9..f794d68d 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.h +++ b/src/google/protobuf/compiler/csharp/csharp_message.h @@ -47,7 +47,7 @@ class FieldGeneratorBase; class MessageGenerator : public SourceGeneratorBase { public: - MessageGenerator(const Descriptor* descriptor); + MessageGenerator(const Descriptor* descriptor, const Options* options); ~MessageGenerator(); void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc index f81f769b..174bf995 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -41,6 +41,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -48,8 +49,8 @@ namespace compiler { namespace csharp { MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { variables_["has_property_check"] = name() + "_ != null"; variables_["has_not_property_check"] = name() + "_ == null"; } @@ -144,8 +145,8 @@ void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) { } MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : MessageFieldGenerator(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : MessageFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h index dc6e4dc5..815790ac 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -43,7 +43,7 @@ namespace csharp { class MessageFieldGenerator : public FieldGeneratorBase { public: - MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~MessageFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -65,7 +65,7 @@ class MessageFieldGenerator : public FieldGeneratorBase { class MessageOneofFieldGenerator : public MessageFieldGenerator { public: - MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~MessageOneofFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h new file mode 100644 index 00000000..99e05140 --- /dev/null +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -0,0 +1,60 @@ +// 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_CSHARP_OPTIONS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ + +#include + +#include +namespace google { +namespace protobuf { +namespace compiler { +namespace csharp { + +// Generator options (used by csharp_generator.cc): +struct Options { + Options() : file_extension(".cs"), base_namespace(""), generate_directories(false) { + } + // Extension of the generated file. Defaults to ".cs" + string file_extension; + // Base namespace to use to create directory hierarchy. Defaults to "" + string base_namespace; + // Whether or not to generate directory hierarchy. Defaults to false + bool generate_directories; +}; + +} // namespace csharp +} // namespace compiler +} // namespace protobuf + + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_OPTIONS_H__ diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc index 60afd892..3b7ca75a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc @@ -40,6 +40,7 @@ #include #include +#include #include namespace google { @@ -48,8 +49,8 @@ namespace compiler { namespace csharp { PrimitiveFieldGenerator::PrimitiveFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { // TODO(jonskeet): Make this cleaner... is_value_type = descriptor->type() != FieldDescriptor::TYPE_STRING && descriptor->type() != FieldDescriptor::TYPE_BYTES; @@ -163,8 +164,8 @@ void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) { } PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : PrimitiveFieldGenerator(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : PrimitiveFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h index 8b87ebc4..f66529fd 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h @@ -41,9 +41,11 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class PrimitiveFieldGenerator : public FieldGeneratorBase { public: - PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~PrimitiveFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -67,7 +69,7 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase { class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { public: - PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~PrimitiveOneofFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc index 22dae43b..f7397c0f 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc @@ -43,6 +43,7 @@ #include #include #include +#include #include namespace google { @@ -50,8 +51,9 @@ namespace protobuf { namespace compiler { namespace csharp { -ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file) - : SourceGeneratorBase(file), +ReflectionClassGenerator::ReflectionClassGenerator(const FileDescriptor* file, + const Options* options) + : SourceGeneratorBase(file, options), file_(file) { namespace_ = GetFileNamespace(file); reflectionClassname_ = GetReflectionClassUnqualifiedName(file); @@ -72,7 +74,7 @@ void ReflectionClassGenerator::Generate(io::Printer* printer) { if (file_->enum_type_count() > 0) { printer->Print("#region Enums\n"); for (int i = 0; i < file_->enum_type_count(); i++) { - EnumGenerator enumGenerator(file_->enum_type(i)); + EnumGenerator enumGenerator(file_->enum_type(i), this->options()); enumGenerator.Generate(printer); } printer->Print("#endregion\n"); @@ -83,7 +85,7 @@ void ReflectionClassGenerator::Generate(io::Printer* printer) { if (file_->message_type_count() > 0) { printer->Print("#region Messages\n"); for (int i = 0; i < file_->message_type_count(); i++) { - MessageGenerator messageGenerator(file_->message_type(i)); + MessageGenerator messageGenerator(file_->message_type(i), this->options()); messageGenerator.Generate(printer); } printer->Print("#endregion\n"); diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h index 0a5b8ed5..518b7204 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h @@ -43,7 +43,7 @@ namespace csharp { class ReflectionClassGenerator : public SourceGeneratorBase { public: - ReflectionClassGenerator(const FileDescriptor* file); + ReflectionClassGenerator(const FileDescriptor* file, const Options* options); ~ReflectionClassGenerator(); void Generate(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc index 3a11b75d..1befdc15 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc @@ -48,8 +48,8 @@ namespace compiler { namespace csharp { RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() { diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h index ee50eef0..92cc5f41 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -45,7 +45,7 @@ namespace csharp { // should probably have a RepeatedFieldGeneratorBase. class RepeatedEnumFieldGenerator : public FieldGeneratorBase { public: - RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~RepeatedEnumFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc index fc12faed..daca43f1 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -49,8 +49,8 @@ namespace compiler { namespace csharp { RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() { @@ -66,10 +66,10 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) { // "create single field generator for this repeated field" // function, but it doesn't seem worth it for just this. if (IsWrapperType(descriptor_)) { - scoped_ptr single_generator(new WrapperFieldGenerator(descriptor_, fieldOrdinal_)); + scoped_ptr single_generator(new WrapperFieldGenerator(descriptor_, fieldOrdinal_, this->options())); single_generator->GenerateCodecCode(printer); } else { - scoped_ptr single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_)); + scoped_ptr single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_, this->options())); single_generator->GenerateCodecCode(printer); } printer->Print(";\n"); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h index cf601c7e..70a66a37 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -41,9 +41,11 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class RepeatedMessageFieldGenerator : public FieldGeneratorBase { public: - RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~RepeatedMessageFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc index 5fe0b203..bee3f363 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc @@ -48,8 +48,8 @@ namespace compiler { namespace csharp { RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( - const FieldDescriptor* descriptor, int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { } RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() { diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h index f1ceeb50..a59348a9 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h @@ -43,7 +43,7 @@ namespace csharp { class RepeatedPrimitiveFieldGenerator : public FieldGeneratorBase { public: - RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~RepeatedPrimitiveFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc index 735d164a..0705d521 100644 --- a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc @@ -39,14 +39,16 @@ #include #include +#include +#include namespace google { namespace protobuf { namespace compiler { namespace csharp { -SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor) - : descriptor_(descriptor) { +SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor, const Options *options) + : descriptor_(descriptor), options_(options) { } SourceGeneratorBase::~SourceGeneratorBase() { @@ -60,6 +62,10 @@ std::string SourceGeneratorBase::class_access_level() { return IsDescriptorProto(descriptor_) ? "internal" : "public"; // public_classes is always on. } +const Options* SourceGeneratorBase::options() { + return this->options_; +} + } // namespace csharp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h index 6caef171..2e734581 100644 --- a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h @@ -40,17 +40,21 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class SourceGeneratorBase { protected: - SourceGeneratorBase(const FileDescriptor* descriptor); + SourceGeneratorBase(const FileDescriptor* descriptor, const Options* options); virtual ~SourceGeneratorBase(); std::string class_access_level(); + const Options* options(); void WriteGeneratedCodeAttributes(io::Printer* printer); private: const FileDescriptor* descriptor_; + const Options *options_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceGeneratorBase); }; diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc index 6a3750e0..10767f03 100644 --- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc @@ -39,6 +39,7 @@ #include #include +#include #include namespace google { @@ -47,8 +48,8 @@ namespace compiler { namespace csharp { WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : FieldGeneratorBase(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : FieldGeneratorBase(descriptor, fieldOrdinal, options) { variables_["has_property_check"] = name() + "_ != null"; variables_["has_not_property_check"] = name() + "_ == null"; const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0); @@ -152,8 +153,8 @@ void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) { } WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal) - : WrapperFieldGenerator(descriptor, fieldOrdinal) { + int fieldOrdinal, const Options *options) + : WrapperFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h index 6e2414af..475b765b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h @@ -41,9 +41,11 @@ namespace protobuf { namespace compiler { namespace csharp { +struct Options; + class WrapperFieldGenerator : public FieldGeneratorBase { public: - WrapperFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + WrapperFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~WrapperFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -65,7 +67,7 @@ class WrapperFieldGenerator : public FieldGeneratorBase { class WrapperOneofFieldGenerator : public WrapperFieldGenerator { public: - WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal); + WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); ~WrapperOneofFieldGenerator(); virtual void GenerateMembers(io::Printer* printer); From f3f5b3fb64308817c5df105321995c5b9d0c0be7 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 5 Apr 2016 12:33:39 -0400 Subject: [PATCH 060/123] Add tests to ensure we read strings with BOMs so we don't forget about lessons of the past. --- objectivec/Tests/GPBCodedInputStreamTests.m | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m index b0e39d2c..b40360eb 100644 --- a/objectivec/Tests/GPBCodedInputStreamTests.m +++ b/objectivec/Tests/GPBCodedInputStreamTests.m @@ -295,4 +295,42 @@ XCTAssertEqualObjects(@"", message.defaultString); } +- (void)testBOMWithinStrings { + // We've seen servers that end up with BOMs within strings (not always at the + // start, and sometimes in multiple places), make sure they always parse + // correctly. (Again, this is inpart incase a custom string class is ever + // used again.) + const char* strs[] = { + "\xEF\xBB\xBF String with BOM", + "String with \xEF\xBB\xBF in middle", + "String with end bom \xEF\xBB\xBF", + "\xEF\xBB\xBF\xe2\x99\xa1", // BOM White Heart + "\xEF\xBB\xBF\xEF\xBB\xBF String with Two BOM", + }; + for (size_t i = 0; i < GPBARRAYSIZE(strs); ++i) { + NSOutputStream* rawOutput = [NSOutputStream outputStreamToMemory]; + GPBCodedOutputStream* output = + [GPBCodedOutputStream streamWithOutputStream:rawOutput]; + + int32_t tag = GPBWireFormatMakeTag(TestAllTypes_FieldNumber_DefaultString, + GPBWireFormatLengthDelimited); + [output writeRawVarint32:tag]; + size_t length = strlen(strs[i]); + [output writeRawVarint32:(int32_t)length]; + [output writeRawData:[NSData dataWithBytes:strs[i] length:length]]; + [output flush]; + + NSData* data = + [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input + extensionRegistry:nil + error:NULL]; + XCTAssertNotNil(message, @"Loop %zd", i); + // Ensure the string is there. NSString can consume the BOM in some + // cases, so don't actually check the string for exact equality. + XCTAssertTrue(message.defaultString.length > 0, @"Loop %zd", i); + } +} + @end From c9167f2acdd8ab477acb620cdd0bd231c8a0f3d0 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 5 Apr 2016 17:04:36 -0400 Subject: [PATCH 061/123] Error during parsing for invalid UTF-8 instead of dropping dropping data. This seems to be some code evolution side effects. Back when there was a custom string class, we couldn't really error when we finally saw the string was bad so we had to return the empty string, but now that full validation is done up front, it can error out. --- objectivec/GPBCodedInputStream.m | 7 ++++--- objectivec/Tests/GPBCodedInputStreamTests.m | 11 +++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/objectivec/GPBCodedInputStream.m b/objectivec/GPBCodedInputStream.m index eaa28e50..319ec15b 100644 --- a/objectivec/GPBCodedInputStream.m +++ b/objectivec/GPBCodedInputStream.m @@ -219,15 +219,16 @@ NSString *GPBCodedInputStreamReadRetainedString( result = [[NSString alloc] initWithBytes:&state->bytes[state->bufferPos] length:size encoding:NSUTF8StringEncoding]; + state->bufferPos += size; if (!result) { - result = @""; #ifdef DEBUG // https://developers.google.com/protocol-buffers/docs/proto#scalar - NSLog(@"UTF8 failure, is some field type 'string' when it should be " + NSLog(@"UTF-8 failure, is some field type 'string' when it should be " @"'bytes'?"); #endif + [NSException raise:NSParseErrorException + format:@"Invalid UTF-8 for a 'string'"]; } - state->bufferPos += size; } return result; } diff --git a/objectivec/Tests/GPBCodedInputStreamTests.m b/objectivec/Tests/GPBCodedInputStreamTests.m index b40360eb..cc402156 100644 --- a/objectivec/Tests/GPBCodedInputStreamTests.m +++ b/objectivec/Tests/GPBCodedInputStreamTests.m @@ -283,16 +283,15 @@ [output writeRawData:[NSData dataWithBytes:bytes length:sizeof(bytes)]]; [output flush]; - NSData* data = + NSData *data = [rawOutput propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; GPBCodedInputStream* input = [GPBCodedInputStream streamWithData:data]; + NSError *error = nil; TestAllTypes* message = [TestAllTypes parseFromCodedInputStream:input extensionRegistry:nil - error:NULL]; - XCTAssertNotNil(message); - // Make sure we can read string properties twice without crashing. - XCTAssertEqual([message.defaultString length], (NSUInteger)0); - XCTAssertEqualObjects(@"", message.defaultString); + error:&error]; + XCTAssertNotNil(error); + XCTAssertNil(message); } - (void)testBOMWithinStrings { From bfd1c84a3dab01683c4e97dc401f5a4a264a7e7e Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 6 Apr 2016 10:17:13 +0100 Subject: [PATCH 062/123] Line-wrapping changes only for C# generator code This should have no behavioral changes at all. This doesn't strictly enforce an 80-column limit, but removes the most egregious violations. The indentation in the C# generator code is inconsistent in general, unfortunately - if we have any good tools that can be trusted to reformat, I'd be happy to apply them. --- .../compiler/csharp/csharp_enum_field.cc | 4 ++-- .../compiler/csharp/csharp_enum_field.h | 8 ++++++-- .../compiler/csharp/csharp_field_base.cc | 10 ++++++---- .../compiler/csharp/csharp_field_base.h | 4 +++- .../protobuf/compiler/csharp/csharp_helpers.cc | 6 ++++-- .../protobuf/compiler/csharp/csharp_helpers.h | 18 +++++++++++------- .../compiler/csharp/csharp_map_field.cc | 6 ++++-- .../compiler/csharp/csharp_map_field.h | 4 +++- .../protobuf/compiler/csharp/csharp_message.cc | 15 ++++++++++----- .../compiler/csharp/csharp_message_field.cc | 9 ++++++--- .../compiler/csharp/csharp_message_field.h | 8 ++++++-- .../protobuf/compiler/csharp/csharp_options.h | 5 ++++- .../compiler/csharp/csharp_primitive_field.h | 8 ++++++-- .../compiler/csharp/csharp_reflection_class.h | 4 +++- .../csharp/csharp_repeated_enum_field.h | 4 +++- .../csharp/csharp_repeated_message_field.cc | 6 ++++-- .../csharp/csharp_repeated_message_field.h | 4 +++- .../csharp/csharp_source_generator_base.cc | 3 ++- .../compiler/csharp/csharp_wrapper_field.cc | 4 ++-- .../compiler/csharp/csharp_wrapper_field.h | 8 ++++++-- 20 files changed, 94 insertions(+), 44 deletions(-) diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc index 53c4589b..67c0b596 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.cc @@ -81,8 +81,8 @@ void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) { "pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x)"); } -EnumOneofFieldGenerator::EnumOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal, const Options *options) +EnumOneofFieldGenerator::EnumOneofFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) : PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal, options) { } diff --git a/src/google/protobuf/compiler/csharp/csharp_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_enum_field.h index 7e38d6e6..9b7669ba 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_enum_field.h @@ -43,7 +43,9 @@ namespace csharp { class EnumFieldGenerator : public PrimitiveFieldGenerator { public: - EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + EnumFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~EnumFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -57,7 +59,9 @@ class EnumFieldGenerator : public PrimitiveFieldGenerator { class EnumOneofFieldGenerator : public PrimitiveOneofFieldGenerator { public: - EnumOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~EnumOneofFieldGenerator(); virtual void GenerateParsingCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc index d8566613..3b88954c 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -94,7 +94,8 @@ void FieldGeneratorBase::SetCommonFieldVariables( void FieldGeneratorBase::SetCommonOneofFieldVariables( map* variables) { (*variables)["oneof_name"] = oneof_name(); - (*variables)["has_property_check"] = oneof_name() + "Case_ == " + oneof_property_name() + + (*variables)["has_property_check"] = + oneof_name() + "Case_ == " + oneof_property_name() + "OneofCase." + property_name(); (*variables)["oneof_property_name"] = oneof_property_name(); } @@ -158,10 +159,11 @@ std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) { case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_GROUP: if (IsWrapperType(descriptor)) { - const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0); + const FieldDescriptor* wrapped_field = + descriptor->message_type()->field(0); string wrapped_field_type_name = type_name(wrapped_field); - // String and ByteString go to the same type; other wrapped types go to the - // nullable equivalent. + // String and ByteString go to the same type; other wrapped types + // go to the nullable equivalent. if (wrapped_field->type() == FieldDescriptor::TYPE_STRING || wrapped_field->type() == FieldDescriptor::TYPE_BYTES) { return wrapped_field_type_name; diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.h b/src/google/protobuf/compiler/csharp/csharp_field_base.h index 40f36042..4109f3ca 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.h +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.h @@ -44,7 +44,9 @@ namespace csharp { class FieldGeneratorBase : public SourceGeneratorBase { public: - FieldGeneratorBase(const FieldDescriptor* descriptor, int fieldOrdinal, const Options* options); + FieldGeneratorBase(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options* options); ~FieldGeneratorBase(); virtual void GenerateCloningCode(io::Printer* printer) = 0; diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index 3c1cd4b7..41265f9a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -128,7 +128,8 @@ std::string GetFileNameBase(const FileDescriptor* descriptor) { } std::string GetReflectionClassUnqualifiedName(const FileDescriptor* descriptor) { - // TODO: Detect collisions with existing messages, and append an underscore if necessary. + // TODO: Detect collisions with existing messages, + // and append an underscore if necessary. return GetFileNameBase(descriptor) + "Reflection"; } @@ -352,7 +353,8 @@ std::string FileDescriptorToBase64(const FileDescriptor* descriptor) { } FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal, const Options* options) { + int fieldOrdinal, + const Options* options) { switch (descriptor->type()) { case FieldDescriptor::TYPE_GROUP: case FieldDescriptor::TYPE_MESSAGE: diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index beead038..eaf85014 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -83,7 +83,9 @@ std::string GetPropertyName(const FieldDescriptor* descriptor); int GetFixedSize(FieldDescriptor::Type type); -std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter, bool preserve_period); +std::string UnderscoresToCamelCase(const std::string& input, + bool cap_next_letter, + bool preserve_period); inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_next_letter) { return UnderscoresToCamelCase(input, cap_next_letter, false); @@ -96,17 +98,19 @@ std::string StringToBase64(const std::string& input); std::string FileDescriptorToBase64(const FileDescriptor* descriptor); -FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options* options); +FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options* options); -// Determines whether the given message is a map entry message, i.e. one implicitly created -// by protoc due to a map field. +// Determines whether the given message is a map entry message, +// i.e. one implicitly created by protoc due to a map field. inline bool IsMapEntryMessage(const Descriptor* descriptor) { return descriptor->options().map_entry(); } -// Determines whether we're generating code for the proto representation of descriptors etc, -// for use in the runtime. This is the only type which is allowed to use proto2 syntax, -// and it generates internal classes. +// Determines whether we're generating code for the proto representation of +// descriptors etc, for use in the runtime. This is the only type which is +// allowed to use proto2 syntax, and it generates internal classes. inline bool IsDescriptorProto(const FileDescriptor* descriptor) { return descriptor->name() == "google/protobuf/descriptor.proto"; } diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.cc b/src/google/protobuf/compiler/csharp/csharp_map_field.cc index 8bf4f462..565d1225 100644 --- a/src/google/protobuf/compiler/csharp/csharp_map_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_map_field.cc @@ -63,8 +63,10 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) { descriptor_->message_type()->FindFieldByName("value"); variables_["key_type_name"] = type_name(key_descriptor); variables_["value_type_name"] = type_name(value_descriptor); - scoped_ptr key_generator(CreateFieldGenerator(key_descriptor, 1, this->options())); - scoped_ptr value_generator(CreateFieldGenerator(value_descriptor, 2, this->options())); + scoped_ptr key_generator( + CreateFieldGenerator(key_descriptor, 1, this->options())); + scoped_ptr value_generator( + CreateFieldGenerator(value_descriptor, 2, this->options())); printer->Print( variables_, diff --git a/src/google/protobuf/compiler/csharp/csharp_map_field.h b/src/google/protobuf/compiler/csharp/csharp_map_field.h index c7ebd0bd..84a33a03 100644 --- a/src/google/protobuf/compiler/csharp/csharp_map_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_map_field.h @@ -43,7 +43,9 @@ namespace csharp { class MapFieldGenerator : public FieldGeneratorBase { public: - MapFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options* options); + MapFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options* options); ~MapFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_message.cc b/src/google/protobuf/compiler/csharp/csharp_message.cc index 3b54040d..532da6b9 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message.cc @@ -60,7 +60,8 @@ bool CompareFieldNumbers(const FieldDescriptor* d1, const FieldDescriptor* d2) { return d1->number() < d2->number(); } -MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Options* options) +MessageGenerator::MessageGenerator(const Descriptor* descriptor, + const Options* options) : SourceGeneratorBase(descriptor->file(), options), descriptor_(descriptor) { @@ -185,7 +186,8 @@ void MessageGenerator::Generate(io::Printer* printer) { } printer->Outdent(); printer->Print("}\n"); - // TODO: Should we put the oneof .proto comments here? It's unclear exactly where they should go. + // TODO: Should we put the oneof .proto comments here? + // It's unclear exactly where they should go. printer->Print( vars, "private $property_name$OneofCase $name$Case_ = $property_name$OneofCase.None;\n" @@ -220,7 +222,8 @@ void MessageGenerator::Generate(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { // Don't generate nested types for maps... if (!IsMapEntryMessage(descriptor_->nested_type(i))) { - MessageGenerator messageGenerator(descriptor_->nested_type(i), this->options()); + MessageGenerator messageGenerator( + descriptor_->nested_type(i), this->options()); messageGenerator.Generate(printer); } } @@ -268,7 +271,8 @@ void MessageGenerator::GenerateCloningCode(io::Printer* printer) { // Clone just the right field for each oneof for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { vars["name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), false); - vars["property_name"] = UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true); + vars["property_name"] = UnderscoresToCamelCase( + descriptor_->oneof_decl(i)->name(), true); printer->Print(vars, "switch (other.$property_name$Case) {\n"); printer->Indent(); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { @@ -449,7 +453,8 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) { uint32 tag = internal::WireFormatLite::MakeTag(field->number(), wt); // Handle both packed and unpacked repeated fields with the same Read*Array call; // the two generated cases are the packed and unpacked tags. - // TODO(jonskeet): Check that is_packable is equivalent to is_repeated && wt in { VARINT, FIXED32, FIXED64 }. + // TODO(jonskeet): Check that is_packable is equivalent to + // is_repeated && wt in { VARINT, FIXED32, FIXED64 }. // It looks like it is... if (field->is_packable()) { printer->Print( diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_message_field.cc index 174bf995..338692f8 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.cc @@ -49,7 +49,8 @@ namespace compiler { namespace csharp { MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal, const Options *options) + int fieldOrdinal, + const Options *options) : FieldGeneratorBase(descriptor, fieldOrdinal, options) { variables_["has_property_check"] = name() + "_ != null"; variables_["has_not_property_check"] = name() + "_ == null"; @@ -144,8 +145,10 @@ void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) { "pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)"); } -MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal, const Options *options) +MessageOneofFieldGenerator::MessageOneofFieldGenerator( + const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options) : MessageFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_message_field.h b/src/google/protobuf/compiler/csharp/csharp_message_field.h index 815790ac..7d614756 100644 --- a/src/google/protobuf/compiler/csharp/csharp_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_message_field.h @@ -43,7 +43,9 @@ namespace csharp { class MessageFieldGenerator : public FieldGeneratorBase { public: - MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + MessageFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~MessageFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -65,7 +67,9 @@ class MessageFieldGenerator : public FieldGeneratorBase { class MessageOneofFieldGenerator : public MessageFieldGenerator { public: - MessageOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~MessageOneofFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h index 99e05140..d75eefa6 100644 --- a/src/google/protobuf/compiler/csharp/csharp_options.h +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -41,7 +41,10 @@ namespace csharp { // Generator options (used by csharp_generator.cc): struct Options { - Options() : file_extension(".cs"), base_namespace(""), generate_directories(false) { + Options() : + file_extension(".cs"), + base_namespace(""), + generate_directories(false) { } // Extension of the generated file. Defaults to ".cs" string file_extension; diff --git a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h index f66529fd..5f466fc4 100644 --- a/src/google/protobuf/compiler/csharp/csharp_primitive_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_primitive_field.h @@ -45,7 +45,9 @@ struct Options; class PrimitiveFieldGenerator : public FieldGeneratorBase { public: - PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~PrimitiveFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -69,7 +71,9 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase { class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { public: - PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~PrimitiveOneofFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h index 518b7204..e0c69f31 100644 --- a/src/google/protobuf/compiler/csharp/csharp_reflection_class.h +++ b/src/google/protobuf/compiler/csharp/csharp_reflection_class.h @@ -56,7 +56,9 @@ class ReflectionClassGenerator : public SourceGeneratorBase { void WriteIntroduction(io::Printer* printer); void WriteDescriptor(io::Printer* printer); - void WriteGeneratedCodeInfo(const Descriptor* descriptor, io::Printer* printer, bool last); + void WriteGeneratedCodeInfo(const Descriptor* descriptor, + io::Printer* printer, + bool last); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionClassGenerator); }; diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h index 92cc5f41..819b5832 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h @@ -45,7 +45,9 @@ namespace csharp { // should probably have a RepeatedFieldGeneratorBase. class RepeatedEnumFieldGenerator : public FieldGeneratorBase { public: - RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~RepeatedEnumFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc index daca43f1..d51e638a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc @@ -66,10 +66,12 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) { // "create single field generator for this repeated field" // function, but it doesn't seem worth it for just this. if (IsWrapperType(descriptor_)) { - scoped_ptr single_generator(new WrapperFieldGenerator(descriptor_, fieldOrdinal_, this->options())); + scoped_ptr single_generator( + new WrapperFieldGenerator(descriptor_, fieldOrdinal_, this->options())); single_generator->GenerateCodecCode(printer); } else { - scoped_ptr single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_, this->options())); + scoped_ptr single_generator( + new MessageFieldGenerator(descriptor_, fieldOrdinal_, this->options())); single_generator->GenerateCodecCode(printer); } printer->Print(";\n"); diff --git a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h index 70a66a37..6e33648b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h @@ -45,7 +45,9 @@ struct Options; class RepeatedMessageFieldGenerator : public FieldGeneratorBase { public: - RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~RepeatedMessageFieldGenerator(); virtual void GenerateCloningCode(io::Printer* printer); diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc index 0705d521..bd459dda 100644 --- a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc @@ -47,7 +47,8 @@ namespace protobuf { namespace compiler { namespace csharp { -SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor, const Options *options) +SourceGeneratorBase::SourceGeneratorBase(const FileDescriptor* descriptor, + const Options *options) : descriptor_(descriptor), options_(options) { } diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc index 10767f03..5cb86b6b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc +++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc @@ -152,8 +152,8 @@ void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) { } } -WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, - int fieldOrdinal, const Options *options) +WrapperOneofFieldGenerator::WrapperOneofFieldGenerator( + const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options) : WrapperFieldGenerator(descriptor, fieldOrdinal, options) { SetCommonOneofFieldVariables(&variables_); } diff --git a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h index 475b765b..250dfd25 100644 --- a/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h +++ b/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h @@ -45,7 +45,9 @@ struct Options; class WrapperFieldGenerator : public FieldGeneratorBase { public: - WrapperFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + WrapperFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~WrapperFieldGenerator(); virtual void GenerateCodecCode(io::Printer* printer); @@ -67,7 +69,9 @@ class WrapperFieldGenerator : public FieldGeneratorBase { class WrapperOneofFieldGenerator : public WrapperFieldGenerator { public: - WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal, const Options *options); + WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, + int fieldOrdinal, + const Options *options); ~WrapperOneofFieldGenerator(); virtual void GenerateMembers(io::Printer* printer); From 2a18bb5a337bb1f07e66b89d5ae01b1e79ae3b68 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 6 Apr 2016 10:30:19 +0100 Subject: [PATCH 063/123] Add more documentation for csharp_options.h This also renames generate_directories to base_namespace_specified; generating directories is the immediate *effect* of specifying a base namespace, but with this change the options reflect what has been specified rather than the effect. (There may be other effects in the future, of course.) --- .../compiler/csharp/csharp_generator.cc | 4 ++-- .../protobuf/compiler/csharp/csharp_options.h | 20 +++++++++++++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc index 567f827e..df9730f8 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -80,7 +80,7 @@ bool Generator::Generate( cli_options.file_extension = options[i].second; } else if (options[i].first == "base_namespace") { cli_options.base_namespace = options[i].second; - cli_options.generate_directories = true; + cli_options.base_namespace_specified = true; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -90,7 +90,7 @@ bool Generator::Generate( string filename_error = ""; std::string filename = GetOutputFile(file, cli_options.file_extension, - cli_options.generate_directories, + cli_options.base_namespace_specified, cli_options.base_namespace, &filename_error); diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h index d75eefa6..9e5573ca 100644 --- a/src/google/protobuf/compiler/csharp/csharp_options.h +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -44,14 +44,26 @@ struct Options { Options() : file_extension(".cs"), base_namespace(""), - generate_directories(false) { + base_namespace_specified(false) { } // Extension of the generated file. Defaults to ".cs" string file_extension; - // Base namespace to use to create directory hierarchy. Defaults to "" + // Base namespace to use to create directory hierarchy. Defaults to "". + // This option allows the simple creation of a conventional C# file layout, + // where directories are created relative to a project-specific base + // namespace. For example, in a project with a base namespace of PetShop, a + // proto of user.proto with a C# namespace of PetShop.Model.Shared would + // generate Model/Shared/User.cs underneath the specified --csharp_out + // directory. + // + // If no base namespace is specified, all files are generated in the + // --csharp_out directory, with no subdirectories created automatically. string base_namespace; - // Whether or not to generate directory hierarchy. Defaults to false - bool generate_directories; + // Whether the base namespace has been explicitly specified by the user. + // This is required as the base namespace can be explicitly set to the empty + // string, meaning "create a full directory hierarchy, starting from the first + // segment of the namespace." + bool base_namespace_specified; }; } // namespace csharp From f98d2f5147bdb8182bc63acf00c9be9be5956b5e Mon Sep 17 00:00:00 2001 From: Geoffrey Wiseman Date: Wed, 6 Apr 2016 15:29:52 -0400 Subject: [PATCH 064/123] Updating Xcode Settings to use iOS 9.3 Update the simulators used for some tests under Xcode 7.3 to be iOS 9.3. --- objectivec/DevTools/full_mac_build.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh index b382779e..4d4930dc 100755 --- a/objectivec/DevTools/full_mac_build.sh +++ b/objectivec/DevTools/full_mac_build.sh @@ -242,6 +242,14 @@ if [[ "${DO_XCODE_IOS_TESTS}" == "yes" ]] ; then -destination "platform=iOS Simulator,name=iPad Air,OS=9.0" # 64bit ) ;; + 7.3* ) + XCODEBUILD_TEST_BASE_IOS+=( + -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit + -destination "platform=iOS Simulator,name=iPhone 6,OS=9.3" # 64bit + -destination "platform=iOS Simulator,name=iPad 2,OS=8.1" # 32bit + -destination "platform=iOS Simulator,name=iPad Air,OS=9.3" # 64bit + ) + ;; 7.* ) XCODEBUILD_TEST_BASE_IOS+=( -destination "platform=iOS Simulator,name=iPhone 4s,OS=8.1" # 32bit From c61207492efa36244ffa16cc5b394e71888e4c0f Mon Sep 17 00:00:00 2001 From: Jie Luo Date: Wed, 6 Apr 2016 14:24:45 -0700 Subject: [PATCH 065/123] sync the Manually integrate changes in google3/third_party --- src/google/protobuf/compiler/java/java_enum.cc | 6 +++++- .../protobuf/compiler/java/java_enum_field.cc | 16 ++++++++-------- .../compiler/java/java_enum_field_lite.cc | 12 ++++++------ .../protobuf/compiler/java/java_enum_lite.cc | 6 +++++- .../protobuf/compiler/java/java_message.cc | 6 +++++- .../compiler/java/java_message_builder.cc | 2 +- .../protobuf/compiler/java/java_message_lite.cc | 6 +++++- src/google/protobuf/dynamic_message.cc | 6 ++++++ 8 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 8a09f3a8..c06988c8 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -158,6 +158,10 @@ void EnumGenerator::Generate(io::Printer* printer) { "}\n" "\n" "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $classname$ forNumber(int value) {\n" " switch (value) {\n", "classname", descriptor_->name()); printer->Indent(); @@ -185,7 +189,7 @@ void EnumGenerator::Generate(io::Printer* printer) { " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" - " return $classname$.valueOf(number);\n" + " return $classname$.forNumber(number);\n" " }\n" " };\n" "\n", diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index 558da968..ae53b11b 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -198,7 +198,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); } @@ -231,7 +231,7 @@ GenerateBuilderMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -311,7 +311,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -405,7 +405,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -443,7 +443,7 @@ GenerateBuilderMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -500,7 +500,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -613,7 +613,7 @@ GenerateMembers(io::Printer* printer) const { " new com.google.protobuf.Internal.ListAdapter.Converter<\n" " java.lang.Integer, $type$>() {\n" " public $type$ convert(java.lang.Integer from) {\n" - " $type$ result = $type$.valueOf(from);\n" + " $type$ result = $type$.forNumber(from);\n" " return result == null ? $unknown$ : result;\n" " }\n" " };\n"); @@ -846,7 +846,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index e8bf15d0..27c992bc 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -179,7 +179,7 @@ GenerateMembers(io::Printer* printer) const { WriteFieldDocComment(printer, descriptor_); printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" - " $type$ result = $type$.valueOf($name$_);\n" + " $type$ result = $type$.forNumber($name$_);\n" " return result == null ? $unknown$ : result;\n" "}\n"); @@ -295,7 +295,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -389,7 +389,7 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "$deprecation$public $type$ get$capitalized_name$() {\n" " if ($has_oneof_case_message$) {\n" - " $type$ result = $type$.valueOf((java.lang.Integer) $oneof_name$_);\n" + " $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n" " return result == null ? $unknown$ : result;\n" " }\n" " return $default$;\n" @@ -488,7 +488,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, @@ -604,7 +604,7 @@ GenerateMembers(io::Printer* printer) const { " new com.google.protobuf.Internal.ListAdapter.Converter<\n" " java.lang.Integer, $type$>() {\n" " public $type$ convert(java.lang.Integer from) {\n" - " $type$ result = $type$.valueOf(from);\n" + " $type$ result = $type$.forNumber(from);\n" " return result == null ? $unknown$ : result;\n" " }\n" " };\n"); @@ -846,7 +846,7 @@ GenerateParsingCode(io::Printer* printer) const { } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" - "$type$ value = $type$.valueOf(rawValue);\n" + "$type$ value = $type$.forNumber(rawValue);\n" "if (value == null) {\n"); if (PreserveUnknownFields(descriptor_->containing_type())) { printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc index 62186386..4d7cd3f0 100644 --- a/src/google/protobuf/compiler/java/java_enum_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_lite.cc @@ -158,6 +158,10 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { "}\n" "\n" "public static $classname$ valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $classname$ forNumber(int value) {\n" " switch (value) {\n", "classname", descriptor_->name()); printer->Indent(); @@ -185,7 +189,7 @@ void EnumLiteGenerator::Generate(io::Printer* printer) { " $classname$> internalValueMap =\n" " new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" " public $classname$ findValueByNumber(int number) {\n" - " return $classname$.valueOf(number);\n" + " return $classname$.forNumber(number);\n" " }\n" " };\n" "\n", diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 19ba0707..a26030dd 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -414,6 +414,10 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "}\n"); printer->Print(vars, "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" " switch (value) {\n"); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); @@ -440,7 +444,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" "get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n"); diff --git a/src/google/protobuf/compiler/java/java_message_builder.cc b/src/google/protobuf/compiler/java/java_message_builder.cc index 72694119..1b86d2a9 100644 --- a/src/google/protobuf/compiler/java/java_message_builder.cc +++ b/src/google/protobuf/compiler/java/java_message_builder.cc @@ -134,7 +134,7 @@ Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" " get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n" diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 94ed2c39..b6f42d16 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -265,6 +265,10 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { "}\n"); printer->Print(vars, "public static $oneof_capitalized_name$Case valueOf(int value) {\n" + " return forNumber(value);\n" + "}\n" + "\n" + "public static $oneof_capitalized_name$Case forNumber(int value) {\n" " switch (value) {\n"); for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); @@ -291,7 +295,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print(vars, "public $oneof_capitalized_name$Case\n" "get$oneof_capitalized_name$Case() {\n" - " return $oneof_capitalized_name$Case.valueOf(\n" + " return $oneof_capitalized_name$Case.forNumber(\n" " $oneof_name$Case_);\n" "}\n" "\n" diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 091fc975..72a8483f 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -253,6 +253,12 @@ class DynamicMessage : public Message { DynamicMessage(const TypeInfo* type_info); ~DynamicMessage(); +#ifndef _MSC_VER + void operator delete(void *p) { + ::operator delete(p); // non-sized deallocation + } +#endif + // Called on the prototype after construction to initialize message fields. void CrossLinkPrototypes(); From a6e39316a7ab891d86aad2a902a1d9d7b23fd95d Mon Sep 17 00:00:00 2001 From: Gaurav Vaish Date: Thu, 7 Apr 2016 10:10:59 -0700 Subject: [PATCH 066/123] Added support for internal_access for C# --- src/google/protobuf/compiler/csharp/csharp_generator.cc | 2 ++ src/google/protobuf/compiler/csharp/csharp_options.h | 3 +++ .../protobuf/compiler/csharp/csharp_source_generator_base.cc | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc index df9730f8..c13ed65b 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -81,6 +81,8 @@ bool Generator::Generate( } else if (options[i].first == "base_namespace") { cli_options.base_namespace = options[i].second; cli_options.base_namespace_specified = true; + } else if (options[i].first == "internal_access") { + cli_options.internal_access = true; } else { *error = "Unknown generator option: " + options[i].first; return false; diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h index 9e5573ca..f25812c8 100644 --- a/src/google/protobuf/compiler/csharp/csharp_options.h +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -64,6 +64,9 @@ struct Options { // string, meaning "create a full directory hierarchy, starting from the first // segment of the namespace." bool base_namespace_specified; + // Whether the generated classes should have accessibility level of "internal". + // Defaults to false that generates "public" classes. + bool internal_access; }; } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc index bd459dda..16411e49 100644 --- a/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc @@ -60,7 +60,7 @@ void SourceGeneratorBase::WriteGeneratedCodeAttributes(io::Printer* printer) { } std::string SourceGeneratorBase::class_access_level() { - return IsDescriptorProto(descriptor_) ? "internal" : "public"; // public_classes is always on. + return (IsDescriptorProto(descriptor_) || this->options()->internal_access) ? "internal" : "public"; } const Options* SourceGeneratorBase::options() { From 15239361e31d53c10b918aa9fe8ce057155588b4 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 31 Mar 2016 14:18:34 -0700 Subject: [PATCH 067/123] Fix for CommonJS tests. --- js/commonjs/export_testdeps.js | 18 ++++++++++++++++++ js/commonjs/rewrite_tests_for_commonjs.js | 20 ++++++++++++-------- 2 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 js/commonjs/export_testdeps.js diff --git a/js/commonjs/export_testdeps.js b/js/commonjs/export_testdeps.js new file mode 100644 index 00000000..59c77ca2 --- /dev/null +++ b/js/commonjs/export_testdeps.js @@ -0,0 +1,18 @@ +/** + * @fileoverview Export symbols needed by tests in CommonJS style. + * + * This file is like export.js, but for symbols that are only used by tests. + * However we exclude assert functions here, because they are exported into + * the global namespace, so those are handled as a special case in + * export_asserts.js. + */ + +goog.require('goog.crypt.base64'); +goog.require('jspb.arith.Int64'); +goog.require('jspb.arith.UInt64'); +goog.require('jspb.BinaryEncoder'); +goog.require('jspb.BinaryDecoder'); +goog.require('jspb.utils'); + +exports.goog = goog; +exports.jspb = jspb; diff --git a/js/commonjs/rewrite_tests_for_commonjs.js b/js/commonjs/rewrite_tests_for_commonjs.js index ffa87722..b6d90d28 100644 --- a/js/commonjs/rewrite_tests_for_commonjs.js +++ b/js/commonjs/rewrite_tests_for_commonjs.js @@ -61,6 +61,18 @@ function camelCase(str) { var module = null; var pkg = null; + +// Header: goes in every file at the top. +console.log("var global = Function('return this')();"); +console.log("var googleProtobuf = require('google-protobuf');"); +console.log("var testdeps = require('testdeps_commonjs');"); +console.log("global.goog = testdeps.goog;"); +console.log("global.jspb = testdeps.jspb;"); +console.log("var asserts = require('closure_asserts_commonjs');"); +console.log(""); +console.log("// Bring asserts into the global namespace."); +console.log("googleProtobuf.object.extend(global, asserts);"); + lineReader.on('line', function(line) { var isRequire = line.match(/goog\.require\('([^']*)'\)/); var isLoadFromFile = line.match(/CommonJS-LoadFromFile: (\S*) (.*)/); @@ -72,14 +84,6 @@ lineReader.on('line', function(line) { console.log("googleProtobuf.exportSymbol('" + fullSym + "', " + module + sym + ', global);'); } } else if (isLoadFromFile) { - if (!module) { - console.log("var googleProtobuf = require('google-protobuf');"); - console.log("var asserts = require('closure_asserts_commonjs');"); - console.log("var global = Function('return this')();"); - console.log(""); - console.log("// Bring asserts into the global namespace."); - console.log("googleProtobuf.object.extend(global, asserts);"); - } var module_path = isLoadFromFile[1].split('/'); module = camelCase(module_path[module_path.length - 1]); pkg = isLoadFromFile[2]; From 2cd79bf3a8fd09c1df3dbc92a279a91a75896035 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 7 Apr 2016 14:26:59 -0700 Subject: [PATCH 068/123] Removed duplicated operator delete from merge conflict. --- src/google/protobuf/dynamic_message.cc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 6792dc0d..9e83bd29 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -253,12 +253,6 @@ class DynamicMessage : public Message { DynamicMessage(const TypeInfo* type_info); ~DynamicMessage(); -#ifndef _MSC_VER - void operator delete(void *p) { - ::operator delete(p); // non-sized deallocation - } -#endif - // Called on the prototype after construction to initialize message fields. void CrossLinkPrototypes(); From 0a902ee0acabf15f7d5f21b4d6ea0574495488f6 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Fri, 8 Apr 2016 09:57:32 +0100 Subject: [PATCH 069/123] Fix to csharp_options - initialize internal_access to false. --- src/google/protobuf/compiler/csharp/csharp_options.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h index f25812c8..426fb3b5 100644 --- a/src/google/protobuf/compiler/csharp/csharp_options.h +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -44,7 +44,8 @@ struct Options { Options() : file_extension(".cs"), base_namespace(""), - base_namespace_specified(false) { + base_namespace_specified(false), + internal_access(false) { } // Extension of the generated file. Defaults to ".cs" string file_extension; From 5ebeefb94cc9cca45331f56d3a9d5b96a74eb18e Mon Sep 17 00:00:00 2001 From: "David Z. Chen" Date: Fri, 8 Apr 2016 13:30:13 -0700 Subject: [PATCH 070/123] Add missing PY2AND3 srcs_versions attributes to Python Bazel build targets. --- BUILD | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/BUILD b/BUILD index 1615486f..d31d1ec1 100644 --- a/BUILD +++ b/BUILD @@ -535,9 +535,9 @@ java_library( "java/util/src/main/java/com/google/protobuf/util/*.java", ]), deps = [ - "protobuf_java", - "//external:gson", - "//external:guava", + "protobuf_java", + "//external:gson", + "//external:guava", ], visibility = ["//visibility:public"], ) @@ -558,6 +558,7 @@ py_library( "python/google/protobuf/internal/test_util.py", ], ), + srcs_version = "PY2AND3", imports = ["python"], ) @@ -642,6 +643,7 @@ py_proto_library( include = "src", default_runtime = "", protoc = ":protoc", + srcs_version = "PY2AND3", deps = [":protobuf_python"], ) @@ -654,6 +656,7 @@ py_proto_library( include = "python", default_runtime = ":protobuf_python", protoc = ":protoc", + srcs_version = "PY2AND3", deps = [":python_common_test_protos"], ) From 2a197b3eb0d74ac1f1d461ac958ebccaf968031c Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Fri, 8 Apr 2016 10:02:04 +0100 Subject: [PATCH 071/123] Use 0 as the default value for all enums, rather than finding the actual enum value name This will make it easier to change the enum value names, as it reduces the number of places they're used. --- src/google/protobuf/compiler/csharp/csharp_field_base.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/compiler/csharp/csharp_field_base.cc b/src/google/protobuf/compiler/csharp/csharp_field_base.cc index 3b88954c..e3c34040 100644 --- a/src/google/protobuf/compiler/csharp/csharp_field_base.cc +++ b/src/google/protobuf/compiler/csharp/csharp_field_base.cc @@ -306,7 +306,9 @@ std::string FieldGeneratorBase::default_value() { std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) { switch (descriptor->type()) { case FieldDescriptor::TYPE_ENUM: - return type_name() + "." + descriptor->default_value_enum()->name(); + // All proto3 enums have a default value of 0, and there's an implicit conversion from the constant 0 to + // any C# enum. This means we don't need to work out what we actually mapped the enum value name to. + return "0"; case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_GROUP: if (IsWrapperType(descriptor)) { From 3c4ce528c63f4dc39d15de963020472980ee7229 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Mon, 11 Apr 2016 15:53:25 -0700 Subject: [PATCH 072/123] Fix for gulpfile.js. --- js/gulpfile.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/js/gulpfile.js b/js/gulpfile.js index 36fd9fda..7e44aa76 100644 --- a/js/gulpfile.js +++ b/js/gulpfile.js @@ -42,7 +42,16 @@ gulp.task('commonjs_asserts', function (cb) { }); }); -gulp.task('make_commonjs_out', ['dist', 'genproto_commonjs', 'commonjs_asserts'], function (cb) { +gulp.task('commonjs_testdeps', function (cb) { + exec('mkdir -p commonjs_out/test_node_modules && ./node_modules/google-closure-library/closure/bin/calcdeps.py -i commonjs/export_testdeps.js -p . -p node_modules/google-closure-library/closure -o compiled --compiler_jar node_modules/google-closure-compiler/compiler.jar > commonjs_out/test_node_modules/testdeps_commonjs.js', + function (err, stdout, stderr) { + console.log(stdout); + console.log(stderr); + cb(err); + }); +}); + +gulp.task('make_commonjs_out', ['dist', 'genproto_commonjs', 'commonjs_asserts', 'commonjs_testdeps'], function (cb) { // TODO(haberman): minify this more aggressively. // Will require proper externs/exports. var cmd = "mkdir -p commonjs_out/binary && mkdir -p commonjs_out/test_node_modules && "; From 94e54b39c8a0f20a4e111784552706f1ffd8b45c Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 14 Apr 2016 12:06:09 -0700 Subject: [PATCH 073/123] Updated upb: picked up legacy JSON flags to help Ruby users migrate. The flags are: UPB_JSON_ACCEPT_LEGACY_FIELD_NAMES UPB_JSON_WRITE_LEGACY_FIELD_NAMES The first just allows the parser to accept the old field names. The second makes the printer print the old field names. These flags are intended to be temporary, as a migration aid for users. --- ruby/ext/google/protobuf_c/upb.c | 1149 ++++++++++++------- ruby/ext/google/protobuf_c/upb.h | 1798 ++++++++++++++---------------- 2 files changed, 1583 insertions(+), 1364 deletions(-) diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c index b2a69b66..db84ae3f 100644 --- a/ruby/ext/google/protobuf_c/upb.c +++ b/ruby/ext/google/protobuf_c/upb.c @@ -72,6 +72,20 @@ upb_deftype_t upb_def_type(const upb_def *d) { return d->type; } const char *upb_def_fullname(const upb_def *d) { return d->fullname; } +const char *upb_def_name(const upb_def *d) { + const char *p; + + if (d->fullname == NULL) { + return NULL; + } else if ((p = strrchr(d->fullname, '.')) == NULL) { + /* No '.' in the name, return the full string. */ + return d->fullname; + } else { + /* Return one past the last '.'. */ + return p + 1; + } +} + bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) { assert(!upb_def_isfrozen(def)); if (!upb_isident(fullname, strlen(fullname), true, s)) return false; @@ -80,6 +94,8 @@ bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) { return true; } +const upb_filedef *upb_def_file(const upb_def *d) { return d->file; } + upb_def *upb_def_dup(const upb_def *def, const void *o) { switch (def->type) { case UPB_DEF_MSG: @@ -102,6 +118,7 @@ static bool upb_def_init(upb_def *def, upb_deftype_t type, def->type = type; def->fullname = NULL; def->came_from_user = false; + def->file = NULL; return true; } @@ -317,11 +334,8 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { return true; } -bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { - int i; - int maxdepth; - bool ret; - upb_status_clear(s); +bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s) { + size_t i; /* First perform validation, in two passes so we can check that we have a * transitive closure without needing to search. */ @@ -347,8 +361,9 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { /* Second pass of validation. Also assign selector bases and indexes, and * compact tables. */ for (i = 0; i < n; i++) { - upb_msgdef *m = upb_dyncast_msgdef_mutable(defs[i]); - upb_enumdef *e = upb_dyncast_enumdef_mutable(defs[i]); + upb_def *def = defs[i]; + upb_msgdef *m = upb_dyncast_msgdef_mutable(def); + upb_enumdef *e = upb_dyncast_enumdef_mutable(def); if (m) { upb_inttable_compact(&m->itof); if (!assign_msg_indices(m, s)) { @@ -359,23 +374,31 @@ bool upb_def_freeze(upb_def *const* defs, int n, upb_status *s) { } } - /* Def graph contains FieldDefs between each MessageDef, so double the - * limit. */ - maxdepth = UPB_MAX_MESSAGE_DEPTH * 2; - - /* Validation all passed; freeze the defs. */ - ret = upb_refcounted_freeze((upb_refcounted * const *)defs, n, s, maxdepth); - assert(!(s && ret != upb_ok(s))); - return ret; + return true; err: for (i = 0; i < n; i++) { - defs[i]->came_from_user = false; + upb_def *def = defs[i]; + def->came_from_user = false; } assert(!(s && upb_ok(s))); return false; } +bool upb_def_freeze(upb_def *const* defs, size_t n, upb_status *s) { + /* Def graph contains FieldDefs between each MessageDef, so double the + * limit. */ + const size_t maxdepth = UPB_MAX_MESSAGE_DEPTH * 2; + + if (!_upb_def_validate(defs, n, s)) { + return false; + } + + + /* Validation all passed; freeze the objects. */ + return upb_refcounted_freeze((upb_refcounted *const*)defs, n, s, maxdepth); +} + /* upb_enumdef ****************************************************************/ @@ -434,6 +457,10 @@ const char *upb_enumdef_fullname(const upb_enumdef *e) { return upb_def_fullname(upb_enumdef_upcast(e)); } +const char *upb_enumdef_name(const upb_enumdef *e) { + return upb_def_name(upb_enumdef_upcast(e)); +} + bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, upb_status *s) { return upb_def_setfullname(upb_enumdef_upcast_mutable(e), fullname, s); @@ -537,7 +564,7 @@ static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit, visit(r, upb_msgdef_upcast2(upb_fielddef_containingtype(f)), closure); } if (upb_fielddef_containingoneof(f)) { - visit(r, upb_oneofdef_upcast2(upb_fielddef_containingoneof(f)), closure); + visit(r, upb_oneofdef_upcast(upb_fielddef_containingoneof(f)), closure); } if (upb_fielddef_subdef(f)) { visit(r, upb_def_upcast(upb_fielddef_subdef(f)), closure); @@ -1263,7 +1290,7 @@ bool upb_fielddef_haspresence(const upb_fielddef *f) { /* Primitive field: return true unless there is a message that specifies * presence should not exist. */ if (f->msg_is_symbolic || !f->msg.def) return true; - return f->msg.def->primitives_have_presence; + return f->msg.def->syntax == UPB_SYNTAX_PROTO2; } bool upb_fielddef_hassubdef(const upb_fielddef *f) { @@ -1299,7 +1326,7 @@ static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit, !upb_msg_oneof_done(&o); upb_msg_oneof_next(&o)) { upb_oneofdef *f = upb_msg_iter_oneof(&o); - visit(r, upb_oneofdef_upcast2(f), closure); + visit(r, upb_oneofdef_upcast(f), closure); } } @@ -1322,7 +1349,7 @@ upb_msgdef *upb_msgdef_new(const void *owner) { if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err2; if (!upb_strtable_init(&m->ntoo, UPB_CTYPE_PTR)) goto err1; m->map_entry = false; - m->primitives_have_presence = true; + m->syntax = UPB_SYNTAX_PROTO2; return m; err1: @@ -1345,7 +1372,7 @@ upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner) { upb_def_fullname(upb_msgdef_upcast(m)), NULL); newm->map_entry = m->map_entry; - newm->primitives_have_presence = m->primitives_have_presence; + newm->syntax = m->syntax; UPB_ASSERT_VAR(ok, ok); for(upb_msg_field_begin(&i, m); !upb_msg_field_done(&i); @@ -1379,6 +1406,10 @@ const char *upb_msgdef_fullname(const upb_msgdef *m) { return upb_def_fullname(upb_msgdef_upcast(m)); } +const char *upb_msgdef_name(const upb_msgdef *m) { + return upb_def_name(upb_msgdef_upcast(m)); +} + bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s) { return upb_def_setfullname(upb_msgdef_upcast_mutable(m), fullname, s); @@ -1490,11 +1521,6 @@ bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, return true; } -void upb_msgdef_setprimitiveshavepresence(upb_msgdef *m, bool have_presence) { - assert(!upb_msgdef_isfrozen(m)); - m->primitives_have_presence = have_presence; -} - const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { upb_value val; return upb_inttable_lookup32(&m->itof, i, &val) ? @@ -1587,7 +1613,7 @@ static void freeoneof(upb_refcounted *r) { upb_oneofdef *o = (upb_oneofdef*)r; upb_strtable_uninit(&o->ntof); upb_inttable_uninit(&o->itof); - upb_def_uninit(upb_oneofdef_upcast_mutable(o)); + free((void*)o->name); free(o); } @@ -1596,9 +1622,9 @@ upb_oneofdef *upb_oneofdef_new(const void *owner) { upb_oneofdef *o = malloc(sizeof(*o)); o->parent = NULL; if (!o) return NULL; - if (!upb_def_init(upb_oneofdef_upcast_mutable(o), UPB_DEF_ONEOF, &vtbl, - owner)) + if (!upb_refcounted_init(upb_oneofdef_upcast_mutable(o), &vtbl, owner)) goto err2; + o->name = NULL; if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2; if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1; return o; @@ -1615,8 +1641,7 @@ upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) { upb_oneof_iter i; upb_oneofdef *newo = upb_oneofdef_new(owner); if (!newo) return NULL; - ok = upb_def_setfullname(upb_oneofdef_upcast_mutable(newo), - upb_def_fullname(upb_oneofdef_upcast(o)), NULL); + ok = upb_oneofdef_setname(newo, upb_oneofdef_name(o), NULL); UPB_ASSERT_VAR(ok, ok); for (upb_oneof_begin(&i, o); !upb_oneof_done(&i); upb_oneof_next(&i)) { upb_fielddef *f = upb_fielddef_dup(upb_oneof_iter_field(&i), &f); @@ -1628,17 +1653,18 @@ upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner) { return newo; } -const char *upb_oneofdef_name(const upb_oneofdef *o) { - return upb_def_fullname(upb_oneofdef_upcast(o)); -} +const char *upb_oneofdef_name(const upb_oneofdef *o) { return o->name; } -bool upb_oneofdef_setname(upb_oneofdef *o, const char *fullname, - upb_status *s) { +bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s) { + assert(!upb_oneofdef_isfrozen(o)); if (upb_oneofdef_containingtype(o)) { upb_status_seterrmsg(s, "oneof already added to a message"); return false; } - return upb_def_setfullname(upb_oneofdef_upcast_mutable(o), fullname, s); + if (!upb_isident(name, strlen(name), true, s)) return false; + free((void*)o->name); + o->name = upb_strdup(name); + return true; } const upb_msgdef *upb_oneofdef_containingtype(const upb_oneofdef *o) { @@ -1757,6 +1783,191 @@ void upb_oneof_iter_setdone(upb_oneof_iter *iter) { upb_inttable_iter_setdone(iter); } +/* upb_filedef ****************************************************************/ + +static void visitfiledef(const upb_refcounted *r, upb_refcounted_visit *visit, + void *closure) { + const upb_filedef *f = (const upb_filedef*)r; + size_t i; + + for(i = 0; i < upb_filedef_defcount(f); i++) { + visit(r, upb_def_upcast(upb_filedef_def(f, i)), closure); + } +} + +static void freefiledef(upb_refcounted *r) { + upb_filedef *f = (upb_filedef*)r; + size_t i; + + for(i = 0; i < upb_filedef_depcount(f); i++) { + upb_filedef_unref(upb_filedef_dep(f, i), f); + } + + upb_inttable_uninit(&f->defs); + upb_inttable_uninit(&f->deps); + free((void*)f->name); + free((void*)f->package); + free(f); +} + +upb_filedef *upb_filedef_new(const void *owner) { + static const struct upb_refcounted_vtbl vtbl = {visitfiledef, freefiledef}; + upb_filedef *f = malloc(sizeof(*f)); + + if (!f) { + return NULL; + } + + f->package = NULL; + f->name = NULL; + f->syntax = UPB_SYNTAX_PROTO2; + + if (!upb_refcounted_init(upb_filedef_upcast_mutable(f), &vtbl, owner)) { + goto err; + } + + if (!upb_inttable_init(&f->defs, UPB_CTYPE_CONSTPTR)) { + goto err; + } + + if (!upb_inttable_init(&f->deps, UPB_CTYPE_CONSTPTR)) { + goto err2; + } + + return f; + + +err2: + upb_inttable_uninit(&f->defs); + +err: + free(f); + return NULL; +} + +const char *upb_filedef_name(const upb_filedef *f) { + return f->name; +} + +const char *upb_filedef_package(const upb_filedef *f) { + return f->package; +} + +upb_syntax_t upb_filedef_syntax(const upb_filedef *f) { + return f->syntax; +} + +size_t upb_filedef_defcount(const upb_filedef *f) { + return upb_inttable_count(&f->defs); +} + +size_t upb_filedef_depcount(const upb_filedef *f) { + return upb_inttable_count(&f->deps); +} + +const upb_def *upb_filedef_def(const upb_filedef *f, size_t i) { + upb_value v; + + if (upb_inttable_lookup32(&f->defs, i, &v)) { + return upb_value_getconstptr(v); + } else { + return NULL; + } +} + +const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i) { + upb_value v; + + if (upb_inttable_lookup32(&f->deps, i, &v)) { + return upb_value_getconstptr(v); + } else { + return NULL; + } +} + +bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s) { + name = upb_strdup(name); + if (!name) { + upb_status_seterrmsg(s, "Out of memory"); + return false; + } + free((void*)f->name); + f->name = name; + return true; +} + +bool upb_filedef_setpackage(upb_filedef *f, const char *package, + upb_status *s) { + if (!upb_isident(package, strlen(package), true, s)) return false; + package = upb_strdup(package); + if (!package) { + upb_status_seterrmsg(s, "Out of memory"); + return false; + } + free((void*)f->package); + f->package = package; + return true; +} + +bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax, + upb_status *s) { + UPB_UNUSED(s); + if (syntax != UPB_SYNTAX_PROTO2 && + syntax != UPB_SYNTAX_PROTO3) { + upb_status_seterrmsg(s, "Unknown syntax value."); + return false; + } + f->syntax = syntax; + + { + /* Set all messages in this file to match. */ + size_t i; + for (i = 0; i < upb_filedef_defcount(f); i++) { + /* Casting const away is safe since all defs in mutable filedef must + * also be mutable. */ + upb_def *def = (upb_def*)upb_filedef_def(f, i); + + upb_msgdef *m = upb_dyncast_msgdef_mutable(def); + if (m) { + m->syntax = syntax; + } + } + } + + return true; +} + +bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor, + upb_status *s) { + if (def->file) { + upb_status_seterrmsg(s, "Def is already part of another filedef."); + return false; + } + + if (upb_inttable_push(&f->defs, upb_value_constptr(def))) { + def->file = f; + upb_ref2(def, f); + if (ref_donor) upb_def_unref(def, ref_donor); + if (def->type == UPB_DEF_MSG) { + upb_downcast_msgdef_mutable(def)->syntax = f->syntax; + } + return true; + } else { + upb_status_seterrmsg(s, "Out of memory."); + return false; + } +} + +bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep) { + if (upb_inttable_push(&f->deps, upb_value_constptr(dep))) { + /* Regular ref instead of ref2 because files can't form cycles. */ + upb_filedef_ref(dep, f); + return true; + } else { + return false; + } +} + #include #include @@ -3550,10 +3761,13 @@ void upb_refcounted_checkref(const upb_refcounted *r, const void *owner) { bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, int maxdepth) { int i; + bool ret; for (i = 0; i < n; i++) { assert(!roots[i]->is_frozen); } - return freeze(roots, n, s, maxdepth); + ret = freeze(roots, n, s, maxdepth); + assert(!s || ret == upb_ok(s)); + return ret; } @@ -3834,11 +4048,16 @@ oom: /* TODO(haberman): we need a lot more testing of error conditions. * The came_from_user stuff in particular is not tested. */ -bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, - upb_status *status) { - int i; +static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, + void *ref_donor, upb_refcounted *freeze_also, + upb_status *status) { + size_t i; + size_t add_n; + size_t freeze_n; upb_strtable_iter iter; + upb_refcounted **add_objs = NULL; upb_def **add_defs = NULL; + size_t add_objs_size; upb_strtable addtab; upb_inttable seen; @@ -3983,15 +4202,38 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, } } - /* We need an array of the defs in addtab, for passing to upb_def_freeze. */ - add_defs = malloc(sizeof(void*) * upb_strtable_count(&addtab)); - if (add_defs == NULL) goto oom_err; - upb_strtable_begin(&iter, &addtab); - for (n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { - add_defs[n++] = upb_value_getptr(upb_strtable_iter_value(&iter)); + /* We need an array of the defs in addtab, for passing to + * upb_refcounted_freeze(). */ + add_objs_size = upb_strtable_count(&addtab); + if (freeze_also) { + add_objs_size++; } - if (!upb_def_freeze(add_defs, n, status)) goto err; + add_defs = malloc(sizeof(void*) * add_objs_size); + if (add_defs == NULL) goto oom_err; + upb_strtable_begin(&iter, &addtab); + for (add_n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { + add_defs[add_n++] = upb_value_getptr(upb_strtable_iter_value(&iter)); + } + + /* Validate defs. */ + if (!_upb_def_validate(add_defs, add_n, status)) { + goto err; + } + + /* Cheat a little and give the array a new type. + * This is probably undefined behavior, but this code will be deleted soon. */ + add_objs = (upb_refcounted**)add_defs; + + freeze_n = add_n; + if (freeze_also) { + add_objs[freeze_n++] = freeze_also; + } + + if (!upb_refcounted_freeze(add_objs, freeze_n, status, + UPB_MAX_MESSAGE_DEPTH * 2)) { + goto err; + } /* This must be delayed until all errors have been detected, since error * recovery code uses this table to cleanup defs. */ @@ -3999,8 +4241,8 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, /* TODO(haberman) we don't properly handle errors after this point (like * OOM in upb_strtable_insert() below). */ - for (i = 0; i < n; i++) { - upb_def *def = add_defs[i]; + for (i = 0; i < add_n; i++) { + upb_def *def = (upb_def*)add_objs[i]; const char *name = upb_def_fullname(def); upb_value v; bool success; @@ -4012,7 +4254,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def)); UPB_ASSERT_VAR(success, success == true); } - free(add_defs); + free(add_objs); return true; oom_err: @@ -4033,11 +4275,40 @@ err: { } } upb_strtable_uninit(&addtab); - free(add_defs); + free(add_objs); assert(!upb_ok(status)); return false; } +bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, + void *ref_donor, upb_status *status) { + return symtab_add(s, defs, n, ref_donor, NULL, status); +} + +bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status *status) { + size_t n; + size_t i; + upb_def **defs; + bool ret; + + n = upb_filedef_defcount(file); + defs = malloc(sizeof(*defs) * n); + + if (defs == NULL) { + upb_status_seterrmsg(status, "Out of memory"); + return false; + } + + for (i = 0; i < n; i++) { + defs[i] = upb_filedef_mutabledef(file, i); + } + + ret = symtab_add(s, defs, n, NULL, upb_filedef_upcast_mutable(file), status); + + free(defs); + return ret; +} + /* Iteration. */ static void advance_to_matching(upb_symtab_iter *iter) { @@ -5037,16 +5308,18 @@ void upb_status_copy(upb_status *to, const upb_status *from) { * Do not edit -- your changes will be discarded when the file is * regenerated. */ +#include + static const upb_msgdef msgs[22]; static const upb_fielddef fields[105]; static const upb_enumdef enums[5]; -static const upb_tabent strentries[268]; +static const upb_tabent strentries[236]; static const upb_tabent intentries[18]; static const upb_tabval arrays[184]; #ifdef UPB_DEBUG_REFS -static upb_inttable reftables[266]; +static upb_inttable reftables[264]; #endif static const upb_msgdef msgs[22] = { @@ -5084,18 +5357,18 @@ static const upb_fielddef fields[105] = { UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "ctype", 1, &msgs[8], (const upb_def*)(&enums[2]), 6, 1, {0},&reftables[56], &reftables[57]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "default_value", 7, &msgs[7], NULL, 16, 7, {0},&reftables[58], &reftables[59]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, false, false, "dependency", 3, &msgs[9], NULL, 30, 8, {0},&reftables[60], &reftables[61]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 1, &msgs[6], NULL, 6, 1, {0},&reftables[62], &reftables[63]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[4], NULL, 7, 2, {0},&reftables[64], &reftables[65]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[17], NULL, 6, 1, {0},&reftables[66], &reftables[67]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[8], NULL, 8, 3, {0},&reftables[68], &reftables[69]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[14], NULL, 6, 1, {0},&reftables[70], &reftables[71]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[12], NULL, 8, 3, {0},&reftables[72], &reftables[73]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 23, &msgs[11], NULL, 21, 10, {0},&reftables[74], &reftables[75]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[12], NULL, 8, 3, {0},&reftables[62], &reftables[63]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[8], NULL, 8, 3, {0},&reftables[64], &reftables[65]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[14], NULL, 6, 1, {0},&reftables[66], &reftables[67]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 23, &msgs[11], NULL, 21, 10, {0},&reftables[68], &reftables[69]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 3, &msgs[4], NULL, 7, 2, {0},&reftables[70], &reftables[71]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 33, &msgs[17], NULL, 6, 1, {0},&reftables[72], &reftables[73]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "deprecated", 1, &msgs[6], NULL, 6, 1, {0},&reftables[74], &reftables[75]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, false, false, "double_value", 6, &msgs[20], NULL, 11, 4, {0},&reftables[76], &reftables[77]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[2], NULL, 3, 1, {0},&reftables[78], &reftables[79]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "end", 2, &msgs[1], NULL, 3, 1, {0},&reftables[80], &reftables[81]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[9], (const upb_def*)(&msgs[3]), 13, 1, {0},&reftables[82], &reftables[83]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], (const upb_def*)(&msgs[3]), 18, 2, {0},&reftables[84], &reftables[85]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 4, &msgs[0], (const upb_def*)(&msgs[3]), 18, 2, {0},&reftables[82], &reftables[83]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "enum_type", 5, &msgs[9], (const upb_def*)(&msgs[3]), 13, 1, {0},&reftables[84], &reftables[85]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "extendee", 2, &msgs[7], NULL, 7, 2, {0},&reftables[86], &reftables[87]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 6, &msgs[0], (const upb_def*)(&msgs[7]), 24, 4, {0},&reftables[88], &reftables[89]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "extension", 7, &msgs[9], (const upb_def*)(&msgs[7]), 19, 3, {0},&reftables[90], &reftables[91]), @@ -5124,32 +5397,32 @@ static const upb_fielddef fields[105] = { UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "message_set_wire_format", 1, &msgs[12], NULL, 6, 1, {0},&reftables[136], &reftables[137]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "message_type", 4, &msgs[9], (const upb_def*)(&msgs[0]), 10, 0, {0},&reftables[138], &reftables[139]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "method", 2, &msgs[16], (const upb_def*)(&msgs[13]), 6, 0, {0},&reftables[140], &reftables[141]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[9], NULL, 22, 6, {0},&reftables[142], &reftables[143]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[5], NULL, 4, 1, {0},&reftables[144], &reftables[145]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[13], NULL, 4, 1, {0},&reftables[146], &reftables[147]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[3], NULL, 8, 2, {0},&reftables[142], &reftables[143]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[15], NULL, 2, 0, {0},&reftables[144], &reftables[145]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[20], (const upb_def*)(&msgs[21]), 5, 0, {0},&reftables[146], &reftables[147]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[0], NULL, 32, 8, {0},&reftables[148], &reftables[149]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[3], NULL, 8, 2, {0},&reftables[150], &reftables[151]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[15], NULL, 2, 0, {0},&reftables[152], &reftables[153]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[16], NULL, 8, 2, {0},&reftables[154], &reftables[155]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[7], NULL, 4, 1, {0},&reftables[156], &reftables[157]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "name", 2, &msgs[20], (const upb_def*)(&msgs[21]), 5, 0, {0},&reftables[158], &reftables[159]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[5], NULL, 4, 1, {0},&reftables[150], &reftables[151]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[9], NULL, 22, 6, {0},&reftables[152], &reftables[153]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[7], NULL, 4, 1, {0},&reftables[154], &reftables[155]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[13], NULL, 4, 1, {0},&reftables[156], &reftables[157]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "name", 1, &msgs[16], NULL, 8, 2, {0},&reftables[158], &reftables[159]), UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, false, false, "name_part", 1, &msgs[21], NULL, 2, 0, {0},&reftables[160], &reftables[161]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, false, false, "negative_int_value", 5, &msgs[20], NULL, 10, 3, {0},&reftables[162], &reftables[163]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "nested_type", 3, &msgs[0], (const upb_def*)(&msgs[0]), 15, 1, {0},&reftables[164], &reftables[165]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "no_standard_descriptor_accessor", 2, &msgs[12], NULL, 7, 2, {0},&reftables[166], &reftables[167]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[7], NULL, 10, 3, {0},&reftables[168], &reftables[169]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[5], NULL, 7, 2, {0},&reftables[170], &reftables[171]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 2, &msgs[5], NULL, 7, 2, {0},&reftables[168], &reftables[169]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "number", 3, &msgs[7], NULL, 10, 3, {0},&reftables[170], &reftables[171]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "objc_class_prefix", 36, &msgs[11], NULL, 24, 13, {0},&reftables[172], &reftables[173]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "oneof_decl", 8, &msgs[0], (const upb_def*)(&msgs[15]), 28, 6, {0},&reftables[174], &reftables[175]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "oneof_index", 9, &msgs[7], NULL, 19, 8, {0},&reftables[176], &reftables[177]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "optimize_for", 9, &msgs[11], (const upb_def*)(&enums[4]), 12, 3, {0},&reftables[178], &reftables[179]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[13], (const upb_def*)(&msgs[14]), 3, 0, {0},&reftables[180], &reftables[181]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[3], (const upb_def*)(&msgs[4]), 7, 1, {0},&reftables[182], &reftables[183]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], (const upb_def*)(&msgs[12]), 25, 5, {0},&reftables[184], &reftables[185]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[5], (const upb_def*)(&msgs[6]), 3, 0, {0},&reftables[186], &reftables[187]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[9], (const upb_def*)(&msgs[11]), 20, 4, {0},&reftables[188], &reftables[189]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[16], (const upb_def*)(&msgs[17]), 7, 1, {0},&reftables[190], &reftables[191]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[7], (const upb_def*)(&msgs[8]), 3, 0, {0},&reftables[192], &reftables[193]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 7, &msgs[0], (const upb_def*)(&msgs[12]), 25, 5, {0},&reftables[180], &reftables[181]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[9], (const upb_def*)(&msgs[11]), 20, 4, {0},&reftables[182], &reftables[183]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 4, &msgs[13], (const upb_def*)(&msgs[14]), 3, 0, {0},&reftables[184], &reftables[185]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 8, &msgs[7], (const upb_def*)(&msgs[8]), 3, 0, {0},&reftables[186], &reftables[187]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[16], (const upb_def*)(&msgs[17]), 7, 1, {0},&reftables[188], &reftables[189]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[5], (const upb_def*)(&msgs[6]), 3, 0, {0},&reftables[190], &reftables[191]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "options", 3, &msgs[3], (const upb_def*)(&msgs[4]), 7, 1, {0},&reftables[192], &reftables[193]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "output_type", 3, &msgs[13], NULL, 10, 3, {0},&reftables[194], &reftables[195]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "package", 2, &msgs[9], NULL, 25, 7, {0},&reftables[196], &reftables[197]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "packed", 2, &msgs[8], NULL, 7, 2, {0},&reftables[198], &reftables[199]), @@ -5163,20 +5436,20 @@ static const upb_fielddef fields[105] = { UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "service", 6, &msgs[9], (const upb_def*)(&msgs[16]), 16, 2, {0},&reftables[214], &reftables[215]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, false, false, "source_code_info", 9, &msgs[9], (const upb_def*)(&msgs[18]), 21, 5, {0},&reftables[216], &reftables[217]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, true, "span", 2, &msgs[19], NULL, 7, 1, {0},&reftables[218], &reftables[219]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 2, 0, {0},&reftables[220], &reftables[221]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[2], NULL, 2, 0, {0},&reftables[222], &reftables[223]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[2], NULL, 2, 0, {0},&reftables[220], &reftables[221]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "start", 1, &msgs[1], NULL, 2, 0, {0},&reftables[222], &reftables[223]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, false, false, "string_value", 7, &msgs[20], NULL, 12, 5, {0},&reftables[224], &reftables[225]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "syntax", 12, &msgs[9], NULL, 39, 11, {0},&reftables[226], &reftables[227]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "trailing_comments", 4, &msgs[19], NULL, 11, 3, {0},&reftables[228], &reftables[229]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, false, false, "type", 5, &msgs[7], (const upb_def*)(&enums[1]), 12, 5, {0},&reftables[230], &reftables[231]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, false, false, "type_name", 6, &msgs[7], NULL, 13, 6, {0},&reftables[232], &reftables[233]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[17], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[234], &reftables[235]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[234], &reftables[235]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[12], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[236], &reftables[237]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[8], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[238], &reftables[239]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[14], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[240], &reftables[241]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[11], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[242], &reftables[243]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[4], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[244], &reftables[245]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[6], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[246], &reftables[247]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[6], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[238], &reftables[239]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[4], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[240], &reftables[241]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[8], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[242], &reftables[243]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[14], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[244], &reftables[245]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "uninterpreted_option", 999, &msgs[17], (const upb_def*)(&msgs[20]), 5, 0, {0},&reftables[246], &reftables[247]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, false, false, "value", 2, &msgs[3], (const upb_def*)(&msgs[5]), 6, 0, {0},&reftables[248], &reftables[249]), UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, false, false, "weak", 10, &msgs[8], NULL, 11, 6, {0},&reftables[250], &reftables[251]), UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, false, false, "weak_dependency", 11, &msgs[9], NULL, 38, 10, {0},&reftables[252], &reftables[253]), @@ -5190,7 +5463,7 @@ static const upb_enumdef enums[5] = { UPB_ENUMDEF_INIT("google.protobuf.FileOptions.OptimizeMode", UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_INT32, 2, &strentries[232]), UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_CSTR, 0, NULL, &arrays[180], 4, 3), 0, &reftables[262], &reftables[263]), }; -static const upb_tabent strentries[268] = { +static const upb_tabent strentries[236] = { {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[22]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "reserved_name"), UPB_TABVALUE_PTR_INIT(&fields[82]), NULL}, @@ -5204,50 +5477,50 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "nested_type"), UPB_TABVALUE_PTR_INIT(&fields[60]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\016", "\000", "\000", "\000", "reserved_range"), UPB_TABVALUE_PTR_INIT(&fields[83]), NULL}, - {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[70]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[68]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "oneof_decl"), UPB_TABVALUE_PTR_INIT(&fields[65]), NULL}, - {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[20]), &strentries[13]}, - {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[88]), NULL}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[19]), &strentries[13]}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[89]), NULL}, {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[18]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[89]), NULL}, + {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "start"), UPB_TABVALUE_PTR_INIT(&fields[88]), NULL}, {UPB_TABKEY_STR("\003", "\000", "\000", "\000", "end"), UPB_TABVALUE_PTR_INIT(&fields[17]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "value"), UPB_TABVALUE_PTR_INIT(&fields[102]), NULL}, - {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[69]), NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[53]), &strentries[26]}, - {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL}, - {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[49]), &strentries[26]}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "allow_alias"), UPB_TABVALUE_PTR_INIT(&fields[1]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[63]), NULL}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[62]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[50]), &strentries[34]}, - {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL}, - {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[9]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[73]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[53]), &strentries[34]}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[15]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "oneof_index"), UPB_TABVALUE_PTR_INIT(&fields[66]), NULL}, {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "label"), UPB_TABVALUE_PTR_INIT(&fields[40]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[56]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[55]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[62]), &strentries[53]}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "number"), UPB_TABVALUE_PTR_INIT(&fields[63]), &strentries[53]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "extendee"), UPB_TABVALUE_PTR_INIT(&fields[21]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "type_name"), UPB_TABVALUE_PTR_INIT(&fields[94]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "json_name"), UPB_TABVALUE_PTR_INIT(&fields[38]), NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "type"), UPB_TABVALUE_PTR_INIT(&fields[93]), &strentries[50]}, {UPB_TABKEY_STR("\015", "\000", "\000", "\000", "default_value"), UPB_TABVALUE_PTR_INIT(&fields[7]), NULL}, - {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[74]), NULL}, - {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[71]), NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "weak"), UPB_TABVALUE_PTR_INIT(&fields[103]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, @@ -5260,13 +5533,13 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "ctype"), UPB_TABVALUE_PTR_INIT(&fields[6]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "jstype"), UPB_TABVALUE_PTR_INIT(&fields[39]), NULL}, - {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[12]), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[10]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "extension"), UPB_TABVALUE_PTR_INIT(&fields[23]), NULL}, {UPB_TABKEY_STR("\017", "\000", "\000", "\000", "weak_dependency"), UPB_TABVALUE_PTR_INIT(&fields[104]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[49]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[54]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "service"), UPB_TABVALUE_PTR_INIT(&fields[85]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "source_code_info"), UPB_TABVALUE_PTR_INIT(&fields[86]), NULL}, @@ -5276,8 +5549,8 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "dependency"), UPB_TABVALUE_PTR_INIT(&fields[8]), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "message_type"), UPB_TABVALUE_PTR_INIT(&fields[47]), NULL}, {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "package"), UPB_TABVALUE_PTR_INIT(&fields[76]), NULL}, - {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[72]), &strentries[86]}, - {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[19]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[69]), &strentries[86]}, + {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "enum_type"), UPB_TABVALUE_PTR_INIT(&fields[20]), NULL}, {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "public_dependency"), UPB_TABVALUE_PTR_INIT(&fields[80]), &strentries[85]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "file"), UPB_TABVALUE_PTR_INIT(&fields[26]), NULL}, @@ -5299,7 +5572,7 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "java_outer_classname"), UPB_TABVALUE_PTR_INIT(&fields[34]), NULL}, - {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, @@ -5312,7 +5585,7 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_STR("\023", "\000", "\000", "\000", "py_generic_services"), UPB_TABVALUE_PTR_INIT(&fields[81]), NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "optimize_for"), UPB_TABVALUE_PTR_INIT(&fields[67]), NULL}, {UPB_TABKEY_STR("\026", "\000", "\000", "\000", "java_string_check_utf8"), UPB_TABVALUE_PTR_INIT(&fields[36]), NULL}, - {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[15]), &strentries[119]}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[12]), &strentries[119]}, {UPB_TABKEY_STR("\021", "\000", "\000", "\000", "objc_class_prefix"), UPB_TABVALUE_PTR_INIT(&fields[64]), NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "cc_enable_arenas"), UPB_TABVALUE_PTR_INIT(&fields[2]), NULL}, {UPB_TABKEY_STR("\027", "\000", "\000", "\000", "message_set_wire_format"), UPB_TABVALUE_PTR_INIT(&fields[46]), &strentries[128]}, @@ -5320,35 +5593,35 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[96]), NULL}, - {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[9]), NULL}, {UPB_TABKEY_STR("\011", "\000", "\000", "\000", "map_entry"), UPB_TABVALUE_PTR_INIT(&fields[45]), NULL}, {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "no_standard_descriptor_accessor"), UPB_TABVALUE_PTR_INIT(&fields[61]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "client_streaming"), UPB_TABVALUE_PTR_INIT(&fields[4]), NULL}, {UPB_TABKEY_STR("\020", "\000", "\000", "\000", "server_streaming"), UPB_TABVALUE_PTR_INIT(&fields[84]), NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[51]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[56]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "input_type"), UPB_TABVALUE_PTR_INIT(&fields[29]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\013", "\000", "\000", "\000", "output_type"), UPB_TABVALUE_PTR_INIT(&fields[75]), NULL}, - {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[68]), NULL}, - {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL}, - {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[54]), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[73]), &strentries[150]}, - {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "method"), UPB_TABVALUE_PTR_INIT(&fields[48]), NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[55]), &strentries[149]}, - {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[70]), NULL}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL}, {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[11]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[50]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_STR("\007", "\000", "\000", "\000", "options"), UPB_TABVALUE_PTR_INIT(&fields[72]), &strentries[150]}, + {UPB_TABKEY_STR("\006", "\000", "\000", "\000", "method"), UPB_TABVALUE_PTR_INIT(&fields[48]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[57]), &strentries[149]}, + {UPB_TABKEY_STR("\024", "\000", "\000", "\000", "uninterpreted_option"), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL}, + {UPB_TABKEY_STR("\012", "\000", "\000", "\000", "deprecated"), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\010", "\000", "\000", "\000", "location"), UPB_TABVALUE_PTR_INIT(&fields[44]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, @@ -5362,7 +5635,7 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "double_value"), UPB_TABVALUE_PTR_INIT(&fields[16]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[57]), NULL}, + {UPB_TABKEY_STR("\004", "\000", "\000", "\000", "name"), UPB_TABVALUE_PTR_INIT(&fields[51]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, @@ -5427,59 +5700,27 @@ static const upb_tabent strentries[268] = { {UPB_TABKEY_STR("\005", "\000", "\000", "\000", "SPEED"), UPB_TABVALUE_INT_INIT(1), &strentries[235]}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_STR("\014", "\000", "\000", "\000", "LITE_RUNTIME"), UPB_TABVALUE_INT_INIT(3), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\047", "\000", "\000", "\000", "google.protobuf.SourceCodeInfo.Location"), UPB_TABVALUE_PTR_INIT(&msgs[19]), NULL}, - {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.UninterpretedOption"), UPB_TABVALUE_PTR_INIT(&msgs[20]), NULL}, - {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.FileDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[9]), NULL}, - {UPB_TABKEY_STR("\045", "\000", "\000", "\000", "google.protobuf.MethodDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[13]), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\040", "\000", "\000", "\000", "google.protobuf.EnumValueOptions"), UPB_TABVALUE_PTR_INIT(&msgs[6]), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_STR("\055", "\000", "\000", "\000", "google.protobuf.DescriptorProto.ReservedRange"), UPB_TABVALUE_PTR_INIT(&msgs[2]), NULL}, - {UPB_TABKEY_STR("\037", "\000", "\000", "\000", "google.protobuf.DescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[0]), &strentries[248]}, - {UPB_TABKEY_STR("\041", "\000", "\000", "\000", "google.protobuf.FileDescriptorSet"), UPB_TABVALUE_PTR_INIT(&msgs[10]), &strentries[267]}, - {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.SourceCodeInfo"), UPB_TABVALUE_PTR_INIT(&msgs[18]), NULL}, - {UPB_TABKEY_STR("\051", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto.Type"), UPB_TABVALUE_PTR_INIT(&enums[1]), NULL}, - {UPB_TABKEY_STR("\056", "\000", "\000", "\000", "google.protobuf.DescriptorProto.ExtensionRange"), UPB_TABVALUE_PTR_INIT(&msgs[1]), NULL}, - {UPB_TABKEY_STR("\044", "\000", "\000", "\000", "google.protobuf.OneofDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[15]), NULL}, - {UPB_TABKEY_STR("\046", "\000", "\000", "\000", "google.protobuf.ServiceDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[16]), NULL}, - {UPB_TABKEY_STR("\034", "\000", "\000", "\000", "google.protobuf.FieldOptions"), UPB_TABVALUE_PTR_INIT(&msgs[8]), NULL}, - {UPB_TABKEY_STR("\033", "\000", "\000", "\000", "google.protobuf.FileOptions"), UPB_TABVALUE_PTR_INIT(&msgs[11]), NULL}, - {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.EnumDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[3]), &strentries[265]}, - {UPB_TABKEY_STR("\052", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto.Label"), UPB_TABVALUE_PTR_INIT(&enums[0]), NULL}, - {UPB_TABKEY_STR("\050", "\000", "\000", "\000", "google.protobuf.FileOptions.OptimizeMode"), UPB_TABVALUE_PTR_INIT(&enums[4]), NULL}, - {UPB_TABKEY_STR("\042", "\000", "\000", "\000", "google.protobuf.FieldOptions.CType"), UPB_TABVALUE_PTR_INIT(&enums[2]), &strentries[261]}, - {UPB_TABKEY_STR("\043", "\000", "\000", "\000", "google.protobuf.FieldOptions.JSType"), UPB_TABVALUE_PTR_INIT(&enums[3]), NULL}, - {UPB_TABKEY_STR("\033", "\000", "\000", "\000", "google.protobuf.EnumOptions"), UPB_TABVALUE_PTR_INIT(&msgs[4]), NULL}, - {UPB_TABKEY_STR("\044", "\000", "\000", "\000", "google.protobuf.FieldDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[7]), NULL}, - {UPB_TABKEY_STR("\050", "\000", "\000", "\000", "google.protobuf.EnumValueDescriptorProto"), UPB_TABVALUE_PTR_INIT(&msgs[5]), &strentries[258]}, - {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.ServiceOptions"), UPB_TABVALUE_PTR_INIT(&msgs[17]), NULL}, - {UPB_TABKEY_STR("\036", "\000", "\000", "\000", "google.protobuf.MessageOptions"), UPB_TABVALUE_PTR_INIT(&msgs[12]), NULL}, - {UPB_TABKEY_STR("\035", "\000", "\000", "\000", "google.protobuf.MethodOptions"), UPB_TABVALUE_PTR_INIT(&msgs[14]), &strentries[253]}, - {UPB_TABKEY_STR("\054", "\000", "\000", "\000", "google.protobuf.UninterpretedOption.NamePart"), UPB_TABVALUE_PTR_INIT(&msgs[21]), NULL}, }; static const upb_tabent intentries[18] = { {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[97]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[99]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[96]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[13]), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[98]), NULL}, - {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[11]), NULL}, {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, - {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[95]), NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[100]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(33), UPB_TABVALUE_PTR_INIT(&fields[14]), NULL}, + {UPB_TABKEY_NONE, UPB_TABVALUE_EMPTY_INIT, NULL}, + {UPB_TABKEY_NUM(999), UPB_TABVALUE_PTR_INIT(&fields[101]), NULL}, }; static const upb_tabval arrays[184] = { @@ -5487,48 +5728,48 @@ static const upb_tabval arrays[184] = { UPB_TABVALUE_PTR_INIT(&fields[52]), UPB_TABVALUE_PTR_INIT(&fields[25]), UPB_TABVALUE_PTR_INIT(&fields[60]), - UPB_TABVALUE_PTR_INIT(&fields[20]), + UPB_TABVALUE_PTR_INIT(&fields[19]), UPB_TABVALUE_PTR_INIT(&fields[24]), UPB_TABVALUE_PTR_INIT(&fields[22]), - UPB_TABVALUE_PTR_INIT(&fields[70]), + UPB_TABVALUE_PTR_INIT(&fields[68]), UPB_TABVALUE_PTR_INIT(&fields[65]), UPB_TABVALUE_PTR_INIT(&fields[83]), UPB_TABVALUE_PTR_INIT(&fields[82]), UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[88]), + UPB_TABVALUE_PTR_INIT(&fields[89]), UPB_TABVALUE_PTR_INIT(&fields[18]), UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[89]), + UPB_TABVALUE_PTR_INIT(&fields[88]), UPB_TABVALUE_PTR_INIT(&fields[17]), UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[53]), + UPB_TABVALUE_PTR_INIT(&fields[49]), UPB_TABVALUE_PTR_INIT(&fields[102]), - UPB_TABVALUE_PTR_INIT(&fields[69]), + UPB_TABVALUE_PTR_INIT(&fields[74]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[1]), - UPB_TABVALUE_PTR_INIT(&fields[10]), + UPB_TABVALUE_PTR_INIT(&fields[13]), UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[50]), - UPB_TABVALUE_PTR_INIT(&fields[63]), - UPB_TABVALUE_PTR_INIT(&fields[71]), - UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[9]), - UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[56]), - UPB_TABVALUE_PTR_INIT(&fields[21]), + UPB_TABVALUE_PTR_INIT(&fields[53]), UPB_TABVALUE_PTR_INIT(&fields[62]), + UPB_TABVALUE_PTR_INIT(&fields[73]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[15]), + UPB_TABVALUE_EMPTY_INIT, + UPB_TABVALUE_PTR_INIT(&fields[55]), + UPB_TABVALUE_PTR_INIT(&fields[21]), + UPB_TABVALUE_PTR_INIT(&fields[63]), UPB_TABVALUE_PTR_INIT(&fields[40]), UPB_TABVALUE_PTR_INIT(&fields[93]), UPB_TABVALUE_PTR_INIT(&fields[94]), UPB_TABVALUE_PTR_INIT(&fields[7]), - UPB_TABVALUE_PTR_INIT(&fields[74]), + UPB_TABVALUE_PTR_INIT(&fields[71]), UPB_TABVALUE_PTR_INIT(&fields[66]), UPB_TABVALUE_PTR_INIT(&fields[38]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[6]), UPB_TABVALUE_PTR_INIT(&fields[77]), - UPB_TABVALUE_PTR_INIT(&fields[12]), + UPB_TABVALUE_PTR_INIT(&fields[10]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[41]), UPB_TABVALUE_PTR_INIT(&fields[39]), @@ -5537,14 +5778,14 @@ static const upb_tabval arrays[184] = { UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[103]), UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[49]), + UPB_TABVALUE_PTR_INIT(&fields[54]), UPB_TABVALUE_PTR_INIT(&fields[76]), UPB_TABVALUE_PTR_INIT(&fields[8]), UPB_TABVALUE_PTR_INIT(&fields[47]), - UPB_TABVALUE_PTR_INIT(&fields[19]), + UPB_TABVALUE_PTR_INIT(&fields[20]), UPB_TABVALUE_PTR_INIT(&fields[85]), UPB_TABVALUE_PTR_INIT(&fields[23]), - UPB_TABVALUE_PTR_INIT(&fields[72]), + UPB_TABVALUE_PTR_INIT(&fields[69]), UPB_TABVALUE_PTR_INIT(&fields[86]), UPB_TABVALUE_PTR_INIT(&fields[80]), UPB_TABVALUE_PTR_INIT(&fields[104]), @@ -5574,7 +5815,7 @@ static const upb_tabval arrays[184] = { UPB_TABVALUE_PTR_INIT(&fields[31]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[15]), + UPB_TABVALUE_PTR_INIT(&fields[12]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, @@ -5593,25 +5834,25 @@ static const upb_tabval arrays[184] = { UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[46]), UPB_TABVALUE_PTR_INIT(&fields[61]), - UPB_TABVALUE_PTR_INIT(&fields[14]), + UPB_TABVALUE_PTR_INIT(&fields[9]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[45]), UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[51]), + UPB_TABVALUE_PTR_INIT(&fields[56]), UPB_TABVALUE_PTR_INIT(&fields[29]), UPB_TABVALUE_PTR_INIT(&fields[75]), - UPB_TABVALUE_PTR_INIT(&fields[68]), + UPB_TABVALUE_PTR_INIT(&fields[70]), UPB_TABVALUE_PTR_INIT(&fields[4]), UPB_TABVALUE_PTR_INIT(&fields[84]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[54]), + UPB_TABVALUE_PTR_INIT(&fields[50]), UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[55]), + UPB_TABVALUE_PTR_INIT(&fields[57]), UPB_TABVALUE_PTR_INIT(&fields[48]), - UPB_TABVALUE_PTR_INIT(&fields[73]), + UPB_TABVALUE_PTR_INIT(&fields[72]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_PTR_INIT(&fields[44]), @@ -5624,7 +5865,7 @@ static const upb_tabval arrays[184] = { UPB_TABVALUE_PTR_INIT(&fields[43]), UPB_TABVALUE_EMPTY_INIT, UPB_TABVALUE_EMPTY_INIT, - UPB_TABVALUE_PTR_INIT(&fields[57]), + UPB_TABVALUE_PTR_INIT(&fields[51]), UPB_TABVALUE_PTR_INIT(&fields[28]), UPB_TABVALUE_PTR_INIT(&fields[79]), UPB_TABVALUE_PTR_INIT(&fields[59]), @@ -5669,17 +5910,8 @@ static const upb_tabval arrays[184] = { UPB_TABVALUE_PTR_INIT("LITE_RUNTIME"), }; -static const upb_symtab symtab = UPB_SYMTAB_INIT(UPB_STRTABLE_INIT(27, 31, UPB_CTYPE_PTR, 5, &strentries[236]), &reftables[264], &reftables[265]); - -const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner) { - upb_symtab_ref(&symtab, owner); - return &symtab; -} - #ifdef UPB_DEBUG_REFS -static upb_inttable reftables[266] = { - UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), - UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), +static upb_inttable reftables[264] = { UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), UPB_EMPTY_INTTABLE_INIT(UPB_CTYPE_PTR), @@ -5947,6 +6179,45 @@ static upb_inttable reftables[266] = { }; #endif +static const upb_msgdef *refm(const upb_msgdef *m, const void *owner) { + upb_msgdef_ref(m, owner); + return m; +} + +static const upb_enumdef *refe(const upb_enumdef *e, const void *owner) { + upb_enumdef_ref(e, owner); + return e; +} + +/* Public API. */ +const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner) { return refm(&msgs[0], owner); } +const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner) { return refm(&msgs[1], owner); } +const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner) { return refm(&msgs[2], owner); } +const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner) { return refm(&msgs[3], owner); } +const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner) { return refm(&msgs[4], owner); } +const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner) { return refm(&msgs[5], owner); } +const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner) { return refm(&msgs[6], owner); } +const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner) { return refm(&msgs[7], owner); } +const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner) { return refm(&msgs[8], owner); } +const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner) { return refm(&msgs[9], owner); } +const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner) { return refm(&msgs[10], owner); } +const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner) { return refm(&msgs[11], owner); } +const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner) { return refm(&msgs[12], owner); } +const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner) { return refm(&msgs[13], owner); } +const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner) { return refm(&msgs[14], owner); } +const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner) { return refm(&msgs[15], owner); } +const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner) { return refm(&msgs[16], owner); } +const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner) { return refm(&msgs[17], owner); } +const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner) { return refm(&msgs[18], owner); } +const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner) { return refm(&msgs[19], owner); } +const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner) { return refm(&msgs[20], owner); } +const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner) { return refm(&msgs[21], owner); } + +const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner) { return refe(&enums[0], owner); } +const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner) { return refe(&enums[1], owner); } +const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner) { return refe(&enums[2], owner); } +const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner) { return refe(&enums[3], owner); } +const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner) { return refe(&enums[4], owner); } /* ** XXX: The routines in this file that consume a string do not currently ** support having the string span buffers. In the future, as upb_sink and @@ -5965,15 +6236,6 @@ static bool upb_streq(const char *str, const char *buf, size_t n) { return strlen(str) == n && memcmp(str, buf, n) == 0; } -/* upb_deflist is an internal-only dynamic array for storing a growing list of - * upb_defs. */ -typedef struct { - upb_def **defs; - size_t len; - size_t size; - bool owned; -} upb_deflist; - /* We keep a stack of all the messages scopes we are currently in, as well as * the top-level file scope. This is necessary to correctly qualify the * definitions that are contained inside. "name" tracks the name of the @@ -5999,13 +6261,11 @@ typedef struct { struct upb_descreader { upb_sink sink; - upb_deflist defs; + upb_inttable files; + upb_filedef *file; /* The last file in files. */ upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING]; int stack_len; - bool primitives_have_presence; - int file_start; - uint32_t number; char *name; bool saw_number; @@ -6042,53 +6302,11 @@ static char *upb_join(const char *base, const char *name) { } } - -/* upb_deflist ****************************************************************/ - -void upb_deflist_init(upb_deflist *l) { - l->size = 0; - l->defs = NULL; - l->len = 0; - l->owned = true; -} - -void upb_deflist_uninit(upb_deflist *l) { - size_t i; - if (l->owned) - for(i = 0; i < l->len; i++) - upb_def_unref(l->defs[i], l); - free(l->defs); -} - -bool upb_deflist_push(upb_deflist *l, upb_def *d) { - if(++l->len >= l->size) { - size_t new_size = UPB_MAX(l->size, 4); - new_size *= 2; - l->defs = realloc(l->defs, new_size * sizeof(void *)); - if (!l->defs) return false; - l->size = new_size; - } - l->defs[l->len - 1] = d; - return true; -} - -void upb_deflist_donaterefs(upb_deflist *l, void *owner) { - size_t i; - assert(l->owned); - for (i = 0; i < l->len; i++) - upb_def_donateref(l->defs[i], l, owner); - l->owned = false; -} - -static upb_def *upb_deflist_last(upb_deflist *l) { - return l->defs[l->len-1]; -} - /* Qualify the defname for all defs starting with offset "start" with "str". */ -static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) { - uint32_t i; - for (i = start; i < l->len; i++) { - upb_def *def = l->defs[i]; +static void upb_descreader_qualify(upb_filedef *f, char *str, int32_t start) { + size_t i; + for (i = start; i < upb_filedef_defcount(f); i++) { + upb_def *def = upb_filedef_mutabledef(f, i); char *name = upb_join(str, upb_def_fullname(def)); upb_def_setfullname(def, name, NULL); free(name); @@ -6103,24 +6321,24 @@ static upb_msgdef *upb_descreader_top(upb_descreader *r) { assert(r->stack_len > 1); index = r->stack[r->stack_len-1].start - 1; assert(index >= 0); - return upb_downcast_msgdef_mutable(r->defs.defs[index]); + return upb_downcast_msgdef_mutable(upb_filedef_mutabledef(r->file, index)); } static upb_def *upb_descreader_last(upb_descreader *r) { - return upb_deflist_last(&r->defs); + return upb_filedef_mutabledef(r->file, upb_filedef_defcount(r->file) - 1); } /* Start/end handlers for FileDescriptorProto and DescriptorProto (the two * entities that have names and can contain sub-definitions. */ void upb_descreader_startcontainer(upb_descreader *r) { upb_descreader_frame *f = &r->stack[r->stack_len++]; - f->start = r->defs.len; + f->start = upb_filedef_defcount(r->file); f->name = NULL; } void upb_descreader_endcontainer(upb_descreader *r) { upb_descreader_frame *f = &r->stack[--r->stack_len]; - upb_deflist_qualify(&r->defs, f->name, f->start); + upb_descreader_qualify(r->file, f->name, f->start); free(f->name); f->name = NULL; } @@ -6131,17 +6349,26 @@ void upb_descreader_setscopename(upb_descreader *r, char *str) { f->name = str; } -/* Handlers for google.protobuf.FileDescriptorProto. */ -static bool file_startmsg(void *closure, const void *hd) { +/** Handlers for google.protobuf.FileDescriptorSet. ***************************/ + +static void *fileset_startfile(void *closure, const void *hd) { + upb_descreader *r = closure; + UPB_UNUSED(hd); + r->file = upb_filedef_new(&r->files); + upb_inttable_push(&r->files, upb_value_ptr(r->file)); + return r; +} + +/** Handlers for google.protobuf.FileDescriptorProto. *************************/ + +static bool file_start(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_descreader_startcontainer(r); - r->primitives_have_presence = true; - r->file_start = r->defs.len; return true; } -static bool file_endmsg(void *closure, const void *hd, upb_status *status) { +static bool file_end(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(status); @@ -6149,46 +6376,86 @@ static bool file_endmsg(void *closure, const void *hd, upb_status *status) { return true; } +static size_t file_onname(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + upb_descreader *r = closure; + char *name; + bool ok; + UPB_UNUSED(hd); + UPB_UNUSED(handle); + + name = upb_strndup(buf, n); + /* XXX: see comment at the top of the file. */ + ok = upb_filedef_setname(r->file, name, NULL); + UPB_ASSERT_VAR(ok, ok); + return n; +} + static size_t file_onpackage(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; + char *package; + bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); + + package = upb_strndup(buf, n); /* XXX: see comment at the top of the file. */ - upb_descreader_setscopename(r, upb_strndup(buf, n)); + upb_descreader_setscopename(r, package); + ok = upb_filedef_setpackage(r->file, package, NULL); + UPB_ASSERT_VAR(ok, ok); return n; } static size_t file_onsyntax(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; + bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ if (upb_streq("proto2", buf, n)) { - /* Technically we could verify that proto3 hadn't previously been seen. */ + ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO2, NULL); } else if (upb_streq("proto3", buf, n)) { - uint32_t i; - /* Update messages created before the syntax was read. */ - for (i = r->file_start; i < r->defs.len; i++) { - upb_msgdef *m = upb_dyncast_msgdef_mutable(r->defs.defs[i]); - if (m) { - upb_msgdef_setprimitiveshavepresence(m, false); - } - } - - /* Set a flag for any future messages that will be created. */ - r->primitives_have_presence = false; + ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO3, NULL); } else { - /* Error: neither proto3 nor proto3. - * TODO(haberman): there should be a status object we can report this to. */ - return 0; + ok = false; } + UPB_ASSERT_VAR(ok, ok); return n; } -/* Handlers for google.protobuf.EnumValueDescriptorProto. */ +static void *file_startmsg(void *closure, const void *hd) { + upb_descreader *r = closure; + upb_msgdef *m = upb_msgdef_new(&m); + bool ok = upb_filedef_addmsg(r->file, m, &m, NULL); + UPB_UNUSED(hd); + UPB_ASSERT_VAR(ok, ok); + return r; +} + +static void *file_startenum(void *closure, const void *hd) { + upb_descreader *r = closure; + upb_enumdef *e = upb_enumdef_new(&e); + bool ok = upb_filedef_addenum(r->file, e, &e, NULL); + UPB_UNUSED(hd); + UPB_ASSERT_VAR(ok, ok); + return r; +} + +static void *file_startext(void *closure, const void *hd) { + upb_descreader *r = closure; + bool ok; + r->f = upb_fielddef_new(r); + ok = upb_filedef_addext(r->file, r->f, r, NULL); + UPB_UNUSED(hd); + UPB_ASSERT_VAR(ok, ok); + return r; +} + +/** Handlers for google.protobuf.EnumValueDescriptorProto. *********************/ + static bool enumval_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); @@ -6233,15 +6500,7 @@ static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) { return true; } - -/* Handlers for google.protobuf.EnumDescriptorProto. */ -static bool enum_startmsg(void *closure, const void *hd) { - upb_descreader *r = closure; - UPB_UNUSED(hd); - upb_deflist_push(&r->defs, - upb_enumdef_upcast_mutable(upb_enumdef_new(&r->defs))); - return true; -} +/** Handlers for google.protobuf.EnumDescriptorProto. *************************/ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; @@ -6272,11 +6531,12 @@ static size_t enum_onname(void *closure, const void *hd, const char *buf, return n; } -/* Handlers for google.protobuf.FieldDescriptorProto */ +/** Handlers for google.protobuf.FieldDescriptorProto *************************/ + static bool field_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); - r->f = upb_fielddef_new(&r->defs); + assert(r->f); free(r->default_string); r->default_string = NULL; @@ -6419,9 +6679,10 @@ static bool field_onlabel(void *closure, const void *hd, int32_t val) { static bool field_onnumber(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; - bool ok = upb_fielddef_setnumber(r->f, val, NULL); + bool ok; UPB_UNUSED(hd); + ok = upb_fielddef_setnumber(r->f, val, NULL); UPB_ASSERT_VAR(ok, ok); return true; } @@ -6479,20 +6740,17 @@ static size_t field_ondefaultval(void *closure, const void *hd, const char *buf, return n; } -/* Handlers for google.protobuf.DescriptorProto (representing a message). */ -static bool msg_startmsg(void *closure, const void *hd) { +/** Handlers for google.protobuf.DescriptorProto ******************************/ + +static bool msg_start(void *closure, const void *hd) { upb_descreader *r = closure; - upb_msgdef *m; UPB_UNUSED(hd); - m = upb_msgdef_new(&r->defs); - upb_msgdef_setprimitiveshavepresence(m, r->primitives_have_presence); - upb_deflist_push(&r->defs, upb_msgdef_upcast_mutable(m)); upb_descreader_startcontainer(r); return true; } -static bool msg_endmsg(void *closure, const void *hd, upb_status *status) { +static bool msg_end(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); UPB_UNUSED(hd); @@ -6505,8 +6763,8 @@ static bool msg_endmsg(void *closure, const void *hd, upb_status *status) { return true; } -static size_t msg_onname(void *closure, const void *hd, const char *buf, - size_t n, const upb_bufhandle *handle) { +static size_t msg_name(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); /* XXX: see comment at the top of the file. */ @@ -6519,89 +6777,130 @@ static size_t msg_onname(void *closure, const void *hd, const char *buf, return n; } -static bool msg_onendfield(void *closure, const void *hd) { +static void *msg_startmsg(void *closure, const void *hd) { + upb_descreader *r = closure; + upb_msgdef *m = upb_msgdef_new(&m); + bool ok = upb_filedef_addmsg(r->file, m, &m, NULL); + UPB_UNUSED(hd); + UPB_ASSERT_VAR(ok, ok); + return r; +} + +static void *msg_startext(void *closure, const void *hd) { + upb_descreader *r = closure; + upb_fielddef *f = upb_fielddef_new(&f); + bool ok = upb_filedef_addext(r->file, f, &f, NULL); + UPB_UNUSED(hd); + UPB_ASSERT_VAR(ok, ok); + return r; +} + +static void *msg_startfield(void *closure, const void *hd) { + upb_descreader *r = closure; + r->f = upb_fielddef_new(&r->f); + /* We can't add the new field to the message until its name/number are + * filled in. */ + UPB_UNUSED(hd); + return r; +} + +static bool msg_endfield(void *closure, const void *hd) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); UPB_UNUSED(hd); - upb_msgdef_addfield(m, r->f, &r->defs, NULL); + upb_msgdef_addfield(m, r->f, &r->f, NULL); r->f = NULL; return true; } -static bool pushextension(void *closure, const void *hd) { - upb_descreader *r = closure; - UPB_UNUSED(hd); - assert(upb_fielddef_containingtypename(r->f)); - upb_fielddef_setisextension(r->f, true); - upb_deflist_push(&r->defs, upb_fielddef_upcast_mutable(r->f)); - r->f = NULL; - return true; -} +/** Code to register handlers *************************************************/ -#define D(name) upbdefs_google_protobuf_ ## name(s) +#define F(msg, field) upbdefs_google_protobuf_ ## msg ## _f_ ## field(m) static void reghandlers(const void *closure, upb_handlers *h) { - const upb_symtab *s = closure; const upb_msgdef *m = upb_handlers_msgdef(h); + UPB_UNUSED(closure); - if (m == D(DescriptorProto)) { - upb_handlers_setstartmsg(h, &msg_startmsg, NULL); - upb_handlers_setendmsg(h, &msg_endmsg, NULL); - upb_handlers_setstring(h, D(DescriptorProto_name), &msg_onname, NULL); - upb_handlers_setendsubmsg(h, D(DescriptorProto_field), &msg_onendfield, - NULL); - upb_handlers_setendsubmsg(h, D(DescriptorProto_extension), &pushextension, - NULL); - } else if (m == D(FileDescriptorProto)) { - upb_handlers_setstartmsg(h, &file_startmsg, NULL); - upb_handlers_setendmsg(h, &file_endmsg, NULL); - upb_handlers_setstring(h, D(FileDescriptorProto_package), &file_onpackage, + if (upbdefs_google_protobuf_FileDescriptorSet_is(m)) { + upb_handlers_setstartsubmsg(h, F(FileDescriptorSet, file), + &fileset_startfile, NULL); + } else if (upbdefs_google_protobuf_DescriptorProto_is(m)) { + upb_handlers_setstartmsg(h, &msg_start, NULL); + upb_handlers_setendmsg(h, &msg_end, NULL); + upb_handlers_setstring(h, F(DescriptorProto, name), &msg_name, NULL); + upb_handlers_setstartsubmsg(h, F(DescriptorProto, extension), &msg_startext, + NULL); + upb_handlers_setstartsubmsg(h, F(DescriptorProto, nested_type), + &msg_startmsg, NULL); + upb_handlers_setstartsubmsg(h, F(DescriptorProto, field), + &msg_startfield, NULL); + upb_handlers_setendsubmsg(h, F(DescriptorProto, field), + &msg_endfield, NULL); + upb_handlers_setstartsubmsg(h, F(DescriptorProto, enum_type), + &file_startenum, NULL); + } else if (upbdefs_google_protobuf_FileDescriptorProto_is(m)) { + upb_handlers_setstartmsg(h, &file_start, NULL); + upb_handlers_setendmsg(h, &file_end, NULL); + upb_handlers_setstring(h, F(FileDescriptorProto, name), &file_onname, NULL); - upb_handlers_setstring(h, D(FileDescriptorProto_syntax), &file_onsyntax, + upb_handlers_setstring(h, F(FileDescriptorProto, package), &file_onpackage, NULL); - upb_handlers_setendsubmsg(h, D(FileDescriptorProto_extension), &pushextension, - NULL); - } else if (m == D(EnumValueDescriptorProto)) { + upb_handlers_setstring(h, F(FileDescriptorProto, syntax), &file_onsyntax, + NULL); + upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, message_type), + &file_startmsg, NULL); + upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, enum_type), + &file_startenum, NULL); + upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, extension), + &file_startext, NULL); + } else if (upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &enumval_startmsg, NULL); upb_handlers_setendmsg(h, &enumval_endmsg, NULL); - upb_handlers_setstring(h, D(EnumValueDescriptorProto_name), &enumval_onname, NULL); - upb_handlers_setint32(h, D(EnumValueDescriptorProto_number), &enumval_onnumber, + upb_handlers_setstring(h, F(EnumValueDescriptorProto, name), &enumval_onname, NULL); + upb_handlers_setint32(h, F(EnumValueDescriptorProto, number), &enumval_onnumber, NULL); - } else if (m == D(EnumDescriptorProto)) { - upb_handlers_setstartmsg(h, &enum_startmsg, NULL); + } else if (upbdefs_google_protobuf_EnumDescriptorProto_is(m)) { upb_handlers_setendmsg(h, &enum_endmsg, NULL); - upb_handlers_setstring(h, D(EnumDescriptorProto_name), &enum_onname, NULL); - } else if (m == D(FieldDescriptorProto)) { + upb_handlers_setstring(h, F(EnumDescriptorProto, name), &enum_onname, NULL); + } else if (upbdefs_google_protobuf_FieldDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &field_startmsg, NULL); upb_handlers_setendmsg(h, &field_endmsg, NULL); - upb_handlers_setint32(h, D(FieldDescriptorProto_type), &field_ontype, + upb_handlers_setint32(h, F(FieldDescriptorProto, type), &field_ontype, NULL); - upb_handlers_setint32(h, D(FieldDescriptorProto_label), &field_onlabel, + upb_handlers_setint32(h, F(FieldDescriptorProto, label), &field_onlabel, NULL); - upb_handlers_setint32(h, D(FieldDescriptorProto_number), &field_onnumber, + upb_handlers_setint32(h, F(FieldDescriptorProto, number), &field_onnumber, NULL); - upb_handlers_setstring(h, D(FieldDescriptorProto_name), &field_onname, + upb_handlers_setstring(h, F(FieldDescriptorProto, name), &field_onname, NULL); - upb_handlers_setstring(h, D(FieldDescriptorProto_type_name), + upb_handlers_setstring(h, F(FieldDescriptorProto, type_name), &field_ontypename, NULL); - upb_handlers_setstring(h, D(FieldDescriptorProto_extendee), + upb_handlers_setstring(h, F(FieldDescriptorProto, extendee), &field_onextendee, NULL); - upb_handlers_setstring(h, D(FieldDescriptorProto_default_value), + upb_handlers_setstring(h, F(FieldDescriptorProto, default_value), &field_ondefaultval, NULL); - } else if (m == D(FieldOptions)) { - upb_handlers_setbool(h, D(FieldOptions_lazy), &field_onlazy, NULL); - upb_handlers_setbool(h, D(FieldOptions_packed), &field_onpacked, NULL); + } else if (upbdefs_google_protobuf_FieldOptions_is(m)) { + upb_handlers_setbool(h, F(FieldOptions, lazy), &field_onlazy, NULL); + upb_handlers_setbool(h, F(FieldOptions, packed), &field_onpacked, NULL); } + + assert(upb_ok(upb_handlers_status(h))); } -#undef D +#undef F void descreader_cleanup(void *_r) { upb_descreader *r = _r; + size_t i; + + for (i = 0; i < upb_descreader_filecount(r); i++) { + upb_filedef_unref(upb_descreader_file(r, i), &r->files); + } + free(r->name); - upb_deflist_uninit(&r->defs); + upb_inttable_uninit(&r->files); free(r->default_string); while (r->stack_len > 0) { upb_descreader_frame *f = &r->stack[--r->stack_len]; @@ -6618,7 +6917,7 @@ upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) { return NULL; } - upb_deflist_init(&r->defs); + upb_inttable_init(&r->files, UPB_CTYPE_PTR); upb_sink_reset(upb_descreader_input(r), h, r); r->stack_len = 0; r->name = NULL; @@ -6627,10 +6926,17 @@ upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) { return r; } -upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n) { - *n = r->defs.len; - upb_deflist_donaterefs(&r->defs, owner); - return r->defs.defs; +size_t upb_descreader_filecount(const upb_descreader *r) { + return upb_inttable_count(&r->files); +} + +upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i) { + upb_value v; + if (upb_inttable_lookup(&r->files, i, &v)) { + return upb_value_getptr(v); + } else { + return NULL; + } } upb_sink *upb_descreader_input(upb_descreader *r) { @@ -6638,10 +6944,9 @@ upb_sink *upb_descreader_input(upb_descreader *r) { } const upb_handlers *upb_descreader_newhandlers(const void *owner) { - const upb_symtab *s = upbdefs_google_protobuf_descriptor(&s); - const upb_handlers *h = upb_handlers_newfrozen( - upbdefs_google_protobuf_FileDescriptorSet(s), owner, reghandlers, s); - upb_symtab_unref(s, &s); + const upb_msgdef *m = upbdefs_google_protobuf_FileDescriptorSet_get(&m); + const upb_handlers *h = upb_handlers_newfrozen(m, owner, reghandlers, NULL); + upb_msgdef_unref(m, &m); return h; } /* @@ -9281,8 +9586,8 @@ upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; } #include #include -upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, - void *owner, upb_status *status) { +upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner, + upb_status *status) { /* Create handlers. */ const upb_pbdecodermethod *decoder_m; const upb_handlers *reader_h = upb_descreader_newhandlers(&reader_h); @@ -9291,8 +9596,8 @@ upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, upb_pbdecoder *decoder; upb_descreader *reader; bool ok; - upb_def **ret = NULL; - upb_def **defs; + size_t i; + upb_filedef **ret = NULL; upb_pbdecodermethodopts_init(&opts, reader_h); decoder_m = upb_pbdecodermethod_new(&opts, &decoder_m); @@ -9304,12 +9609,24 @@ upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, decoder = upb_pbdecoder_create(&env, decoder_m, upb_descreader_input(reader)); /* Push input data. */ - ok = upb_bufsrc_putbuf(str, len, upb_pbdecoder_input(decoder)); + ok = upb_bufsrc_putbuf(buf, n, upb_pbdecoder_input(decoder)); - if (!ok) goto cleanup; - defs = upb_descreader_getdefs(reader, owner, n); - ret = malloc(sizeof(upb_def*) * (*n)); - memcpy(ret, defs, sizeof(upb_def*) * (*n)); + if (!ok) { + goto cleanup; + } + + ret = malloc(sizeof (*ret) * (upb_descreader_filecount(reader) + 1)); + + if (!ret) { + goto cleanup; + } + + for (i = 0; i < upb_descreader_filecount(reader); i++) { + ret[i] = upb_descreader_file(reader, i); + upb_filedef_ref(ret[i], owner); + } + + ret[i] = NULL; cleanup: upb_env_uninit(&env); @@ -9317,51 +9634,6 @@ cleanup: upb_pbdecodermethod_unref(decoder_m, &decoder_m); return ret; } - -bool upb_load_descriptor_into_symtab(upb_symtab *s, const char *str, size_t len, - upb_status *status) { - int n; - bool success; - upb_def **defs = upb_load_defs_from_descriptor(str, len, &n, &defs, status); - if (!defs) return false; - success = upb_symtab_add(s, defs, n, &defs, status); - free(defs); - return success; -} - -char *upb_readfile(const char *filename, size_t *len) { - long size; - char *buf; - FILE *f = fopen(filename, "rb"); - if(!f) return NULL; - if(fseek(f, 0, SEEK_END) != 0) goto error; - size = ftell(f); - if(size < 0) goto error; - if(fseek(f, 0, SEEK_SET) != 0) goto error; - buf = malloc(size + 1); - if(size && fread(buf, size, 1, f) != 1) goto error; - fclose(f); - if (len) *len = size; - return buf; - -error: - fclose(f); - return NULL; -} - -bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname, - upb_status *status) { - size_t len; - bool success; - char *data = upb_readfile(fname, &len); - if (!data) { - if (status) upb_status_seterrf(status, "Couldn't read file: %s", fname); - return false; - } - success = upb_load_descriptor_into_symtab(symtab, data, len, status); - free(data); - return success; -} /* * upb::pb::TextPrinter * @@ -11452,14 +11724,24 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { !upb_msg_field_done(&i); upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); + size_t field_len = upb_fielddef_getjsonname(f, buf, len); if (field_len > len) { + size_t len2; buf = realloc(buf, field_len); len = field_len; - upb_fielddef_getjsonname(f, buf, len); + len2 = upb_fielddef_getjsonname(f, buf, len); + UPB_ASSERT_VAR(len2, len == len2); } upb_strtable_insert(t, buf, upb_value_constptr(f)); + if (getenv("UPB_JSON_ACCEPT_LEGACY_FIELD_NAMES")) { + /* Temporary code to help people migrate if they were depending on the + * old, non-proto3-json-compliant field names. In this case we + * recognize both old names and new names. */ + upb_strtable_insert(t, upb_fielddef_name(f), upb_value_constptr(f)); + } + if (upb_fielddef_issubmsg(f)) { add_jsonname_table(m, upb_fielddef_msgsubdef(f)); } @@ -11574,12 +11856,19 @@ void freestrpc(void *ptr) { strpc *newstrpc(upb_handlers *h, const upb_fielddef *f) { /* TODO(haberman): handle malloc failure. */ strpc *ret = malloc(sizeof(*ret)); - size_t len; - ret->len = upb_fielddef_getjsonname(f, NULL, 0); - ret->ptr = malloc(ret->len); - len = upb_fielddef_getjsonname(f, ret->ptr, ret->len); - UPB_ASSERT_VAR(len, len == ret->len); - ret->len--; /* NULL */ + if (getenv("UPB_JSON_WRITE_LEGACY_FIELD_NAMES")) { + /* Temporary code to help people migrate if they were depending on the + * old, non-proto3-json-compliant field names. */ + ret->ptr = upb_strdup(upb_fielddef_name(f)); + ret->len = strlen(ret->ptr); + } else { + size_t len; + ret->len = upb_fielddef_getjsonname(f, NULL, 0); + ret->ptr = malloc(ret->len); + len = upb_fielddef_getjsonname(f, ret->ptr, ret->len); + UPB_ASSERT_VAR(len, len == ret->len); + ret->len--; /* NULL */ + } upb_handlers_addcleanup(h, ret, freestrpc); return ret; diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h index 0be5b296..6cea1068 100644 --- a/ruby/ext/google/protobuf_c/upb.h +++ b/ruby/ext/google/protobuf_c/upb.h @@ -5,6 +5,7 @@ ** ** - upb::MessageDef (upb_msgdef): describes a "message" construct. ** - upb::FieldDef (upb_fielddef): describes a message field. +** - upb::FileDef (upb_filedef): describes a .proto file and its defs. ** - upb::EnumDef (upb_enumdef): describes an enum. ** - upb::OneofDef (upb_oneofdef): describes a oneof. ** - upb::Def (upb_def): base class of all the others. @@ -365,6 +366,11 @@ template class reffed_ptr { if (ptr_) ptr_->Ref(this); } + reffed_ptr(const reffed_ptr& other) + : ptr_(upb::upcast(other.get())) { + if (ptr_) ptr_->Ref(this); + } + ~reffed_ptr() { if (ptr_) ptr_->Unref(this); } template @@ -1265,12 +1271,17 @@ namespace upb { class Def; class EnumDef; class FieldDef; +class FileDef; class MessageDef; class OneofDef; } #endif UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted) +UPB_DECLARE_DERIVED_TYPE(upb::OneofDef, upb::RefCounted, upb_oneofdef, + upb_refcounted) +UPB_DECLARE_DERIVED_TYPE(upb::FileDef, upb::RefCounted, upb_filedef, + upb_refcounted) /* The maximum message depth that the type graph can have. This is a resource * limit for the C stack since we sometimes need to recursively traverse the @@ -1282,15 +1293,16 @@ UPB_DECLARE_DERIVED_TYPE(upb::Def, upb::RefCounted, upb_def, upb_refcounted) #define UPB_MAX_MESSAGE_DEPTH 64 -/* upb::Def: base class for defs *********************************************/ +/* upb::Def: base class for top-level defs ***********************************/ -/* All the different kind of defs we support. These correspond 1:1 with - * declarations in a .proto file. */ +/* All the different kind of defs that can be defined at the top-level and put + * in a SymbolTable or appear in a FileDef::defs() list. This excludes some + * defs (like oneofs and files). It only includes fields because they can be + * defined as extensions. */ typedef enum { UPB_DEF_MSG, UPB_DEF_FIELD, UPB_DEF_ENUM, - UPB_DEF_ONEOF, UPB_DEF_SERVICE, /* Not yet implemented. */ UPB_DEF_ANY = -1 /* Wildcard for upb_symtab_get*() */ } upb_deftype_t; @@ -1313,6 +1325,9 @@ class upb::Def { /* "fullname" is the def's fully-qualified name (eg. foo.bar.Message). */ const char *full_name() const; + /* The final part of a def's name (eg. Message). */ + const char *name() const; + /* The def must be mutable. Caller retains ownership of fullname. Defs are * not required to have a name; if a def has no name when it is frozen, it * will remain an anonymous def. On failure, returns false and details in "s" @@ -1320,6 +1335,11 @@ class upb::Def { bool set_full_name(const char* fullname, upb::Status* s); bool set_full_name(const std::string &fullname, upb::Status* s); + /* The file in which this def appears. It is not necessary to add a def to a + * file (and consequently the accessor may return NULL). Set this by calling + * file->Add(def). */ + FileDef* file() const; + /* Freezes the given defs; this validates all constraints and marks the defs * as frozen (read-only). "defs" may not contain any fielddefs, but fields * of any msgdefs will be frozen. @@ -1331,7 +1351,7 @@ class upb::Def { * * After this operation succeeds, the finalized defs must only be accessed * through a const pointer! */ - static bool Freeze(Def* const* defs, int n, Status* status); + static bool Freeze(Def* const* defs, size_t n, Status* status); static bool Freeze(const std::vector& defs, Status* status); private: @@ -1350,8 +1370,13 @@ UPB_REFCOUNTED_CMETHODS(upb_def, upb_def_upcast) upb_deftype_t upb_def_type(const upb_def *d); const char *upb_def_fullname(const upb_def *d); +const char *upb_def_name(const upb_def *d); +const upb_filedef *upb_def_file(const upb_def *d); bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s); -bool upb_def_freeze(upb_def *const *defs, int n, upb_status *s); +bool upb_def_freeze(upb_def *const *defs, size_t n, upb_status *s); + +/* Temporary API: for internal use only. */ +bool _upb_def_validate(upb_def *const*defs, size_t n, upb_status *s); UPB_END_EXTERN_C @@ -1424,7 +1449,6 @@ UPB_END_EXTERN_C UPB_DECLARE_DEF_TYPE(upb::FieldDef, fielddef, FIELD) UPB_DECLARE_DEF_TYPE(upb::MessageDef, msgdef, MSG) UPB_DECLARE_DEF_TYPE(upb::EnumDef, enumdef, ENUM) -UPB_DECLARE_DEF_TYPE(upb::OneofDef, oneofdef, ONEOF) #undef UPB_DECLARE_DEF_TYPE #undef UPB_DEF_CASTS @@ -1582,7 +1606,7 @@ class upb::FieldDef { * whatever message this field belongs to. Guaranteed to be less than * f->containing_type()->field_count(). May only be accessed once the def has * been finalized. */ - int index() const; + uint32_t index() const; /* The MessageDef to which this field belongs. * @@ -1893,6 +1917,7 @@ class upb::MessageDef { /* Functionality from upb::Def. */ const char* full_name() const; + const char* name() const; bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); @@ -2126,6 +2151,7 @@ UPB_REFCOUNTED_CMETHODS(upb_msgdef, upb_msgdef_upcast2) bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status); const char *upb_msgdef_fullname(const upb_msgdef *m); +const char *upb_msgdef_name(const upb_msgdef *m); bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s); upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner); @@ -2133,7 +2159,6 @@ bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor, upb_status *s); bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, upb_status *s); -void upb_msgdef_setprimitiveshavepresence(upb_msgdef *m, bool have_presence); /* Field lookup in a couple of different variations: * - itof = int to field @@ -2232,6 +2257,7 @@ class upb::EnumDef { /* Functionality from upb::Def. */ const char* full_name() const; + const char* name() const; bool set_full_name(const char* fullname, Status* s); bool set_full_name(const std::string& fullname, Status* s); @@ -2306,6 +2332,7 @@ bool upb_enumdef_freeze(upb_enumdef *e, upb_status *status); /* From upb_def. */ const char *upb_enumdef_fullname(const upb_enumdef *e); +const char *upb_enumdef_name(const upb_enumdef *e); bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, upb_status *s); @@ -2347,8 +2374,7 @@ typedef upb_inttable_iter upb_oneof_iter; #ifdef __cplusplus -/* Class that represents a oneof. Its base class is upb::Def (convert with - * upb::upcast()). */ +/* Class that represents a oneof. */ class upb::OneofDef { public: /* Returns NULL if memory allocation failed. */ @@ -2357,9 +2383,6 @@ class upb::OneofDef { /* upb::RefCounted methods like Ref()/Unref(). */ UPB_REFCOUNTED_CPPMETHODS - /* Functionality from upb::Def. */ - const char* full_name() const; - /* Returns the MessageDef that owns this OneofDef. */ const MessageDef* containing_type() const; @@ -2367,6 +2390,7 @@ class upb::OneofDef { * by name once added to a message def. */ const char* name() const; bool set_name(const char* name, Status* s); + bool set_name(const std::string& name, Status* s); /* Returns the number of fields currently defined in the oneof. */ int field_count() const; @@ -2460,7 +2484,7 @@ upb_oneofdef *upb_oneofdef_new(const void *owner); upb_oneofdef *upb_oneofdef_dup(const upb_oneofdef *o, const void *owner); /* Include upb_refcounted methods like upb_oneofdef_ref(). */ -UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast2) +UPB_REFCOUNTED_CMETHODS(upb_oneofdef, upb_oneofdef_upcast) const char *upb_oneofdef_name(const upb_oneofdef *o); bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s); @@ -2496,6 +2520,125 @@ void upb_oneof_iter_setdone(upb_oneof_iter *iter); UPB_END_EXTERN_C + +/* upb::FileDef ***************************************************************/ + +typedef enum { + UPB_SYNTAX_PROTO2 = 2, + UPB_SYNTAX_PROTO3 = 3 +} upb_syntax_t; + +#ifdef __cplusplus + +/* Class that represents a .proto file with some things defined in it. + * + * Many users won't care about FileDefs, but they are necessary if you want to + * read the values of file-level options. */ +class upb::FileDef { + public: + /* Returns NULL if memory allocation failed. */ + static reffed_ptr New(); + + /* upb::RefCounted methods like Ref()/Unref(). */ + UPB_REFCOUNTED_CPPMETHODS + + /* Get/set name of the file (eg. "foo/bar.proto"). */ + const char* name() const; + bool set_name(const char* name, Status* s); + bool set_name(const std::string& name, Status* s); + + /* Package name for definitions inside the file (eg. "foo.bar"). */ + const char* package() const; + bool set_package(const char* package, Status* s); + + /* Syntax for the file. Defaults to proto2. */ + upb_syntax_t syntax() const; + void set_syntax(upb_syntax_t syntax); + + /* Get the list of defs from the file. These are returned in the order that + * they were added to the FileDef. */ + int def_count() const; + const Def* def(int index) const; + Def* def(int index); + + /* Get the list of dependencies from the file. These are returned in the + * order that they were added to the FileDef. */ + int dependency_count() const; + const FileDef* dependency(int index) const; + + /* Adds defs to this file. The def must not already belong to another + * file. + * + * Note: this does *not* ensure that this def's name is unique in this file! + * Use a SymbolTable if you want to check this property. Especially since + * properly checking uniqueness would require a check across *all* files + * (including dependencies). */ + bool AddDef(Def* def, Status* s); + bool AddMessage(MessageDef* m, Status* s); + bool AddEnum(EnumDef* e, Status* s); + bool AddExtension(FieldDef* f, Status* s); + + /* Adds a dependency of this file. */ + bool AddDependency(const FileDef* file); + + /* Freezes this FileDef and all messages/enums under it. All subdefs must be + * resolved and all messages/enums must validate. Returns true if this + * succeeded. + * + * TODO(haberman): should we care whether the file's dependencies are frozen + * already? */ + bool Freeze(Status* s); + + private: + UPB_DISALLOW_POD_OPS(FileDef, upb::FileDef) +}; + +#endif + +UPB_BEGIN_EXTERN_C + +upb_filedef *upb_filedef_new(const void *owner); + +/* Include upb_refcounted methods like upb_msgdef_ref(). */ +UPB_REFCOUNTED_CMETHODS(upb_filedef, upb_filedef_upcast) + +const char *upb_filedef_name(const upb_filedef *f); +const char *upb_filedef_package(const upb_filedef *f); +upb_syntax_t upb_filedef_syntax(const upb_filedef *f); +size_t upb_filedef_defcount(const upb_filedef *f); +size_t upb_filedef_depcount(const upb_filedef *f); +const upb_def *upb_filedef_def(const upb_filedef *f, size_t i); +const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i); + +bool upb_filedef_freeze(upb_filedef *f, upb_status *s); +bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s); +bool upb_filedef_setpackage(upb_filedef *f, const char *package, upb_status *s); +bool upb_filedef_setsyntax(upb_filedef *f, upb_syntax_t syntax, upb_status *s); + +bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor, + upb_status *s); +bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep); + +UPB_INLINE bool upb_filedef_addmsg(upb_filedef *f, upb_msgdef *m, + const void *ref_donor, upb_status *s) { + return upb_filedef_adddef(f, upb_msgdef_upcast_mutable(m), ref_donor, s); +} + +UPB_INLINE bool upb_filedef_addenum(upb_filedef *f, upb_enumdef *e, + const void *ref_donor, upb_status *s) { + return upb_filedef_adddef(f, upb_enumdef_upcast_mutable(e), ref_donor, s); +} + +UPB_INLINE bool upb_filedef_addext(upb_filedef *file, upb_fielddef *f, + const void *ref_donor, upb_status *s) { + return upb_filedef_adddef(file, upb_fielddef_upcast_mutable(f), ref_donor, s); +} +UPB_INLINE upb_def *upb_filedef_mutabledef(upb_filedef *f, int i) { + return (upb_def*)upb_filedef_def(f, i); +} + +UPB_END_EXTERN_C + #ifdef __cplusplus UPB_INLINE const char* upb_safecstr(const std::string& str) { @@ -2511,13 +2654,14 @@ inline Def* Def::Dup(const void* owner) const { } inline Def::Type Def::def_type() const { return upb_def_type(this); } inline const char* Def::full_name() const { return upb_def_fullname(this); } +inline const char* Def::name() const { return upb_def_name(this); } inline bool Def::set_full_name(const char* fullname, Status* s) { return upb_def_setfullname(this, fullname, s); } inline bool Def::set_full_name(const std::string& fullname, Status* s) { return upb_def_setfullname(this, upb_safecstr(fullname), s); } -inline bool Def::Freeze(Def* const* defs, int n, Status* status) { +inline bool Def::Freeze(Def* const* defs, size_t n, Status* status) { return upb_def_freeze(defs, n, status); } inline bool Def::Freeze(const std::vector& defs, Status* status) { @@ -2596,6 +2740,9 @@ inline void FieldDef::set_lazy(bool lazy) { inline bool FieldDef::packed() const { return upb_fielddef_packed(this); } +inline uint32_t FieldDef::index() const { + return upb_fielddef_index(this); +} inline void FieldDef::set_packed(bool packed) { upb_fielddef_setpacked(this, packed); } @@ -2740,6 +2887,9 @@ inline reffed_ptr MessageDef::New() { inline const char *MessageDef::full_name() const { return upb_msgdef_fullname(this); } +inline const char *MessageDef::name() const { + return upb_msgdef_name(this); +} inline bool MessageDef::set_full_name(const char* fullname, Status* s) { return upb_msgdef_setfullname(this, fullname, s); } @@ -2927,6 +3077,9 @@ inline reffed_ptr EnumDef::New() { inline const char* EnumDef::full_name() const { return upb_enumdef_fullname(this); } +inline const char* EnumDef::name() const { + return upb_enumdef_name(this); +} inline bool EnumDef::set_full_name(const char* fullname, Status* s) { return upb_enumdef_setfullname(this, fullname, s); } @@ -2976,9 +3129,6 @@ inline reffed_ptr OneofDef::New() { upb_oneofdef *o = upb_oneofdef_new(&o); return reffed_ptr(o, &o); } -inline const char* OneofDef::full_name() const { - return upb_oneofdef_name(this); -} inline const MessageDef* OneofDef::containing_type() const { return upb_oneofdef_containingtype(this); @@ -2989,6 +3139,9 @@ inline const char* OneofDef::name() const { inline bool OneofDef::set_name(const char* name, Status* s) { return upb_oneofdef_setname(this, name, s); } +inline bool OneofDef::set_name(const std::string& name, Status* s) { + return upb_oneofdef_setname(this, upb_safecstr(name), s); +} inline int OneofDef::field_count() const { return upb_oneofdef_numfields(this); } @@ -3057,6 +3210,57 @@ inline bool OneofDef::const_iterator::operator!=( return !(*this == other); } +inline reffed_ptr FileDef::New() { + upb_filedef *f = upb_filedef_new(&f); + return reffed_ptr(f, &f); +} + +inline const char* FileDef::name() const { + return upb_filedef_name(this); +} +inline bool FileDef::set_name(const char* name, Status* s) { + return upb_filedef_setname(this, name, s); +} +inline bool FileDef::set_name(const std::string& name, Status* s) { + return upb_filedef_setname(this, upb_safecstr(name), s); +} +inline const char* FileDef::package() const { + return upb_filedef_package(this); +} +inline bool FileDef::set_package(const char* package, Status* s) { + return upb_filedef_setpackage(this, package, s); +} +inline int FileDef::def_count() const { + return upb_filedef_defcount(this); +} +inline const Def* FileDef::def(int index) const { + return upb_filedef_def(this, index); +} +inline Def* FileDef::def(int index) { + return const_cast(upb_filedef_def(this, index)); +} +inline int FileDef::dependency_count() const { + return upb_filedef_depcount(this); +} +inline const FileDef* FileDef::dependency(int index) const { + return upb_filedef_dep(this, index); +} +inline bool FileDef::AddDef(Def* def, Status* s) { + return upb_filedef_adddef(this, def, NULL, s); +} +inline bool FileDef::AddMessage(MessageDef* m, Status* s) { + return upb_filedef_addmsg(this, m, NULL, s); +} +inline bool FileDef::AddEnum(EnumDef* e, Status* s) { + return upb_filedef_addenum(this, e, NULL, s); +} +inline bool FileDef::AddExtension(FieldDef* f, Status* s) { + return upb_filedef_addext(this, f, NULL, s); +} +inline bool FileDef::AddDependency(const FileDef* file) { + return upb_filedef_adddep(this, file); +} + } /* namespace upb */ #endif @@ -3095,6 +3299,7 @@ struct upb_def { upb_refcounted base; const char *fullname; + const upb_filedef* file; char type; /* A upb_deftype_t (char to save space) */ /* Used as a flag during the def's mutable stage. Must be false unless @@ -3105,7 +3310,7 @@ struct upb_def { }; #define UPB_DEF_INIT(name, type, refs, ref2s) \ - { UPB_REFCOUNT_INIT(refs, ref2s), name, type, false } + { UPB_REFCOUNT_INIT(refs, ref2s), name, NULL, type, false } /* upb_fielddef ***************************************************************/ @@ -3176,10 +3381,10 @@ struct upb_msgdef { * descriptor.upb.c. */ bool map_entry; - /* Do primitive values in this message have explicit presence or not? + /* Whether this message has proto2 or proto3 semantics. * TODO: set this flag properly for static descriptors; regenerate * descriptor.upb.c. */ - bool primitives_have_presence; + upb_syntax_t syntax; /* TODO(haberman): proper extension ranges (there can be multiple). */ }; @@ -3212,15 +3417,16 @@ struct upb_enumdef { /* upb_oneofdef ***************************************************************/ struct upb_oneofdef { - upb_def base; + upb_refcounted base; + const char *name; upb_strtable ntof; upb_inttable itof; const upb_msgdef *parent; }; #define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \ - { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntof, itof } + { UPB_REFCOUNT_INIT(refs, ref2s), name, ntof, itof } /* upb_symtab *****************************************************************/ @@ -3234,6 +3440,16 @@ struct upb_symtab { #define UPB_SYMTAB_INIT(symtab, refs, ref2s) \ { UPB_REFCOUNT_INIT(refs, ref2s), symtab } +struct upb_filedef { + upb_refcounted base; + + const char *name; + const char *package; + upb_syntax_t syntax; + + upb_inttable defs; + upb_inttable deps; +}; #endif /* UPB_STATICINIT_H_ */ /* @@ -6140,12 +6356,17 @@ class upb::SymbolTable { * only a few messages are changing. We may want to add a way of adding a * tree of frozen defs to the symtab (perhaps an alternate constructor where * you pass the root of the tree?) */ - bool Add(Def*const* defs, int n, void* ref_donor, upb_status* status); + bool Add(Def*const* defs, size_t n, void* ref_donor, Status* status); bool Add(const std::vector& defs, void *owner, Status* status) { return Add((Def*const*)&defs[0], defs.size(), owner, status); } + /* Resolves all subdefs for messages in this file and attempts to freeze the + * file. If this succeeds, adds all the symbols to this SymbolTable + * (replacing any existing ones with the same names). */ + bool AddFile(FileDef* file, Status* s); + private: UPB_DISALLOW_POD_OPS(SymbolTable, upb::SymbolTable) }; @@ -6166,8 +6387,9 @@ const upb_def *upb_symtab_resolve(const upb_symtab *s, const char *base, const upb_def *upb_symtab_lookup(const upb_symtab *s, const char *sym); const upb_msgdef *upb_symtab_lookupmsg(const upb_symtab *s, const char *sym); const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym); -bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, - upb_status *status); +bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, + void *ref_donor, upb_status *status); +bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status* status); /* upb_symtab_iter i; * for(upb_symtab_begin(&i, s, type); !upb_symtab_done(&i); @@ -6209,9 +6431,12 @@ inline const MessageDef *SymbolTable::LookupMessage(const char *sym) const { return upb_symtab_lookupmsg(this, sym); } inline bool SymbolTable::Add( - Def*const* defs, int n, void* ref_donor, upb_status* status) { + Def*const* defs, size_t n, void* ref_donor, Status* status) { return upb_symtab_add(this, (upb_def*const*)defs, n, ref_donor, status); } +inline bool SymbolTable::AddFile(FileDef* file, Status* s) { + return upb_symtab_addfile(this, file, s); +} } /* namespace upb */ #endif @@ -6255,14 +6480,9 @@ class upb::descriptor::Reader { /* The reader's input; this is where descriptor.proto data should be sent. */ Sink* input(); - /* Returns an array of all defs that have been parsed, and transfers ownership - * of them to "owner". The number of defs is stored in *n. Ownership of the - * returned array is retained and is invalidated by any other call into - * Reader. - * - * These defs are not frozen or resolved; they are ready to be added to a - * symtab. */ - upb::Def** GetDefs(void* owner, int* n); + /* Use to get the FileDefs that have been parsed. */ + size_t file_count() const; + FileDef* file(size_t i) const; /* Builds and returns handlers for the reader, owned by "owner." */ static Handlers* NewHandlers(const void* owner); @@ -6278,7 +6498,8 @@ UPB_BEGIN_EXTERN_C /* C API. */ upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h); upb_sink *upb_descreader_input(upb_descreader *r); -upb_def **upb_descreader_getdefs(upb_descreader *r, void *owner, int *n); +size_t upb_descreader_filecount(const upb_descreader *r); +upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i); const upb_handlers *upb_descreader_newhandlers(const void *owner); UPB_END_EXTERN_C @@ -6291,8 +6512,11 @@ inline Reader* Reader::Create(Environment* e, const Handlers *h) { return upb_descreader_create(e, h); } inline Sink* Reader::input() { return upb_descreader_input(this); } -inline upb::Def** Reader::GetDefs(void* owner, int* n) { - return upb_descreader_getdefs(this, owner, n); +inline size_t Reader::file_count() const { + return upb_descreader_filecount(this); +} +inline FileDef* Reader::file(size_t i) const { + return upb_descreader_file(this, i); } } /* namespace descriptor */ } /* namespace upb */ @@ -6309,610 +6533,282 @@ inline upb::Def** Reader::GetDefs(void* owner, int* n) { * Do not edit -- your changes will be discarded when the file is * regenerated. */ -#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_ -#define GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_ +#ifndef UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ +#define UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ -#ifdef __cplusplus UPB_BEGIN_EXTERN_C -#endif /* Enums */ typedef enum { - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_OPTIONAL = 1, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED = 2, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REPEATED = 3 + google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL = 1, + google_protobuf_FieldDescriptorProto_LABEL_REQUIRED = 2, + google_protobuf_FieldDescriptorProto_LABEL_REPEATED = 3 } google_protobuf_FieldDescriptorProto_Label; typedef enum { - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_DOUBLE = 1, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FLOAT = 2, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT64 = 3, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT64 = 4, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 = 5, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED64 = 6, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIXED32 = 7, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BOOL = 8, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_STRING = 9, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_GROUP = 10, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_MESSAGE = 11, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_BYTES = 12, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_UINT32 = 13, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ENUM = 14, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED32 = 15, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SFIXED64 = 16, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT32 = 17, - GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_SINT64 = 18 + google_protobuf_FieldDescriptorProto_TYPE_DOUBLE = 1, + google_protobuf_FieldDescriptorProto_TYPE_FLOAT = 2, + google_protobuf_FieldDescriptorProto_TYPE_INT64 = 3, + google_protobuf_FieldDescriptorProto_TYPE_UINT64 = 4, + google_protobuf_FieldDescriptorProto_TYPE_INT32 = 5, + google_protobuf_FieldDescriptorProto_TYPE_FIXED64 = 6, + google_protobuf_FieldDescriptorProto_TYPE_FIXED32 = 7, + google_protobuf_FieldDescriptorProto_TYPE_BOOL = 8, + google_protobuf_FieldDescriptorProto_TYPE_STRING = 9, + google_protobuf_FieldDescriptorProto_TYPE_GROUP = 10, + google_protobuf_FieldDescriptorProto_TYPE_MESSAGE = 11, + google_protobuf_FieldDescriptorProto_TYPE_BYTES = 12, + google_protobuf_FieldDescriptorProto_TYPE_UINT32 = 13, + google_protobuf_FieldDescriptorProto_TYPE_ENUM = 14, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED32 = 15, + google_protobuf_FieldDescriptorProto_TYPE_SFIXED64 = 16, + google_protobuf_FieldDescriptorProto_TYPE_SINT32 = 17, + google_protobuf_FieldDescriptorProto_TYPE_SINT64 = 18 } google_protobuf_FieldDescriptorProto_Type; typedef enum { - GOOGLE_PROTOBUF_FIELDOPTIONS_STRING = 0, - GOOGLE_PROTOBUF_FIELDOPTIONS_CORD = 1, - GOOGLE_PROTOBUF_FIELDOPTIONS_STRING_PIECE = 2 + google_protobuf_FieldOptions_STRING = 0, + google_protobuf_FieldOptions_CORD = 1, + google_protobuf_FieldOptions_STRING_PIECE = 2 } google_protobuf_FieldOptions_CType; typedef enum { - GOOGLE_PROTOBUF_FIELDOPTIONS_JS_NORMAL = 0, - GOOGLE_PROTOBUF_FIELDOPTIONS_JS_STRING = 1, - GOOGLE_PROTOBUF_FIELDOPTIONS_JS_NUMBER = 2 + google_protobuf_FieldOptions_JS_NORMAL = 0, + google_protobuf_FieldOptions_JS_STRING = 1, + google_protobuf_FieldOptions_JS_NUMBER = 2 } google_protobuf_FieldOptions_JSType; typedef enum { - GOOGLE_PROTOBUF_FILEOPTIONS_SPEED = 1, - GOOGLE_PROTOBUF_FILEOPTIONS_CODE_SIZE = 2, - GOOGLE_PROTOBUF_FILEOPTIONS_LITE_RUNTIME = 3 + google_protobuf_FileOptions_SPEED = 1, + google_protobuf_FileOptions_CODE_SIZE = 2, + google_protobuf_FileOptions_LITE_RUNTIME = 3 } google_protobuf_FileOptions_OptimizeMode; -/* Selectors */ +/* MessageDefs: call these functions to get a ref to a msgdef. */ +const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_EnumOptions_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_FieldOptions_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_FileOptions_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_MessageOptions_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_MethodOptions_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_ServiceOptions_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_get(const void *owner); +const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart_get(const void *owner); -/* google.protobuf.DescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSUBMSG 3 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 4 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSUBMSG 6 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_STARTSUBMSG 7 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ONEOF_DECL_STARTSUBMSG 8 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_RANGE_STARTSUBMSG 9 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_STARTSEQ 10 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSEQ 11 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_ENDSUBMSG 12 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_STARTSEQ 13 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSEQ 14 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_ENDSUBMSG 15 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 16 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 17 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 18 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_STARTSEQ 19 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSEQ 20 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_RANGE_ENDSUBMSG 21 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_STARTSEQ 22 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSEQ 23 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSION_ENDSUBMSG 24 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_OPTIONS_ENDSUBMSG 25 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ONEOF_DECL_STARTSEQ 26 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ONEOF_DECL_ENDSEQ 27 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_ONEOF_DECL_ENDSUBMSG 28 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_RANGE_STARTSEQ 29 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_RANGE_ENDSEQ 30 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_RANGE_ENDSUBMSG 31 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STRING 32 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_STARTSTR 33 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_ENDSTR 34 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_NAME_STARTSEQ 35 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_NAME_ENDSEQ 36 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_NAME_STRING 37 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_NAME_STARTSTR 38 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVED_NAME_ENDSTR 39 +/* EnumDefs: call these functions to get a ref to an enumdef. */ +const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label_get(const void *owner); +const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type_get(const void *owner); +const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType_get(const void *owner); +const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType_get(const void *owner); +const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode_get(const void *owner); -/* google.protobuf.DescriptorProto.ExtensionRange */ -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_START_INT32 2 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_EXTENSIONRANGE_END_INT32 3 - -/* google.protobuf.DescriptorProto.ReservedRange */ -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVEDRANGE_START_INT32 2 -#define SEL_GOOGLE_PROTOBUF_DESCRIPTORPROTO_RESERVEDRANGE_END_INT32 3 - -/* google.protobuf.EnumDescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_STARTSEQ 4 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSEQ 5 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_ENDSUBMSG 6 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STRING 8 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_STARTSTR 9 -#define SEL_GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_ENDSTR 10 - -/* google.protobuf.EnumOptions */ -#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_ALLOW_ALIAS_BOOL 6 -#define SEL_GOOGLE_PROTOBUF_ENUMOPTIONS_DEPRECATED_BOOL 7 - -/* google.protobuf.EnumValueDescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STRING 4 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_STARTSTR 5 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_ENDSTR 6 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_INT32 7 - -/* google.protobuf.EnumValueOptions */ -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_ENUMVALUEOPTIONS_DEPRECATED_BOOL 6 - -/* google.protobuf.FieldDescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STRING 4 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_STARTSTR 5 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_ENDSTR 6 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STRING 7 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_STARTSTR 8 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_EXTENDEE_ENDSTR 9 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_INT32 10 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_INT32 11 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_INT32 12 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STRING 13 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_STARTSTR 14 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_ENDSTR 15 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STRING 16 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_STARTSTR 17 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_DEFAULT_VALUE_ENDSTR 18 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_ONEOF_INDEX_INT32 19 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_JSON_NAME_STRING 20 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_JSON_NAME_STARTSTR 21 -#define SEL_GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_JSON_NAME_ENDSTR 22 - -/* google.protobuf.FieldOptions */ -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_CTYPE_INT32 6 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_PACKED_BOOL 7 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_DEPRECATED_BOOL 8 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_LAZY_BOOL 9 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_JSTYPE_INT32 10 -#define SEL_GOOGLE_PROTOBUF_FIELDOPTIONS_WEAK_BOOL 11 - -/* google.protobuf.FileDescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSUBMSG 3 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSUBMSG 4 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 6 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_STARTSUBMSG 7 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_STARTSEQ 8 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSEQ 9 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_ENDSUBMSG 10 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_STARTSEQ 11 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSEQ 12 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_ENDSUBMSG 13 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_STARTSEQ 14 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSEQ 15 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SERVICE_ENDSUBMSG 16 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_STARTSEQ 17 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSEQ 18 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_EXTENSION_ENDSUBMSG 19 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 20 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SOURCE_CODE_INFO_ENDSUBMSG 21 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STRING 22 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_STARTSTR 23 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_NAME_ENDSTR 24 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STRING 25 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_STARTSTR 26 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_ENDSTR 27 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSEQ 28 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSEQ 29 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STRING 30 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_STARTSTR 31 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_DEPENDENCY_ENDSTR 32 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_STARTSEQ 33 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_ENDSEQ 34 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PUBLIC_DEPENDENCY_INT32 35 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_STARTSEQ 36 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_ENDSEQ 37 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_WEAK_DEPENDENCY_INT32 38 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SYNTAX_STRING 39 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SYNTAX_STARTSTR 40 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_SYNTAX_ENDSTR 41 - -/* google.protobuf.FileDescriptorSet */ -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_ENDSUBMSG 5 - -/* google.protobuf.FileOptions */ -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STRING 6 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_STARTSTR 7 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_PACKAGE_ENDSTR 8 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STRING 9 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_STARTSTR 10 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_OUTER_CLASSNAME_ENDSTR 11 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_OPTIMIZE_FOR_INT32 12 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_MULTIPLE_FILES_BOOL 13 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STRING 14 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_STARTSTR 15 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_GO_PACKAGE_ENDSTR 16 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CC_GENERIC_SERVICES_BOOL 17 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERIC_SERVICES_BOOL 18 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_PY_GENERIC_SERVICES_BOOL 19 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_GENERATE_EQUALS_AND_HASH_BOOL 20 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_DEPRECATED_BOOL 21 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVA_STRING_CHECK_UTF8_BOOL 22 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CC_ENABLE_ARENAS_BOOL 23 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_OBJC_CLASS_PREFIX_STRING 24 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_OBJC_CLASS_PREFIX_STARTSTR 25 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_OBJC_CLASS_PREFIX_ENDSTR 26 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CSHARP_NAMESPACE_STRING 27 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CSHARP_NAMESPACE_STARTSTR 28 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_CSHARP_NAMESPACE_ENDSTR 29 -#define SEL_GOOGLE_PROTOBUF_FILEOPTIONS_JAVANANO_USE_DEPRECATED_PACKAGE_BOOL 30 - -/* google.protobuf.MessageOptions */ -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_MESSAGE_SET_WIRE_FORMAT_BOOL 6 -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_NO_STANDARD_DESCRIPTOR_ACCESSOR_BOOL 7 -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_DEPRECATED_BOOL 8 -#define SEL_GOOGLE_PROTOBUF_MESSAGEOPTIONS_MAP_ENTRY_BOOL 9 - -/* google.protobuf.MethodDescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 3 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STRING 4 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_STARTSTR 5 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_NAME_ENDSTR 6 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STRING 7 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_STARTSTR 8 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_INPUT_TYPE_ENDSTR 9 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STRING 10 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_STARTSTR 11 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_OUTPUT_TYPE_ENDSTR 12 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_CLIENT_STREAMING_BOOL 13 -#define SEL_GOOGLE_PROTOBUF_METHODDESCRIPTORPROTO_SERVER_STREAMING_BOOL 14 - -/* google.protobuf.MethodOptions */ -#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_METHODOPTIONS_DEPRECATED_BOOL 6 - -/* google.protobuf.OneofDescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_ONEOFDESCRIPTORPROTO_NAME_STRING 2 -#define SEL_GOOGLE_PROTOBUF_ONEOFDESCRIPTORPROTO_NAME_STARTSTR 3 -#define SEL_GOOGLE_PROTOBUF_ONEOFDESCRIPTORPROTO_NAME_ENDSTR 4 - -/* google.protobuf.ServiceDescriptorProto */ -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_STARTSUBMSG 3 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_STARTSEQ 4 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSEQ 5 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_METHOD_ENDSUBMSG 6 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_OPTIONS_ENDSUBMSG 7 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STRING 8 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_STARTSTR 9 -#define SEL_GOOGLE_PROTOBUF_SERVICEDESCRIPTORPROTO_NAME_ENDSTR 10 - -/* google.protobuf.ServiceOptions */ -#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_UNINTERPRETED_OPTION_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_SERVICEOPTIONS_DEPRECATED_BOOL 6 - -/* google.protobuf.SourceCodeInfo */ -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_ENDSUBMSG 5 - -/* google.protobuf.SourceCodeInfo.Location */ -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_STARTSEQ 2 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_ENDSEQ 3 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_PATH_INT32 4 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_STARTSEQ 5 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_ENDSEQ 6 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_SPAN_INT32 7 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STRING 8 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_STARTSTR 9 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_COMMENTS_ENDSTR 10 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STRING 11 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_STARTSTR 12 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_TRAILING_COMMENTS_ENDSTR 13 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_DETACHED_COMMENTS_STARTSEQ 14 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_DETACHED_COMMENTS_ENDSEQ 15 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_DETACHED_COMMENTS_STRING 16 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_DETACHED_COMMENTS_STARTSTR 17 -#define SEL_GOOGLE_PROTOBUF_SOURCECODEINFO_LOCATION_LEADING_DETACHED_COMMENTS_ENDSTR 18 - -/* google.protobuf.UninterpretedOption */ -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSUBMSG 2 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_STARTSEQ 3 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSEQ 4 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAME_ENDSUBMSG 5 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STRING 6 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_STARTSTR 7 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_IDENTIFIER_VALUE_ENDSTR 8 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_POSITIVE_INT_VALUE_UINT64 9 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NEGATIVE_INT_VALUE_INT64 10 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_DOUBLE_VALUE_DOUBLE 11 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STRING 12 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_STARTSTR 13 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_STRING_VALUE_ENDSTR 14 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STRING 15 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_STARTSTR 16 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_AGGREGATE_VALUE_ENDSTR 17 - -/* google.protobuf.UninterpretedOption.NamePart */ -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STRING 2 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_STARTSTR 3 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_NAME_PART_ENDSTR 4 -#define SEL_GOOGLE_PROTOBUF_UNINTERPRETEDOPTION_NAMEPART_IS_EXTENSION_BOOL 5 - -const upb_symtab *upbdefs_google_protobuf_descriptor(const void *owner); - -/* MessageDefs */ -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto"); - assert(m); - return m; +/* Functions to test whether this message is of a certain type. */ +UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ExtensionRange"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ExtensionRange") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_DescriptorProto_ReservedRange(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.DescriptorProto.ReservedRange"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.DescriptorProto.ReservedRange") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumDescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumDescriptorProto"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_EnumDescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumDescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumOptions(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumOptions"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_EnumOptions_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumOptions") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueDescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueDescriptorProto"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_EnumValueDescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueDescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_EnumValueOptions(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.EnumValueOptions"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_EnumValueOptions_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.EnumValueOptions") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldDescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldDescriptorProto"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldDescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FieldOptions(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FieldOptions"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.FieldOptions") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorProto"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileDescriptorSet(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileDescriptorSet"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_FileDescriptorSet_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileDescriptorSet") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_FileOptions(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.FileOptions"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_FileOptions_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.FileOptions") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MessageOptions(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MessageOptions"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_MessageOptions_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.MessageOptions") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodDescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodDescriptorProto"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_MethodDescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodDescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_MethodOptions(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.MethodOptions"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_MethodOptions_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.MethodOptions") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_OneofDescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.OneofDescriptorProto"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_OneofDescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.OneofDescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceDescriptorProto(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceDescriptorProto"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_ServiceDescriptorProto_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceDescriptorProto") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_ServiceOptions(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.ServiceOptions"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_ServiceOptions_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.ServiceOptions") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_SourceCodeInfo_Location(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.SourceCodeInfo.Location"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_SourceCodeInfo_Location_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.SourceCodeInfo.Location") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption") == 0; } -UPB_INLINE const upb_msgdef *upbdefs_google_protobuf_UninterpretedOption_NamePart(const upb_symtab *s) { - const upb_msgdef *m = upb_symtab_lookupmsg(s, "google.protobuf.UninterpretedOption.NamePart"); - assert(m); - return m; +UPB_INLINE bool upbdefs_google_protobuf_UninterpretedOption_NamePart_is(const upb_msgdef *m) { + return strcmp(upb_msgdef_fullname(m), "google.protobuf.UninterpretedOption.NamePart") == 0; +} + +/* Functions to test whether this enum is of a certain type. */ +UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Label_is(const upb_enumdef *e) { + return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Label") == 0; +} +UPB_INLINE bool upbdefs_google_protobuf_FieldDescriptorProto_Type_is(const upb_enumdef *e) { + return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldDescriptorProto.Type") == 0; +} +UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_CType_is(const upb_enumdef *e) { + return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.CType") == 0; +} +UPB_INLINE bool upbdefs_google_protobuf_FieldOptions_JSType_is(const upb_enumdef *e) { + return strcmp(upb_enumdef_fullname(e), "google.protobuf.FieldOptions.JSType") == 0; +} +UPB_INLINE bool upbdefs_google_protobuf_FileOptions_OptimizeMode_is(const upb_enumdef *e) { + return strcmp(upb_enumdef_fullname(e), "google.protobuf.FileOptions.OptimizeMode") == 0; } -/* EnumDefs */ -UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Label(const upb_symtab *s) { - const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Label"); - assert(e); - return e; -} -UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldDescriptorProto_Type(const upb_symtab *s) { - const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldDescriptorProto.Type"); - assert(e); - return e; -} -UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldOptions_CType(const upb_symtab *s) { - const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldOptions.CType"); - assert(e); - return e; -} -UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FieldOptions_JSType(const upb_symtab *s) { - const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FieldOptions.JSType"); - assert(e); - return e; -} -UPB_INLINE const upb_enumdef *upbdefs_google_protobuf_FileOptions_OptimizeMode(const upb_symtab *s) { - const upb_enumdef *e = upb_symtab_lookupenum(s, "google.protobuf.FileOptions.OptimizeMode"); - assert(e); - return e; -} - -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ExtensionRange(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_end(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ReservedRange(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_start(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto_ReservedRange(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 4); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 6); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_extension_range(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 5); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_field(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_nested_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_oneof_decl(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 8); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 7); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_reserved_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 10); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_reserved_range(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_DescriptorProto(s), 9); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumDescriptorProto(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_allow_alias(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumOptions(s), 999); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueDescriptorProto(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueOptions(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_EnumValueOptions(s), 999); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_default_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 7); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_extendee(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_json_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 10); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_label(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 4); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_number(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_oneof_index(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 9); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 8); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 5); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_type_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldDescriptorProto(s), 6); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_ctype(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_jstype(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 6); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_lazy(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 5); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_packed(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 999); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_weak(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FieldOptions(s), 10); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_enum_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 5); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 7); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_message_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 4); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 8); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_public_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 10); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_service(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 6); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_source_code_info(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 9); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_syntax(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 12); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_weak_dependency(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorProto(s), 11); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_file(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileDescriptorSet(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_cc_enable_arenas(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 31); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_cc_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 16); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_csharp_namespace(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 37); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 23); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_go_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 11); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 20); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 17); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_multiple_files(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 10); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_outer_classname(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 8); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_java_string_check_utf8(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 27); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_javanano_use_deprecated_package(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 38); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_objc_class_prefix(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 36); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_optimize_for(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 9); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_py_generic_services(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 18); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_FileOptions(s), 999); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_map_entry(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 7); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_message_set_wire_format(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MessageOptions(s), 999); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_client_streaming(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 5); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_input_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 4); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_output_type(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_server_streaming(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodDescriptorProto(s), 6); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodOptions(s), 33); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_MethodOptions(s), 999); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_OneofDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_OneofDescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_method(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_options(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceDescriptorProto(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_deprecated(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceOptions(s), 33); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_uninterpreted_option(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_ServiceOptions(s), 999); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_leading_detached_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 6); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_path(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_span(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo_Location(s), 4); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_location(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_SourceCodeInfo(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption_NamePart(s), 1); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_aggregate_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 8); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_double_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 6); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_identifier_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 3); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_name(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 2); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_negative_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 5); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_positive_int_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 4); } -UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_string_value(const upb_symtab *s) { return upb_msgdef_itof(upbdefs_google_protobuf_UninterpretedOption(s), 7); } +/* Functions to get a fielddef from a msgdef reference. */ +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_end(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ExtensionRange_f_start(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_end(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_ReservedRange_f_start(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_enum_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_extension_range(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_field(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_nested_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_oneof_decl(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 7); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_DescriptorProto_f_reserved_range(const upb_msgdef *m) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); return upb_msgdef_itof(m, 9); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumDescriptorProto_f_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_allow_alias(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumOptions_is(m)); return upb_msgdef_itof(m, 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_number(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_EnumValueOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_EnumValueOptions_is(m)); return upb_msgdef_itof(m, 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_default_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_extendee(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_json_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_label(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_number(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_oneof_index(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldDescriptorProto_f_type_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_ctype(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_jstype(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_lazy(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_packed(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FieldOptions_f_weak(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); return upb_msgdef_itof(m, 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_dependency(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_enum_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_extension(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 7); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_message_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_public_dependency(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_service(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_source_code_info(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 9); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_syntax(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 12); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorProto_f_weak_dependency(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); return upb_msgdef_itof(m, 11); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileDescriptorSet_f_file(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileDescriptorSet_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_enable_arenas(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 31); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_cc_generic_services(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 16); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_csharp_namespace(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 37); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 23); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_go_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 11); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generate_equals_and_hash(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 20); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_generic_services(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 17); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_multiple_files(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 10); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_outer_classname(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_java_string_check_utf8(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 27); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_javanano_use_deprecated_package(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 38); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_objc_class_prefix(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 36); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_optimize_for(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 9); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_py_generic_services(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 18); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_FileOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_FileOptions_is(m)); return upb_msgdef_itof(m, 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_map_entry(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 7); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_message_set_wire_format(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_no_standard_descriptor_accessor(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MessageOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); return upb_msgdef_itof(m, 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_client_streaming(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_input_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_output_type(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodDescriptorProto_f_server_streaming(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); return upb_msgdef_itof(m, 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 33); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_MethodOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_MethodOptions_is(m)); return upb_msgdef_itof(m, 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_OneofDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_OneofDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_method(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceDescriptorProto_f_options(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_deprecated(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 33); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_ServiceOptions_f_uninterpreted_option(const upb_msgdef *m) { assert(upbdefs_google_protobuf_ServiceOptions_is(m)); return upb_msgdef_itof(m, 999); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_comments(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_leading_detached_comments(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_path(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_span(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_Location_f_trailing_comments(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); return upb_msgdef_itof(m, 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_SourceCodeInfo_f_location(const upb_msgdef *m) { assert(upbdefs_google_protobuf_SourceCodeInfo_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_is_extension(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_NamePart_f_name_part(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); return upb_msgdef_itof(m, 1); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_aggregate_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 8); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_double_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 6); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_identifier_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 3); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_name(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 2); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_negative_int_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 5); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_positive_int_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 4); } +UPB_INLINE const upb_fielddef *upbdefs_google_protobuf_UninterpretedOption_f_string_value(const upb_msgdef *m) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); return upb_msgdef_itof(m, 7); } UPB_END_EXTERN_C @@ -6921,320 +6817,360 @@ UPB_END_EXTERN_C namespace upbdefs { namespace google { namespace protobuf { -namespace descriptor { -inline upb::reffed_ptr SymbolTable() { - const upb::SymbolTable* s = upbdefs_google_protobuf_descriptor(&s); - return upb::reffed_ptr(s, &s); -} -} /* namespace descriptor */ + +class DescriptorProto : public upb::reffed_ptr { + public: + DescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_DescriptorProto_is(m)); + } + + static DescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_get(&m); + return DescriptorProto(m, &m); + } + + class ExtensionRange : public upb::reffed_ptr { + public: + ExtensionRange(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); + } + + static ExtensionRange get() { + const upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(&m); + return ExtensionRange(m, &m); + } + }; + + class ReservedRange : public upb::reffed_ptr { + public: + ReservedRange(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); + } + + static ReservedRange get() { + const upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(&m); + return ReservedRange(m, &m); + } + }; +}; + +class EnumDescriptorProto : public upb::reffed_ptr { + public: + EnumDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); + } + + static EnumDescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_EnumDescriptorProto_get(&m); + return EnumDescriptorProto(m, &m); + } +}; + +class EnumOptions : public upb::reffed_ptr { + public: + EnumOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_EnumOptions_is(m)); + } + + static EnumOptions get() { + const upb::MessageDef* m = upbdefs_google_protobuf_EnumOptions_get(&m); + return EnumOptions(m, &m); + } +}; + +class EnumValueDescriptorProto : public upb::reffed_ptr { + public: + EnumValueDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); + } + + static EnumValueDescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_EnumValueDescriptorProto_get(&m); + return EnumValueDescriptorProto(m, &m); + } +}; + +class EnumValueOptions : public upb::reffed_ptr { + public: + EnumValueOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_EnumValueOptions_is(m)); + } + + static EnumValueOptions get() { + const upb::MessageDef* m = upbdefs_google_protobuf_EnumValueOptions_get(&m); + return EnumValueOptions(m, &m); + } +}; + +class FieldDescriptorProto : public upb::reffed_ptr { + public: + FieldDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); + } + + static FieldDescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_FieldDescriptorProto_get(&m); + return FieldDescriptorProto(m, &m); + } + + class Label : public upb::reffed_ptr { + public: + Label(const upb::EnumDef* e, const void *ref_donor = NULL) + : reffed_ptr(e, ref_donor) { + assert(upbdefs_google_protobuf_FieldDescriptorProto_Label_is(e)); + } + static Label get() { + const upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Label_get(&e); + return Label(e, &e); + } + }; + + class Type : public upb::reffed_ptr { + public: + Type(const upb::EnumDef* e, const void *ref_donor = NULL) + : reffed_ptr(e, ref_donor) { + assert(upbdefs_google_protobuf_FieldDescriptorProto_Type_is(e)); + } + static Type get() { + const upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Type_get(&e); + return Type(e, &e); + } + }; +}; + +class FieldOptions : public upb::reffed_ptr { + public: + FieldOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_FieldOptions_is(m)); + } + + static FieldOptions get() { + const upb::MessageDef* m = upbdefs_google_protobuf_FieldOptions_get(&m); + return FieldOptions(m, &m); + } + + class CType : public upb::reffed_ptr { + public: + CType(const upb::EnumDef* e, const void *ref_donor = NULL) + : reffed_ptr(e, ref_donor) { + assert(upbdefs_google_protobuf_FieldOptions_CType_is(e)); + } + static CType get() { + const upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_CType_get(&e); + return CType(e, &e); + } + }; + + class JSType : public upb::reffed_ptr { + public: + JSType(const upb::EnumDef* e, const void *ref_donor = NULL) + : reffed_ptr(e, ref_donor) { + assert(upbdefs_google_protobuf_FieldOptions_JSType_is(e)); + } + static JSType get() { + const upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_JSType_get(&e); + return JSType(e, &e); + } + }; +}; + +class FileDescriptorProto : public upb::reffed_ptr { + public: + FileDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); + } + + static FileDescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorProto_get(&m); + return FileDescriptorProto(m, &m); + } +}; + +class FileDescriptorSet : public upb::reffed_ptr { + public: + FileDescriptorSet(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_FileDescriptorSet_is(m)); + } + + static FileDescriptorSet get() { + const upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorSet_get(&m); + return FileDescriptorSet(m, &m); + } +}; + +class FileOptions : public upb::reffed_ptr { + public: + FileOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_FileOptions_is(m)); + } + + static FileOptions get() { + const upb::MessageDef* m = upbdefs_google_protobuf_FileOptions_get(&m); + return FileOptions(m, &m); + } + + class OptimizeMode : public upb::reffed_ptr { + public: + OptimizeMode(const upb::EnumDef* e, const void *ref_donor = NULL) + : reffed_ptr(e, ref_donor) { + assert(upbdefs_google_protobuf_FileOptions_OptimizeMode_is(e)); + } + static OptimizeMode get() { + const upb::EnumDef* e = upbdefs_google_protobuf_FileOptions_OptimizeMode_get(&e); + return OptimizeMode(e, &e); + } + }; +}; + +class MessageOptions : public upb::reffed_ptr { + public: + MessageOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_MessageOptions_is(m)); + } + + static MessageOptions get() { + const upb::MessageDef* m = upbdefs_google_protobuf_MessageOptions_get(&m); + return MessageOptions(m, &m); + } +}; + +class MethodDescriptorProto : public upb::reffed_ptr { + public: + MethodDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); + } + + static MethodDescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_MethodDescriptorProto_get(&m); + return MethodDescriptorProto(m, &m); + } +}; + +class MethodOptions : public upb::reffed_ptr { + public: + MethodOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_MethodOptions_is(m)); + } + + static MethodOptions get() { + const upb::MessageDef* m = upbdefs_google_protobuf_MethodOptions_get(&m); + return MethodOptions(m, &m); + } +}; + +class OneofDescriptorProto : public upb::reffed_ptr { + public: + OneofDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_OneofDescriptorProto_is(m)); + } + + static OneofDescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_OneofDescriptorProto_get(&m); + return OneofDescriptorProto(m, &m); + } +}; + +class ServiceDescriptorProto : public upb::reffed_ptr { + public: + ServiceDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); + } + + static ServiceDescriptorProto get() { + const upb::MessageDef* m = upbdefs_google_protobuf_ServiceDescriptorProto_get(&m); + return ServiceDescriptorProto(m, &m); + } +}; + +class ServiceOptions : public upb::reffed_ptr { + public: + ServiceOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_ServiceOptions_is(m)); + } + + static ServiceOptions get() { + const upb::MessageDef* m = upbdefs_google_protobuf_ServiceOptions_get(&m); + return ServiceOptions(m, &m); + } +}; + +class SourceCodeInfo : public upb::reffed_ptr { + public: + SourceCodeInfo(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_SourceCodeInfo_is(m)); + } + + static SourceCodeInfo get() { + const upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_get(&m); + return SourceCodeInfo(m, &m); + } + + class Location : public upb::reffed_ptr { + public: + Location(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); + } + + static Location get() { + const upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_Location_get(&m); + return Location(m, &m); + } + }; +}; + +class UninterpretedOption : public upb::reffed_ptr { + public: + UninterpretedOption(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); + } + + static UninterpretedOption get() { + const upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_get(&m); + return UninterpretedOption(m, &m); + } + + class NamePart : public upb::reffed_ptr { + public: + NamePart(const upb::MessageDef* m, const void *ref_donor = NULL) + : reffed_ptr(m, ref_donor) { + assert(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); + } + + static NamePart get() { + const upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_NamePart_get(&m); + return NamePart(m, &m); + } + }; +}; + } /* namespace protobuf */ } /* namespace google */ - -#define RETURN_REFFED(type, func) \ - const type* obj = func(upbdefs::google::protobuf::descriptor::SymbolTable().get()); \ - return upb::reffed_ptr(obj); - -namespace google { -namespace protobuf { -namespace DescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto) } -inline upb::reffed_ptr enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_enum_type) } -inline upb::reffed_ptr extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension) } -inline upb::reffed_ptr extension_range() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_extension_range) } -inline upb::reffed_ptr field() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_field) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_name) } -inline upb::reffed_ptr nested_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_nested_type) } -inline upb::reffed_ptr oneof_decl() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_oneof_decl) } -inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_options) } -inline upb::reffed_ptr reserved_name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_reserved_name) } -inline upb::reffed_ptr reserved_range() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_reserved_range) } -} /* namespace DescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace DescriptorProto { -namespace ExtensionRange { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange) } -inline upb::reffed_ptr end() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_end) } -inline upb::reffed_ptr start() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ExtensionRange_start) } -} /* namespace ExtensionRange */ -} /* namespace DescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace DescriptorProto { -namespace ReservedRange { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_DescriptorProto_ReservedRange) } -inline upb::reffed_ptr end() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ReservedRange_end) } -inline upb::reffed_ptr start() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_DescriptorProto_ReservedRange_start) } -} /* namespace ReservedRange */ -} /* namespace DescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace EnumDescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumDescriptorProto) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_name) } -inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_options) } -inline upb::reffed_ptr value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumDescriptorProto_value) } -} /* namespace EnumDescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace EnumOptions { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumOptions) } -inline upb::reffed_ptr allow_alias() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_allow_alias) } -inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_deprecated) } -inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumOptions_uninterpreted_option) } -} /* namespace EnumOptions */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace EnumValueDescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueDescriptorProto) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_name) } -inline upb::reffed_ptr number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_number) } -inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueDescriptorProto_options) } -} /* namespace EnumValueDescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace EnumValueOptions { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_EnumValueOptions) } -inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueOptions_deprecated) } -inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_EnumValueOptions_uninterpreted_option) } -} /* namespace EnumValueOptions */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace FieldDescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldDescriptorProto) } -inline upb::reffed_ptr default_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_default_value) } -inline upb::reffed_ptr extendee() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_extendee) } -inline upb::reffed_ptr json_name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_json_name) } -inline upb::reffed_ptr label() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_label) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_name) } -inline upb::reffed_ptr number() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_number) } -inline upb::reffed_ptr oneof_index() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_oneof_index) } -inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_options) } -inline upb::reffed_ptr type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type) } -inline upb::reffed_ptr type_name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldDescriptorProto_type_name) } -inline upb::reffed_ptr Label() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Label) } -inline upb::reffed_ptr Type() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldDescriptorProto_Type) } -} /* namespace FieldDescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace FieldOptions { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FieldOptions) } -inline upb::reffed_ptr ctype() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_ctype) } -inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_deprecated) } -inline upb::reffed_ptr jstype() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_jstype) } -inline upb::reffed_ptr lazy() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_lazy) } -inline upb::reffed_ptr packed() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_packed) } -inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_uninterpreted_option) } -inline upb::reffed_ptr weak() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FieldOptions_weak) } -inline upb::reffed_ptr CType() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldOptions_CType) } -inline upb::reffed_ptr JSType() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FieldOptions_JSType) } -} /* namespace FieldOptions */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace FileDescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorProto) } -inline upb::reffed_ptr dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_dependency) } -inline upb::reffed_ptr enum_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_enum_type) } -inline upb::reffed_ptr extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_extension) } -inline upb::reffed_ptr message_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_message_type) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_name) } -inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_options) } -inline upb::reffed_ptr package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_package) } -inline upb::reffed_ptr public_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_public_dependency) } -inline upb::reffed_ptr service() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_service) } -inline upb::reffed_ptr source_code_info() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_source_code_info) } -inline upb::reffed_ptr syntax() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_syntax) } -inline upb::reffed_ptr weak_dependency() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorProto_weak_dependency) } -} /* namespace FileDescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace FileDescriptorSet { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileDescriptorSet) } -inline upb::reffed_ptr file() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileDescriptorSet_file) } -} /* namespace FileDescriptorSet */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace FileOptions { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_FileOptions) } -inline upb::reffed_ptr cc_enable_arenas() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_cc_enable_arenas) } -inline upb::reffed_ptr cc_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_cc_generic_services) } -inline upb::reffed_ptr csharp_namespace() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_csharp_namespace) } -inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_deprecated) } -inline upb::reffed_ptr go_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_go_package) } -inline upb::reffed_ptr java_generate_equals_and_hash() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generate_equals_and_hash) } -inline upb::reffed_ptr java_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_generic_services) } -inline upb::reffed_ptr java_multiple_files() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_multiple_files) } -inline upb::reffed_ptr java_outer_classname() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_outer_classname) } -inline upb::reffed_ptr java_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_package) } -inline upb::reffed_ptr java_string_check_utf8() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_java_string_check_utf8) } -inline upb::reffed_ptr javanano_use_deprecated_package() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_javanano_use_deprecated_package) } -inline upb::reffed_ptr objc_class_prefix() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_objc_class_prefix) } -inline upb::reffed_ptr optimize_for() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_optimize_for) } -inline upb::reffed_ptr py_generic_services() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_py_generic_services) } -inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_FileOptions_uninterpreted_option) } -inline upb::reffed_ptr OptimizeMode() { RETURN_REFFED(upb::EnumDef, upbdefs_google_protobuf_FileOptions_OptimizeMode) } -} /* namespace FileOptions */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace MessageOptions { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MessageOptions) } -inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_deprecated) } -inline upb::reffed_ptr map_entry() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_map_entry) } -inline upb::reffed_ptr message_set_wire_format() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_message_set_wire_format) } -inline upb::reffed_ptr no_standard_descriptor_accessor() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_no_standard_descriptor_accessor) } -inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MessageOptions_uninterpreted_option) } -} /* namespace MessageOptions */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace MethodDescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodDescriptorProto) } -inline upb::reffed_ptr client_streaming() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_client_streaming) } -inline upb::reffed_ptr input_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_input_type) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_name) } -inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_options) } -inline upb::reffed_ptr output_type() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_output_type) } -inline upb::reffed_ptr server_streaming() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodDescriptorProto_server_streaming) } -} /* namespace MethodDescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace MethodOptions { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_MethodOptions) } -inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodOptions_deprecated) } -inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_MethodOptions_uninterpreted_option) } -} /* namespace MethodOptions */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace OneofDescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_OneofDescriptorProto) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_OneofDescriptorProto_name) } -} /* namespace OneofDescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace ServiceDescriptorProto { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceDescriptorProto) } -inline upb::reffed_ptr method() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_method) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_name) } -inline upb::reffed_ptr options() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceDescriptorProto_options) } -} /* namespace ServiceDescriptorProto */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace ServiceOptions { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_ServiceOptions) } -inline upb::reffed_ptr deprecated() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceOptions_deprecated) } -inline upb::reffed_ptr uninterpreted_option() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_ServiceOptions_uninterpreted_option) } -} /* namespace ServiceOptions */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace SourceCodeInfo { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo) } -inline upb::reffed_ptr location() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_location) } -} /* namespace SourceCodeInfo */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace SourceCodeInfo { -namespace Location { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_SourceCodeInfo_Location) } -inline upb::reffed_ptr leading_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_leading_comments) } -inline upb::reffed_ptr leading_detached_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_leading_detached_comments) } -inline upb::reffed_ptr path() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_path) } -inline upb::reffed_ptr span() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_span) } -inline upb::reffed_ptr trailing_comments() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_SourceCodeInfo_Location_trailing_comments) } -} /* namespace Location */ -} /* namespace SourceCodeInfo */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace UninterpretedOption { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption) } -inline upb::reffed_ptr aggregate_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_aggregate_value) } -inline upb::reffed_ptr double_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_double_value) } -inline upb::reffed_ptr identifier_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_identifier_value) } -inline upb::reffed_ptr name() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_name) } -inline upb::reffed_ptr negative_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_negative_int_value) } -inline upb::reffed_ptr positive_int_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_positive_int_value) } -inline upb::reffed_ptr string_value() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_string_value) } -} /* namespace UninterpretedOption */ -} /* namespace protobuf */ -} /* namespace google */ - -namespace google { -namespace protobuf { -namespace UninterpretedOption { -namespace NamePart { -inline upb::reffed_ptr MessageDef() { RETURN_REFFED(upb::MessageDef, upbdefs_google_protobuf_UninterpretedOption_NamePart) } -inline upb::reffed_ptr is_extension() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_is_extension) } -inline upb::reffed_ptr name_part() { RETURN_REFFED(upb::FieldDef, upbdefs_google_protobuf_UninterpretedOption_NamePart_name_part) } -} /* namespace NamePart */ -} /* namespace UninterpretedOption */ -} /* namespace protobuf */ -} /* namespace google */ - } /* namespace upbdefs */ +#endif /* __cplusplus */ -#undef RETURN_REFFED -#endif /* __cplusplus */ - -#endif /* GOOGLE_PROTOBUF_DESCRIPTOR_UPB_H_ */ +#endif /* UPB_DESCRIPTOR_DESCRIPTOR_PROTO_UPB_H_ */ /* ** Internal-only definitions for the decoder. */ @@ -8155,49 +8091,43 @@ inline reffed_ptr Encoder::NewHandlers( #include #ifdef __cplusplus +#include + extern "C" { #endif -/* Loads all defs from the given protobuf binary descriptor, setting default - * accessors and a default layout on all messages. The caller owns the - * returned array of defs, which will be of length *n. On error NULL is - * returned and status is set (if non-NULL). */ -upb_def **upb_load_defs_from_descriptor(const char *str, size_t len, int *n, - void *owner, upb_status *status); - -/* Like the previous but also adds the loaded defs to the given symtab. */ -bool upb_load_descriptor_into_symtab(upb_symtab *symtab, const char *str, - size_t len, upb_status *status); - -/* Like the previous but also reads the descriptor from the given filename. */ -bool upb_load_descriptor_file_into_symtab(upb_symtab *symtab, const char *fname, - upb_status *status); - -/* Reads the given filename into a character string, returning NULL if there - * was an error. */ -char *upb_readfile(const char *filename, size_t *len); +/* Loads a binary descriptor and returns a NULL-terminated array of unfrozen + * filedefs. The caller owns the returned array. */ +upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner, + upb_status *status); #ifdef __cplusplus } /* extern "C" */ namespace upb { -/* All routines that load descriptors expect the descriptor to be a - * FileDescriptorSet. */ -inline bool LoadDescriptorFileIntoSymtab(SymbolTable* s, const char *fname, - Status* status) { - return upb_load_descriptor_file_into_symtab(s, fname, status); -} +inline bool LoadDescriptor(const char* buf, size_t n, Status* status, + std::vector >* files) { + FileDef** parsed_files = upb_loaddescriptor(buf, n, &parsed_files, status); -inline bool LoadDescriptorIntoSymtab(SymbolTable* s, const char* str, - size_t len, Status* status) { - return upb_load_descriptor_into_symtab(s, str, len, status); + if (parsed_files) { + FileDef** p = parsed_files; + while (*p) { + files->push_back(reffed_ptr(*p, &parsed_files)); + ++p; + } + free(parsed_files); + return true; + } else { + return false; + } } /* Templated so it can accept both string and std::string. */ template -bool LoadDescriptorIntoSymtab(SymbolTable* s, const T& desc, Status* status) { - return upb_load_descriptor_into_symtab(s, desc.c_str(), desc.size(), status); +bool LoadDescriptor(const T& desc, Status* status, + std::vector >* files) { + return LoadDescriptor(desc.c_str(), desc.size(), status, files); } } /* namespace upb */ From 90c7f6e55eb43d89f345fc4412a99ac9477055da Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 14 Apr 2016 12:48:41 -0700 Subject: [PATCH 074/123] Documented the JSON change and compatibility flags. --- ruby/README.md | 96 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/ruby/README.md b/ruby/README.md index 16474322..62a64863 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -7,6 +7,74 @@ we recommend using protoc's Ruby generation support with .proto files. The build process in this directory only installs the extension; you need to install protoc as well to have Ruby code generation functionality. +JSON Migration Note +------------------- + +Users who were using the protobuf Gem `<= 3.0.0.alpha.5.0.4` will notice that +the JSON format has changed slightly and is incompatible with previous +versions. + +The change concerns field names. Prior to the change, field names from the +.proto file were used verbatim. Take this `.proto` file: + +```protobuf +syntax = "proto3"; + +message M { + int32 my_int_field = 1; + bool my_bool_field = 2; +} +``` + +Serializing to JSON used to give you something like this: + +```json +{"my_int_field":1, "my_bool_field":true} +``` + +However this format was not compatible with the proto3 JSON spec. To be +compliant with proto3 JSON, we need to camel-case the names: + +```json +{"myIntField":1, "myBoolField":true} +``` + +Starting with `3.0.0.alpha.5.0.5`, this bug was fixed and we now produce the +correct camelCased names. However this may cause compatibility problems for +JSON users who can't upgrade everything at the same time, or who store +serialized JSON payloads. To mitigate this and allow time for migration, the +library currently recognizes two environment variables: + + - `UPB_JSON_ACCEPT_LEGACY_FIELD_NAMES`: set this variable to instruct the + JSON parser that the old names should be accepted in addition to the new, + compliant ones. This will make the parser compatible with both formats. + - `UPB_JSON_WRITE_LEGACY_FIELD_NAMES`: set this variable to instruct the + JSON serializer to encode the old, non-compliant names. + +These options will be removed in a future version of Ruby protobuf. All +users shoud migrate to the standard names. + +If users have existing payloads in the old format and cannot easily migrate, +the best solution would be to specify the old names explicitly in the +`.proto` file using the `json_name` option. For example, for the .proto +file above, the user could specify: + +```protobuf +syntax = "proto3"; + +message M { + int32 my_int_field = 1 [json_name="my_int_field"]; + bool my_bool_field = 2 [json_name="my_bool_field"]; +} +``` + +This will make all compliant proto3 JSON parsers/serializers use the +non-camel-cased names forever. Note that protobuf Ruby does *not yet* +support this option properly, but support is forthcoming. It will +certainly be supported before the environment variables above are +removed. + + Installation from Gem --------------------- @@ -32,23 +100,25 @@ documentation may be found in the RubyDoc comments (`call-seq` tags) in the source, and we plan to release separate, more detailed, documentation at a later date. - require 'google/protobuf' +```ruby +require 'google/protobuf' - # generated from my_proto_types.proto with protoc: - # $ protoc --ruby_out=. my_proto_types.proto - require 'my_proto_types' +# generated from my_proto_types.proto with protoc: +# $ protoc --ruby_out=. my_proto_types.proto +require 'my_proto_types' - mymessage = MyTestMessage.new(:field1 => 42, :field2 => ["a", "b", "c"]) - mymessage.field1 = 43 - mymessage.field2.push("d") - mymessage.field3 = SubMessage.new(:foo => 100) +mymessage = MyTestMessage.new(:field1 => 42, :field2 => ["a", "b", "c"]) +mymessage.field1 = 43 +mymessage.field2.push("d") +mymessage.field3 = SubMessage.new(:foo => 100) - encoded_data = MyTestMessage.encode(mymessage) - decoded = MyTestMessage.decode(encoded_data) - assert decoded == mymessage +encoded_data = MyTestMessage.encode(mymessage) +decoded = MyTestMessage.decode(encoded_data) +assert decoded == mymessage - puts "JSON:" - puts MyTestMessage.encode_json(mymessage) +puts "JSON:" +puts MyTestMessage.encode_json(mymessage) +``` Installation from Source (Building Gem) --------------------------------------- From 1b912fceee0d3f5ced51e8335f16faa0ee3e334a Mon Sep 17 00:00:00 2001 From: Adam Michalik Date: Thu, 14 Apr 2016 15:54:31 -0700 Subject: [PATCH 075/123] Remove googletest.h header from stringprintf.cc It doesn't seem to be necessary here, and it pulls other testing headers during compilation of release protobuf. --- src/google/protobuf/stubs/stringprintf.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/google/protobuf/stubs/stringprintf.cc b/src/google/protobuf/stubs/stringprintf.cc index 3272d8e3..83fdfe45 100644 --- a/src/google/protobuf/stubs/stringprintf.cc +++ b/src/google/protobuf/stubs/stringprintf.cc @@ -37,7 +37,6 @@ #include // MSVC requires this for _vsnprintf #include #include -#include namespace google { namespace protobuf { From 194ad621bb7260c4f2f27f3575ce21ab946b786c Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 14 Apr 2016 18:33:17 -0700 Subject: [PATCH 076/123] Ruby JSON: always accept both camelCase and original field names. For JSON encoding we provide a new option to decide at encode time whether to use camelCase or original proto field names: json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true) --- ruby/ext/google/protobuf_c/defs.c | 5 +++ ruby/ext/google/protobuf_c/encode_decode.c | 45 +++++++++++++++++----- ruby/ext/google/protobuf_c/message.c | 2 +- ruby/ext/google/protobuf_c/protobuf.h | 3 +- ruby/ext/google/protobuf_c/upb.c | 41 +++++++++++--------- ruby/ext/google/protobuf_c/upb.h | 14 +++++-- ruby/tests/basic.rb | 5 +++ 7 files changed, 82 insertions(+), 33 deletions(-) diff --git a/ruby/ext/google/protobuf_c/defs.c b/ruby/ext/google/protobuf_c/defs.c index 96ef4953..7e93bafb 100644 --- a/ruby/ext/google/protobuf_c/defs.c +++ b/ruby/ext/google/protobuf_c/defs.c @@ -255,6 +255,10 @@ void Descriptor_free(void* _self) { upb_handlers_unref(self->json_serialize_handlers, &self->json_serialize_handlers); } + if (self->json_serialize_handlers_preserve) { + upb_handlers_unref(self->json_serialize_handlers_preserve, + &self->json_serialize_handlers_preserve); + } xfree(self); } @@ -278,6 +282,7 @@ VALUE Descriptor_alloc(VALUE klass) { self->json_fill_method = NULL; self->pb_serialize_handlers = NULL; self->json_serialize_handlers = NULL; + self->json_serialize_handlers_preserve = NULL; self->typeclass_references = rb_ary_new(); return ret; } diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index c2c369eb..9bc7273e 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -1130,13 +1130,23 @@ static const upb_handlers* msgdef_pb_serialize_handlers(Descriptor* desc) { return desc->pb_serialize_handlers; } -static const upb_handlers* msgdef_json_serialize_handlers(Descriptor* desc) { - if (desc->json_serialize_handlers == NULL) { - desc->json_serialize_handlers = - upb_json_printer_newhandlers( - desc->msgdef, &desc->json_serialize_handlers); +static const upb_handlers* msgdef_json_serialize_handlers( + Descriptor* desc, bool preserve_proto_fieldnames) { + if (preserve_proto_fieldnames) { + if (desc->json_serialize_handlers == NULL) { + desc->json_serialize_handlers = + upb_json_printer_newhandlers( + desc->msgdef, true, &desc->json_serialize_handlers); + } + return desc->json_serialize_handlers; + } else { + if (desc->json_serialize_handlers_preserve == NULL) { + desc->json_serialize_handlers_preserve = + upb_json_printer_newhandlers( + desc->msgdef, false, &desc->json_serialize_handlers_preserve); + } + return desc->json_serialize_handlers_preserve; } - return desc->json_serialize_handlers; } /* @@ -1181,16 +1191,33 @@ VALUE Message_encode(VALUE klass, VALUE msg_rb) { * * Encodes the given message object into its serialized JSON representation. */ -VALUE Message_encode_json(VALUE klass, VALUE msg_rb) { +VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass) { VALUE descriptor = rb_ivar_get(klass, descriptor_instancevar_interned); Descriptor* desc = ruby_to_Descriptor(descriptor); - + VALUE msg_rb; + VALUE preserve_proto_fieldnames = Qfalse; stringsink sink; + + if (argc < 1 || argc > 2) { + rb_raise(rb_eArgError, "Expected 1 or 2 arguments."); + } + + msg_rb = argv[0]; + + if (argc == 2) { + VALUE hash_args = argv[1]; + if (TYPE(hash_args) != T_HASH) { + rb_raise(rb_eArgError, "Expected hash arguments."); + } + preserve_proto_fieldnames = rb_hash_lookup2( + hash_args, ID2SYM(rb_intern("preserve_proto_fieldnames")), Qfalse); + } + stringsink_init(&sink); { const upb_handlers* serialize_handlers = - msgdef_json_serialize_handlers(desc); + msgdef_json_serialize_handlers(desc, RTEST(preserve_proto_fieldnames)); upb_json_printer* printer; stackenv se; VALUE ret; diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 283939c9..3a51fe47 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -475,7 +475,7 @@ VALUE build_class_from_descriptor(Descriptor* desc) { rb_define_singleton_method(klass, "decode", Message_decode, 1); rb_define_singleton_method(klass, "encode", Message_encode, 1); rb_define_singleton_method(klass, "decode_json", Message_decode_json, 1); - rb_define_singleton_method(klass, "encode_json", Message_encode_json, 1); + rb_define_singleton_method(klass, "encode_json", Message_encode_json, -1); rb_define_singleton_method(klass, "descriptor", Message_descriptor, 0); return klass; diff --git a/ruby/ext/google/protobuf_c/protobuf.h b/ruby/ext/google/protobuf_c/protobuf.h index 21ce7bb3..2834c894 100644 --- a/ruby/ext/google/protobuf_c/protobuf.h +++ b/ruby/ext/google/protobuf_c/protobuf.h @@ -115,6 +115,7 @@ struct Descriptor { const upb_json_parsermethod* json_fill_method; const upb_handlers* pb_serialize_handlers; const upb_handlers* json_serialize_handlers; + const upb_handlers* json_serialize_handlers_preserve; // Handlers hold type class references for sub-message fields directly in some // cases. We need to keep these rooted because they might otherwise be // collected. @@ -498,7 +499,7 @@ VALUE Message_descriptor(VALUE klass); VALUE Message_decode(VALUE klass, VALUE data); VALUE Message_encode(VALUE klass, VALUE msg_rb); VALUE Message_decode_json(VALUE klass, VALUE data); -VALUE Message_encode_json(VALUE klass, VALUE msg_rb); +VALUE Message_encode_json(int argc, VALUE* argv, VALUE klass); VALUE Google_Protobuf_deep_copy(VALUE self, VALUE obj); diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c index db84ae3f..eac19f71 100644 --- a/ruby/ext/google/protobuf_c/upb.c +++ b/ruby/ext/google/protobuf_c/upb.c @@ -11624,7 +11624,7 @@ _again: #line 1270 "upb/json/parser.rl" if (p != pe) { - upb_status_seterrf(&parser->status, "Parse error at %s\n", p); + upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", p, pe - p); upb_env_reporterror(parser->env, &parser->status); } else { capture_suspend(parser, &p); @@ -11725,6 +11725,7 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { upb_msg_field_next(&i)) { const upb_fielddef *f = upb_msg_iter_field(&i); + /* Add an entry for the JSON name. */ size_t field_len = upb_fielddef_getjsonname(f, buf, len); if (field_len > len) { size_t len2; @@ -11735,10 +11736,10 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { } upb_strtable_insert(t, buf, upb_value_constptr(f)); - if (getenv("UPB_JSON_ACCEPT_LEGACY_FIELD_NAMES")) { - /* Temporary code to help people migrate if they were depending on the - * old, non-proto3-json-compliant field names. In this case we - * recognize both old names and new names. */ + if (strcmp(buf, upb_fielddef_name(f)) != 0) { + /* Since the JSON name is different from the regular field name, add an + * entry for the raw name (compliant proto3 JSON parsers must accept + * both). */ upb_strtable_insert(t, upb_fielddef_name(f), upb_value_constptr(f)); } @@ -11853,12 +11854,11 @@ void freestrpc(void *ptr) { } /* Convert fielddef name to JSON name and return as a string piece. */ -strpc *newstrpc(upb_handlers *h, const upb_fielddef *f) { +strpc *newstrpc(upb_handlers *h, const upb_fielddef *f, + bool preserve_fieldnames) { /* TODO(haberman): handle malloc failure. */ strpc *ret = malloc(sizeof(*ret)); - if (getenv("UPB_JSON_WRITE_LEGACY_FIELD_NAMES")) { - /* Temporary code to help people migrate if they were depending on the - * old, non-proto3-json-compliant field names. */ + if (preserve_fieldnames) { ret->ptr = upb_strdup(upb_fielddef_name(f)); ret->len = strlen(ret->ptr); } else { @@ -12374,10 +12374,11 @@ static size_t mapkey_bytes(void *closure, const void *handler_data, static void set_enum_hd(upb_handlers *h, const upb_fielddef *f, + bool preserve_fieldnames, upb_handlerattr *attr) { EnumHandlerData *hd = malloc(sizeof(EnumHandlerData)); hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f); - hd->keyname = newstrpc(h, f); + hd->keyname = newstrpc(h, f, preserve_fieldnames); upb_handlers_addcleanup(h, hd, free); upb_handlerattr_sethandlerdata(attr, hd); } @@ -12394,7 +12395,8 @@ static void set_enum_hd(upb_handlers *h, * our sources that emit mapentry messages do so canonically (with one key * field, and then one value field), so this is not a pressing concern at the * moment. */ -void printer_sethandlers_mapentry(const void *closure, upb_handlers *h) { +void printer_sethandlers_mapentry(const void *closure, bool preserve_fieldnames, + upb_handlers *h) { const upb_msgdef *md = upb_handlers_msgdef(h); /* A mapentry message is printed simply as '"key": value'. Rather than @@ -12468,7 +12470,7 @@ void printer_sethandlers_mapentry(const void *closure, upb_handlers *h) { break; case UPB_TYPE_ENUM: { upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER; - set_enum_hd(h, value_field, &enum_attr); + set_enum_hd(h, value_field, preserve_fieldnames, &enum_attr); upb_handlers_setint32(h, value_field, mapvalue_enum, &enum_attr); upb_handlerattr_uninit(&enum_attr); break; @@ -12487,13 +12489,13 @@ void printer_sethandlers(const void *closure, upb_handlers *h) { bool is_mapentry = upb_msgdef_mapentry(md); upb_handlerattr empty_attr = UPB_HANDLERATTR_INITIALIZER; upb_msg_field_iter i; - - UPB_UNUSED(closure); + const bool *preserve_fieldnames_ptr = closure; + const bool preserve_fieldnames = *preserve_fieldnames_ptr; if (is_mapentry) { /* mapentry messages are sufficiently different that we handle them * separately. */ - printer_sethandlers_mapentry(closure, h); + printer_sethandlers_mapentry(closure, preserve_fieldnames, h); return; } @@ -12514,7 +12516,8 @@ void printer_sethandlers(const void *closure, upb_handlers *h) { const upb_fielddef *f = upb_msg_iter_field(&i); upb_handlerattr name_attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&name_attr, newstrpc(h, f)); + upb_handlerattr_sethandlerdata(&name_attr, + newstrpc(h, f, preserve_fieldnames)); if (upb_fielddef_ismap(f)) { upb_handlers_setstartseq(h, f, startmap, &name_attr); @@ -12537,7 +12540,7 @@ void printer_sethandlers(const void *closure, upb_handlers *h) { * option later to control this behavior, but we will wait for a real * need first. */ upb_handlerattr enum_attr = UPB_HANDLERATTR_INITIALIZER; - set_enum_hd(h, f, &enum_attr); + set_enum_hd(h, f, preserve_fieldnames, &enum_attr); if (upb_fielddef_isseq(f)) { upb_handlers_setint32(h, f, repeated_enum, &enum_attr); @@ -12614,6 +12617,8 @@ upb_sink *upb_json_printer_input(upb_json_printer *p) { } const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md, + bool preserve_fieldnames, const void *owner) { - return upb_handlers_newfrozen(md, owner, printer_sethandlers, NULL); + return upb_handlers_newfrozen( + md, owner, printer_sethandlers, &preserve_fieldnames); } diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h index 6cea1068..b0058161 100644 --- a/ruby/ext/google/protobuf_c/upb.h +++ b/ruby/ext/google/protobuf_c/upb.h @@ -8370,8 +8370,12 @@ class upb::json::Printer { /* The input to the printer. */ Sink* input(); - /* Returns handlers for printing according to the specified schema. */ - static reffed_ptr NewHandlers(const upb::MessageDef* md); + /* Returns handlers for printing according to the specified schema. + * If preserve_proto_fieldnames is true, the output JSON will use the + * original .proto field names (ie. {"my_field":3}) instead of using + * camelCased names, which is the default: (eg. {"myField":3}). */ + static reffed_ptr NewHandlers(const upb::MessageDef* md, + bool preserve_proto_fieldnames); static const size_t kSize = UPB_JSON_PRINTER_SIZE; @@ -8388,6 +8392,7 @@ upb_json_printer *upb_json_printer_create(upb_env *e, const upb_handlers *h, upb_bytessink *output); upb_sink *upb_json_printer_input(upb_json_printer *p); const upb_handlers *upb_json_printer_newhandlers(const upb_msgdef *md, + bool preserve_fieldnames, const void *owner); UPB_END_EXTERN_C @@ -8402,8 +8407,9 @@ inline Printer* Printer::Create(Environment* env, const upb::Handlers* handlers, } inline Sink* Printer::input() { return upb_json_printer_input(this); } inline reffed_ptr Printer::NewHandlers( - const upb::MessageDef *md) { - const Handlers* h = upb_json_printer_newhandlers(md, &h); + const upb::MessageDef *md, bool preserve_proto_fieldnames) { + const Handlers* h = upb_json_printer_newhandlers( + md, preserve_proto_fieldnames, &h); return reffed_ptr(h, &h); } } /* namespace json */ diff --git a/ruby/tests/basic.rb b/ruby/tests/basic.rb index 86c74c2a..77c186ef 100644 --- a/ruby/tests/basic.rb +++ b/ruby/tests/basic.rb @@ -1161,7 +1161,12 @@ module BasicTest return if RUBY_PLATFORM == "java" m = MapMessage.new(:map_string_int32 => {"a" => 1}) expected = '{"mapStringInt32":{"a":1},"mapStringMsg":{}}' + expected_preserve = '{"map_string_int32":{"a":1},"map_string_msg":{}}' assert MapMessage.encode_json(m) == expected + + json = MapMessage.encode_json(m, :preserve_proto_fieldnames => true) + assert json == expected_preserve + m2 = MapMessage.decode_json(MapMessage.encode_json(m)) assert m == m2 end From 800e986012f43512416cc960a3072642a393073a Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 14 Apr 2016 18:42:22 -0700 Subject: [PATCH 077/123] Remove no longer applicable documentation from README.md. --- ruby/README.md | 68 -------------------------------------------------- 1 file changed, 68 deletions(-) diff --git a/ruby/README.md b/ruby/README.md index 62a64863..f28e05a7 100644 --- a/ruby/README.md +++ b/ruby/README.md @@ -7,74 +7,6 @@ we recommend using protoc's Ruby generation support with .proto files. The build process in this directory only installs the extension; you need to install protoc as well to have Ruby code generation functionality. -JSON Migration Note -------------------- - -Users who were using the protobuf Gem `<= 3.0.0.alpha.5.0.4` will notice that -the JSON format has changed slightly and is incompatible with previous -versions. - -The change concerns field names. Prior to the change, field names from the -.proto file were used verbatim. Take this `.proto` file: - -```protobuf -syntax = "proto3"; - -message M { - int32 my_int_field = 1; - bool my_bool_field = 2; -} -``` - -Serializing to JSON used to give you something like this: - -```json -{"my_int_field":1, "my_bool_field":true} -``` - -However this format was not compatible with the proto3 JSON spec. To be -compliant with proto3 JSON, we need to camel-case the names: - -```json -{"myIntField":1, "myBoolField":true} -``` - -Starting with `3.0.0.alpha.5.0.5`, this bug was fixed and we now produce the -correct camelCased names. However this may cause compatibility problems for -JSON users who can't upgrade everything at the same time, or who store -serialized JSON payloads. To mitigate this and allow time for migration, the -library currently recognizes two environment variables: - - - `UPB_JSON_ACCEPT_LEGACY_FIELD_NAMES`: set this variable to instruct the - JSON parser that the old names should be accepted in addition to the new, - compliant ones. This will make the parser compatible with both formats. - - `UPB_JSON_WRITE_LEGACY_FIELD_NAMES`: set this variable to instruct the - JSON serializer to encode the old, non-compliant names. - -These options will be removed in a future version of Ruby protobuf. All -users shoud migrate to the standard names. - -If users have existing payloads in the old format and cannot easily migrate, -the best solution would be to specify the old names explicitly in the -`.proto` file using the `json_name` option. For example, for the .proto -file above, the user could specify: - -```protobuf -syntax = "proto3"; - -message M { - int32 my_int_field = 1 [json_name="my_int_field"]; - bool my_bool_field = 2 [json_name="my_bool_field"]; -} -``` - -This will make all compliant proto3 JSON parsers/serializers use the -non-camel-cased names forever. Note that protobuf Ruby does *not yet* -support this option properly, but support is forthcoming. It will -certainly be supported before the environment variables above are -removed. - - Installation from Gem --------------------- From e67ef3d449011c7923cf4c1e4b205ebd0d6f2167 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 14 Apr 2016 20:27:45 -0700 Subject: [PATCH 078/123] Bugfix for JSON error case. --- conformance/failure_list_ruby.txt | 2 -- ruby/ext/google/protobuf_c/upb.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/conformance/failure_list_ruby.txt b/conformance/failure_list_ruby.txt index ade0ff4c..7c12da06 100644 --- a/conformance/failure_list_ruby.txt +++ b/conformance/failure_list_ruby.txt @@ -80,7 +80,6 @@ JsonInput.Int32FieldMaxFloatValue.JsonOutput JsonInput.Int32FieldMaxFloatValue.ProtobufOutput JsonInput.Int32FieldMinFloatValue.JsonOutput JsonInput.Int32FieldMinFloatValue.ProtobufOutput -JsonInput.Int32FieldMinValue.JsonOutput JsonInput.Int32FieldStringValue.JsonOutput JsonInput.Int32FieldStringValue.ProtobufOutput JsonInput.Int32FieldStringValueEscaped.JsonOutput @@ -125,7 +124,6 @@ JsonInput.OptionalUint64Wrapper.ProtobufOutput JsonInput.OptionalWrapperTypesWithNonDefaultValue.JsonOutput JsonInput.OptionalWrapperTypesWithNonDefaultValue.ProtobufOutput JsonInput.OriginalProtoFieldName.JsonOutput -JsonInput.OriginalProtoFieldName.ProtobufOutput JsonInput.PrimitiveRepeatedField.JsonOutput JsonInput.PrimitiveRepeatedField.ProtobufOutput JsonInput.RepeatedBoolWrapper.JsonOutput diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c index eac19f71..212f1e0e 100644 --- a/ruby/ext/google/protobuf_c/upb.c +++ b/ruby/ext/google/protobuf_c/upb.c @@ -11624,7 +11624,7 @@ _again: #line 1270 "upb/json/parser.rl" if (p != pe) { - upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", p, pe - p); + upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p); upb_env_reporterror(parser->env, &parser->status); } else { capture_suspend(parser, &p); From baf52bd79e80b019370a1bfda70e46ff6a692e2b Mon Sep 17 00:00:00 2001 From: Chad Whipkey Date: Fri, 15 Apr 2016 09:23:50 -0700 Subject: [PATCH 079/123] Change protobuf CPP proto generator to support the 'lite' option in proto3. Added a couple unit test proto3 files, for arena_lite and lite. Cloned the proto3_arena_unittest to test some of the basics of generated code (and to ensure that the generated proto3 test files are used by some test). --- BUILD | 4 + src/Makefile.am | 8 + .../protobuf/compiler/cpp/cpp_message.cc | 23 +- src/google/protobuf/descriptor.cc | 5 - src/google/protobuf/descriptor_unittest.cc | 12 - .../protobuf/proto3_arena_lite_unittest.cc | 164 ++++++++++++++ src/google/protobuf/proto3_lite_unittest.cc | 145 ++++++++++++ .../protobuf/unittest_proto3_arena_lite.proto | 207 ++++++++++++++++++ .../protobuf/unittest_proto3_lite.proto | 206 +++++++++++++++++ 9 files changed, 744 insertions(+), 30 deletions(-) create mode 100644 src/google/protobuf/proto3_arena_lite_unittest.cc create mode 100644 src/google/protobuf/proto3_lite_unittest.cc create mode 100644 src/google/protobuf/unittest_proto3_arena_lite.proto create mode 100644 src/google/protobuf/unittest_proto3_lite.proto diff --git a/BUILD b/BUILD index 1615486f..09d917b7 100644 --- a/BUILD +++ b/BUILD @@ -376,6 +376,8 @@ RELATIVE_TEST_PROTOS = [ "google/protobuf/unittest_preserve_unknown_enum.proto", "google/protobuf/unittest_preserve_unknown_enum2.proto", "google/protobuf/unittest_proto3_arena.proto", + "google/protobuf/unittest_proto3_arena_lite.proto", + "google/protobuf/unittest_proto3_lite.proto", "google/protobuf/unittest_well_known_types.proto", "google/protobuf/util/internal/testdata/anys.proto", "google/protobuf/util/internal/testdata/books.proto", @@ -461,6 +463,8 @@ cc_test( "src/google/protobuf/no_field_presence_test.cc", "src/google/protobuf/preserve_unknown_enum_test.cc", "src/google/protobuf/proto3_arena_unittest.cc", + "src/google/protobuf/proto3_arena_lite_unittest.cc", + "src/google/protobuf/proto3_lite_unittest.cc", "src/google/protobuf/reflection_ops_unittest.cc", "src/google/protobuf/repeated_field_reflection_unittest.cc", "src/google/protobuf/repeated_field_unittest.cc", diff --git a/src/Makefile.am b/src/Makefile.am index 2ba0ef9b..80065506 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -507,6 +507,8 @@ protoc_inputs = \ google/protobuf/unittest_preserve_unknown_enum.proto \ google/protobuf/unittest.proto \ google/protobuf/unittest_proto3_arena.proto \ + google/protobuf/unittest_proto3_arena_lite.proto \ + google/protobuf/unittest_proto3_lite.proto \ google/protobuf/unittest_well_known_types.proto \ google/protobuf/util/internal/testdata/anys.proto \ google/protobuf/util/internal/testdata/books.proto \ @@ -609,6 +611,10 @@ protoc_outputs = \ google/protobuf/unittest_preserve_unknown_enum.pb.h \ google/protobuf/unittest_proto3_arena.pb.cc \ google/protobuf/unittest_proto3_arena.pb.h \ + google/protobuf/unittest_proto3_arena_lite.pb.cc \ + google/protobuf/unittest_proto3_arena_lite.pb.h \ + google/protobuf/unittest_proto3_lite.pb.cc \ + google/protobuf/unittest_proto3_lite.pb.h \ google/protobuf/unittest_well_known_types.pb.cc \ google/protobuf/unittest_well_known_types.pb.h \ google/protobuf/util/internal/testdata/anys.pb.cc \ @@ -710,6 +716,8 @@ protobuf_test_SOURCES = \ google/protobuf/no_field_presence_test.cc \ google/protobuf/preserve_unknown_enum_test.cc \ google/protobuf/proto3_arena_unittest.cc \ + google/protobuf/proto3_arena_lite_unittest.cc \ + google/protobuf/proto3_lite_unittest.cc \ google/protobuf/reflection_ops_unittest.cc \ google/protobuf/repeated_field_reflection_unittest.cc \ google/protobuf/repeated_field_unittest.cc \ diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index c3166611..9bd5cf51 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -1777,7 +1777,8 @@ void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { // mutable_unknown_fields wrapper function for LazyStringOutputStream // callback. - if (!UseUnknownFieldSet(descriptor_->file())) { + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { printer->Print( "static ::std::string* MutableUnknownFieldsFor$classname$(\n" " $classname$* ptr) {\n" @@ -2656,18 +2657,13 @@ GenerateSwap(io::Printer* printer) { } } - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print( - "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - } else { - printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); - } - } else { - // Still swap internal_metadata as it may contain more than just - // unknown fields. + // Ignore PreserveUnknownFields here - always swap internal_metadata as it + // may contain more than just unknown fields. + if (UseUnknownFieldSet(descriptor_->file())) { printer->Print( - "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); + "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); + } else { + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); } printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); if (descriptor_->extension_range_count() > 0) { @@ -2908,7 +2904,8 @@ GenerateMergeFromCodedStream(io::Printer* printer) { " ::google::protobuf::uint32 tag;\n", "classname", classname_); - if (!UseUnknownFieldSet(descriptor_->file())) { + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file())) { // Use LazyStringOutputString to avoid initializing unknown fields string // unless it is actually needed. For the same reason, disable eager refresh // on the CodedOutputStream. diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 78a34617..f46c7f23 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -5113,11 +5113,6 @@ void DescriptorBuilder::ValidateProto3( for (int i = 0; i < file->enum_type_count(); ++i) { ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i)); } - if (IsLite(file)) { - AddError(file->name(), proto, - DescriptorPool::ErrorCollector::OTHER, - "Lite runtime is not supported in proto3."); - } } static string ToLowercaseWithoutUnderscores(const string& name) { diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index e4720a7e..f937b9ea 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -5740,18 +5740,6 @@ TEST_F(ValidationErrorTest, ValidateProto3Enum) { "}"); } -TEST_F(ValidationErrorTest, ValidateProto3LiteRuntime) { - // Lite runtime is not supported in proto3. - BuildFileWithErrors( - "name: 'foo.proto' " - "syntax: 'proto3' " - "options { " - " optimize_for: LITE_RUNTIME " - "} ", - "foo.proto: foo.proto: OTHER: Lite runtime is not supported " - "in proto3.\n"); -} - TEST_F(ValidationErrorTest, ValidateProto3Group) { BuildFileWithErrors( "name: 'foo.proto' " diff --git a/src/google/protobuf/proto3_arena_lite_unittest.cc b/src/google/protobuf/proto3_arena_lite_unittest.cc new file mode 100644 index 00000000..0f18c027 --- /dev/null +++ b/src/google/protobuf/proto3_arena_lite_unittest.cc @@ -0,0 +1,164 @@ +// 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 +#include +#ifndef _SHARED_PTR_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include + +namespace google { +using proto3_arena_lite_unittest::TestAllTypes; + +namespace protobuf { +namespace { +// We selectively set/check a few representative fields rather than all fields +// as this test is only expected to cover the basics of arena support. +void SetAllFields(TestAllTypes* m) { + m->set_optional_int32(100); + m->set_optional_string("asdf"); + m->set_optional_bytes("jkl;"); + m->mutable_optional_nested_message()->set_bb(42); + m->mutable_optional_foreign_message()->set_c(43); + m->set_optional_nested_enum( + proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->set_optional_foreign_enum( + proto3_arena_lite_unittest::FOREIGN_BAZ); + m->mutable_optional_lazy_message()->set_bb(45); + m->add_repeated_int32(100); + m->add_repeated_string("asdf"); + m->add_repeated_bytes("jkl;"); + m->add_repeated_nested_message()->set_bb(46); + m->add_repeated_foreign_message()->set_c(47); + m->add_repeated_nested_enum( + proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->add_repeated_foreign_enum( + proto3_arena_lite_unittest::FOREIGN_BAZ); + m->add_repeated_lazy_message()->set_bb(49); + + m->set_oneof_uint32(1); + m->mutable_oneof_nested_message()->set_bb(50); + m->set_oneof_string("test"); // only this one remains set +} + +void ExpectAllFieldsSet(const TestAllTypes& m) { + EXPECT_EQ(100, m.optional_int32()); + EXPECT_EQ("asdf", m.optional_string()); + EXPECT_EQ("jkl;", m.optional_bytes()); + EXPECT_EQ(true, m.has_optional_nested_message()); + EXPECT_EQ(42, m.optional_nested_message().bb()); + EXPECT_EQ(true, m.has_optional_foreign_message()); + EXPECT_EQ(43, m.optional_foreign_message().c()); + EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.optional_nested_enum()); + EXPECT_EQ(proto3_arena_lite_unittest::FOREIGN_BAZ, + m.optional_foreign_enum()); + EXPECT_EQ(true, m.has_optional_lazy_message()); + EXPECT_EQ(45, m.optional_lazy_message().bb()); + + EXPECT_EQ(1, m.repeated_int32_size()); + EXPECT_EQ(100, m.repeated_int32(0)); + EXPECT_EQ(1, m.repeated_string_size()); + EXPECT_EQ("asdf", m.repeated_string(0)); + EXPECT_EQ(1, m.repeated_bytes_size()); + EXPECT_EQ("jkl;", m.repeated_bytes(0)); + EXPECT_EQ(1, m.repeated_nested_message_size()); + EXPECT_EQ(46, m.repeated_nested_message(0).bb()); + EXPECT_EQ(1, m.repeated_foreign_message_size()); + EXPECT_EQ(47, m.repeated_foreign_message(0).c()); + EXPECT_EQ(1, m.repeated_nested_enum_size()); + EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.repeated_nested_enum(0)); + EXPECT_EQ(1, m.repeated_foreign_enum_size()); + EXPECT_EQ(proto3_arena_lite_unittest::FOREIGN_BAZ, + m.repeated_foreign_enum(0)); + EXPECT_EQ(1, m.repeated_lazy_message_size()); + EXPECT_EQ(49, m.repeated_lazy_message(0).bb()); + + EXPECT_EQ(proto3_arena_lite_unittest::TestAllTypes::kOneofString, + m.oneof_field_case()); + EXPECT_EQ("test", m.oneof_string()); +} + +// In this file we only test some basic functionalities of arena support in +// proto3 and expect the arena support to be fully tested in proto2 unittests +// because proto3 shares most code with proto2. + +TEST(Proto3ArenaLiteTest, Parsing) { + TestAllTypes original; + SetAllFields(&original); + + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->ParseFromString(original.SerializeAsString()); + ExpectAllFieldsSet(*arena_message); +} + +TEST(Proto3ArenaLiteTest, Swap) { + Arena arena1; + Arena arena2; + + // Test Swap(). + TestAllTypes* arena1_message = Arena::CreateMessage(&arena1); + TestAllTypes* arena2_message = Arena::CreateMessage(&arena2); + arena1_message->Swap(arena2_message); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); +} + +TEST(Proto3ArenaLiteTest, SetAllocatedMessage) { + Arena arena; + TestAllTypes *arena_message = Arena::CreateMessage(&arena); + TestAllTypes::NestedMessage* nested = new TestAllTypes::NestedMessage; + nested->set_bb(118); + arena_message->set_allocated_optional_nested_message(nested); + EXPECT_EQ(118, arena_message->optional_nested_message().bb()); +} + +TEST(Proto3ArenaLiteTest, ReleaseMessage) { + Arena arena; + TestAllTypes* arena_message = Arena::CreateMessage(&arena); + arena_message->mutable_optional_nested_message()->set_bb(118); + google::protobuf::scoped_ptr nested( + arena_message->release_optional_nested_message()); + EXPECT_EQ(118, nested->bb()); +} + +} // namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/proto3_lite_unittest.cc b/src/google/protobuf/proto3_lite_unittest.cc new file mode 100644 index 00000000..2e2beea9 --- /dev/null +++ b/src/google/protobuf/proto3_lite_unittest.cc @@ -0,0 +1,145 @@ +// 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 +#include +#ifndef _SHARED_PTR_H +#include +#endif +#include + +#include +#include +#include +#include +#include +#include + +namespace google { +using proto3_lite_unittest::TestAllTypes; + +namespace protobuf { +namespace { +// We selectively set/check a few representative fields rather than all fields +// as this test is only expected to cover the basics of lite support. +void SetAllFields(TestAllTypes* m) { + m->set_optional_int32(100); + m->set_optional_string("asdf"); + m->set_optional_bytes("jkl;"); + m->mutable_optional_nested_message()->set_bb(42); + m->mutable_optional_foreign_message()->set_c(43); + m->set_optional_nested_enum( + proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->set_optional_foreign_enum( + proto3_lite_unittest::FOREIGN_BAZ); + m->mutable_optional_lazy_message()->set_bb(45); + m->add_repeated_int32(100); + m->add_repeated_string("asdf"); + m->add_repeated_bytes("jkl;"); + m->add_repeated_nested_message()->set_bb(46); + m->add_repeated_foreign_message()->set_c(47); + m->add_repeated_nested_enum( + proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ); + m->add_repeated_foreign_enum( + proto3_lite_unittest::FOREIGN_BAZ); + m->add_repeated_lazy_message()->set_bb(49); + + m->set_oneof_uint32(1); + m->mutable_oneof_nested_message()->set_bb(50); + m->set_oneof_string("test"); // only this one remains set +} + +void ExpectAllFieldsSet(const TestAllTypes& m) { + EXPECT_EQ(100, m.optional_int32()); + EXPECT_EQ("asdf", m.optional_string()); + EXPECT_EQ("jkl;", m.optional_bytes()); + EXPECT_EQ(true, m.has_optional_nested_message()); + EXPECT_EQ(42, m.optional_nested_message().bb()); + EXPECT_EQ(true, m.has_optional_foreign_message()); + EXPECT_EQ(43, m.optional_foreign_message().c()); + EXPECT_EQ(proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.optional_nested_enum()); + EXPECT_EQ(proto3_lite_unittest::FOREIGN_BAZ, + m.optional_foreign_enum()); + EXPECT_EQ(true, m.has_optional_lazy_message()); + EXPECT_EQ(45, m.optional_lazy_message().bb()); + + EXPECT_EQ(1, m.repeated_int32_size()); + EXPECT_EQ(100, m.repeated_int32(0)); + EXPECT_EQ(1, m.repeated_string_size()); + EXPECT_EQ("asdf", m.repeated_string(0)); + EXPECT_EQ(1, m.repeated_bytes_size()); + EXPECT_EQ("jkl;", m.repeated_bytes(0)); + EXPECT_EQ(1, m.repeated_nested_message_size()); + EXPECT_EQ(46, m.repeated_nested_message(0).bb()); + EXPECT_EQ(1, m.repeated_foreign_message_size()); + EXPECT_EQ(47, m.repeated_foreign_message(0).c()); + EXPECT_EQ(1, m.repeated_nested_enum_size()); + EXPECT_EQ(proto3_lite_unittest::TestAllTypes_NestedEnum_BAZ, + m.repeated_nested_enum(0)); + EXPECT_EQ(1, m.repeated_foreign_enum_size()); + EXPECT_EQ(proto3_lite_unittest::FOREIGN_BAZ, + m.repeated_foreign_enum(0)); + EXPECT_EQ(1, m.repeated_lazy_message_size()); + EXPECT_EQ(49, m.repeated_lazy_message(0).bb()); + + EXPECT_EQ(proto3_lite_unittest::TestAllTypes::kOneofString, + m.oneof_field_case()); + EXPECT_EQ("test", m.oneof_string()); +} + +// In this file we only test some basic functionalities of in proto3 and expect +// the rest is fully tested in proto2 unittests because proto3 shares most code +// with proto2. + +TEST(Proto3LiteTest, Parsing) { + TestAllTypes original; + SetAllFields(&original); + + TestAllTypes msg; + msg.ParseFromString(original.SerializeAsString()); + ExpectAllFieldsSet(msg); +} + +TEST(Proto3LiteTest, Swap) { + // Test Swap(). + TestAllTypes msg1; + TestAllTypes msg2; + msg1.set_optional_string("123"); + msg2.set_optional_string("3456"); + msg1.Swap(&msg2); + EXPECT_EQ("3456", msg1.optional_string()); + EXPECT_EQ("123", msg2.optional_string()); + EXPECT_EQ(msg1.ByteSize(), msg2.ByteSize() + 1); +} + +} // namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/unittest_proto3_arena_lite.proto b/src/google/protobuf/unittest_proto3_arena_lite.proto new file mode 100644 index 00000000..5a60b90f --- /dev/null +++ b/src/google/protobuf/unittest_proto3_arena_lite.proto @@ -0,0 +1,207 @@ +// 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"; + +option cc_enable_arenas = true; +option optimize_for = LITE_RUNTIME; + +import "google/protobuf/unittest_import.proto"; + +package proto3_arena_lite_unittest; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + int32 bb = 1; + } + + enum NestedEnum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + NEG = -1; // Intentionally negative. + } + + // Singular + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + // Groups are not allowed in proto3. + // optional group OptionalGroup = 16 { + // optional int32 a = 17; + // } + + NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest_import.ImportMessage optional_import_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; + + string optional_string_piece = 24 [ctype=STRING_PIECE]; + string optional_cord = 25 [ctype=CORD]; + + // Defined in unittest_import_public.proto + protobuf_unittest_import.PublicImportMessage + optional_public_import_message = 26; + + NestedMessage optional_lazy_message = 27 [lazy=true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + // Groups are not allowed in proto3. + // repeated group RepeatedGroup = 46 { + // optional int32 a = 47; + // } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy=true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Test messages for packed fields + +message TestPackedTypes { + repeated int32 packed_int32 = 90 [packed = true]; + repeated int64 packed_int64 = 91 [packed = true]; + repeated uint32 packed_uint32 = 92 [packed = true]; + repeated uint64 packed_uint64 = 93 [packed = true]; + repeated sint32 packed_sint32 = 94 [packed = true]; + repeated sint64 packed_sint64 = 95 [packed = true]; + repeated fixed32 packed_fixed32 = 96 [packed = true]; + repeated fixed64 packed_fixed64 = 97 [packed = true]; + repeated sfixed32 packed_sfixed32 = 98 [packed = true]; + repeated sfixed64 packed_sfixed64 = 99 [packed = true]; + repeated float packed_float = 100 [packed = true]; + repeated double packed_double = 101 [packed = true]; + repeated bool packed_bool = 102 [packed = true]; + repeated ForeignEnum packed_enum = 103 [packed = true]; +} + +// Explicitly set packed to false +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} + +// This proto includes a recusively nested message. +message NestedTestAllTypes { + NestedTestAllTypes child = 1; + TestAllTypes payload = 2; +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_ZERO = 0; + FOREIGN_FOO = 4; + FOREIGN_BAR = 5; + FOREIGN_BAZ = 6; +} + +// TestEmptyMessage is used to test behavior of unknown fields. +message TestEmptyMessage { +} + diff --git a/src/google/protobuf/unittest_proto3_lite.proto b/src/google/protobuf/unittest_proto3_lite.proto new file mode 100644 index 00000000..874ade6c --- /dev/null +++ b/src/google/protobuf/unittest_proto3_lite.proto @@ -0,0 +1,206 @@ +// 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"; + +option optimize_for = LITE_RUNTIME; + +import "google/protobuf/unittest_import.proto"; + +package proto3_lite_unittest; + +// This proto includes every type of field in both singular and repeated +// forms. +message TestAllTypes { + message NestedMessage { + // The field name "b" fails to compile in proto1 because it conflicts with + // a local variable named "b" in one of the generated methods. Doh. + // This file needs to compile in proto1 to test backwards-compatibility. + int32 bb = 1; + } + + enum NestedEnum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 3; + NEG = -1; // Intentionally negative. + } + + // Singular + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + sint32 optional_sint32 = 5; + sint64 optional_sint64 = 6; + fixed32 optional_fixed32 = 7; + fixed64 optional_fixed64 = 8; + sfixed32 optional_sfixed32 = 9; + sfixed64 optional_sfixed64 = 10; + float optional_float = 11; + double optional_double = 12; + bool optional_bool = 13; + string optional_string = 14; + bytes optional_bytes = 15; + + // Groups are not allowed in proto3. + // optional group OptionalGroup = 16 { + // optional int32 a = 17; + // } + + NestedMessage optional_nested_message = 18; + ForeignMessage optional_foreign_message = 19; + protobuf_unittest_import.ImportMessage optional_import_message = 20; + + NestedEnum optional_nested_enum = 21; + ForeignEnum optional_foreign_enum = 22; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // optional protobuf_unittest_import.ImportEnum optional_import_enum = 23; + + string optional_string_piece = 24 [ctype=STRING_PIECE]; + string optional_cord = 25 [ctype=CORD]; + + // Defined in unittest_import_public.proto + protobuf_unittest_import.PublicImportMessage + optional_public_import_message = 26; + + NestedMessage optional_lazy_message = 27 [lazy=true]; + + // Repeated + repeated int32 repeated_int32 = 31; + repeated int64 repeated_int64 = 32; + repeated uint32 repeated_uint32 = 33; + repeated uint64 repeated_uint64 = 34; + repeated sint32 repeated_sint32 = 35; + repeated sint64 repeated_sint64 = 36; + repeated fixed32 repeated_fixed32 = 37; + repeated fixed64 repeated_fixed64 = 38; + repeated sfixed32 repeated_sfixed32 = 39; + repeated sfixed64 repeated_sfixed64 = 40; + repeated float repeated_float = 41; + repeated double repeated_double = 42; + repeated bool repeated_bool = 43; + repeated string repeated_string = 44; + repeated bytes repeated_bytes = 45; + + // Groups are not allowed in proto3. + // repeated group RepeatedGroup = 46 { + // optional int32 a = 47; + // } + + repeated NestedMessage repeated_nested_message = 48; + repeated ForeignMessage repeated_foreign_message = 49; + repeated protobuf_unittest_import.ImportMessage repeated_import_message = 50; + + repeated NestedEnum repeated_nested_enum = 51; + repeated ForeignEnum repeated_foreign_enum = 52; + + // Omitted (compared to unittest.proto) because proto2 enums are not allowed + // inside proto2 messages. + // + // repeated protobuf_unittest_import.ImportEnum repeated_import_enum = 53; + + repeated string repeated_string_piece = 54 [ctype=STRING_PIECE]; + repeated string repeated_cord = 55 [ctype=CORD]; + + repeated NestedMessage repeated_lazy_message = 57 [lazy=true]; + + oneof oneof_field { + uint32 oneof_uint32 = 111; + NestedMessage oneof_nested_message = 112; + string oneof_string = 113; + bytes oneof_bytes = 114; + } +} + +// Test messages for packed fields + +message TestPackedTypes { + repeated int32 packed_int32 = 90 [packed = true]; + repeated int64 packed_int64 = 91 [packed = true]; + repeated uint32 packed_uint32 = 92 [packed = true]; + repeated uint64 packed_uint64 = 93 [packed = true]; + repeated sint32 packed_sint32 = 94 [packed = true]; + repeated sint64 packed_sint64 = 95 [packed = true]; + repeated fixed32 packed_fixed32 = 96 [packed = true]; + repeated fixed64 packed_fixed64 = 97 [packed = true]; + repeated sfixed32 packed_sfixed32 = 98 [packed = true]; + repeated sfixed64 packed_sfixed64 = 99 [packed = true]; + repeated float packed_float = 100 [packed = true]; + repeated double packed_double = 101 [packed = true]; + repeated bool packed_bool = 102 [packed = true]; + repeated ForeignEnum packed_enum = 103 [packed = true]; +} + +// Explicitly set packed to false +message TestUnpackedTypes { + repeated int32 repeated_int32 = 1 [packed = false]; + repeated int64 repeated_int64 = 2 [packed = false]; + repeated uint32 repeated_uint32 = 3 [packed = false]; + repeated uint64 repeated_uint64 = 4 [packed = false]; + repeated sint32 repeated_sint32 = 5 [packed = false]; + repeated sint64 repeated_sint64 = 6 [packed = false]; + repeated fixed32 repeated_fixed32 = 7 [packed = false]; + repeated fixed64 repeated_fixed64 = 8 [packed = false]; + repeated sfixed32 repeated_sfixed32 = 9 [packed = false]; + repeated sfixed64 repeated_sfixed64 = 10 [packed = false]; + repeated float repeated_float = 11 [packed = false]; + repeated double repeated_double = 12 [packed = false]; + repeated bool repeated_bool = 13 [packed = false]; + repeated TestAllTypes.NestedEnum repeated_nested_enum = 14 [packed = false]; +} + +// This proto includes a recusively nested message. +message NestedTestAllTypes { + NestedTestAllTypes child = 1; + TestAllTypes payload = 2; +} + +// Define these after TestAllTypes to make sure the compiler can handle +// that. +message ForeignMessage { + int32 c = 1; +} + +enum ForeignEnum { + FOREIGN_ZERO = 0; + FOREIGN_FOO = 4; + FOREIGN_BAR = 5; + FOREIGN_BAZ = 6; +} + +// TestEmptyMessage is used to test behavior of unknown fields. +message TestEmptyMessage { +} + From 7ff229fa4e7774ee7fa86965fc943c19ace575c3 Mon Sep 17 00:00:00 2001 From: Nikolai Vavilov Date: Fri, 15 Apr 2016 23:23:33 +0200 Subject: [PATCH 080/123] Support Windows in gulpfile.js --- js/gulpfile.js | 6 +++++- js/package.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/gulpfile.js b/js/gulpfile.js index 7e44aa76..c5220153 100644 --- a/js/gulpfile.js +++ b/js/gulpfile.js @@ -1,7 +1,11 @@ var gulp = require('gulp'); -var exec = require('child_process').exec; +var execFile = require('child_process').execFile; var glob = require('glob'); +function exec(command, cb) { + execFile('sh', ['-c', command], cb); +} + var protoc = process.env.PROTOC || '../src/protoc'; gulp.task('genproto_closure', function (cb) { diff --git a/js/package.json b/js/package.json index 6418e507..c16417ca 100644 --- a/js/package.json +++ b/js/package.json @@ -13,7 +13,7 @@ "glob": "~6.0.4" }, "scripts": { - "test": "./node_modules/gulp/bin/gulp.js test" + "test": "node ./node_modules/gulp/bin/gulp.js test" }, "repository": { "type": "git", From 1f4f3e26bdfad8d1777d609825c9a3aa9ea6c856 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Mon, 18 Apr 2016 14:12:08 -0700 Subject: [PATCH 081/123] Update file list to include the missing extension lite file. --- BUILD | 2 ++ cmake/extract_includes.bat.in | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/BUILD b/BUILD index 1615486f..2fbf2f94 100644 --- a/BUILD +++ b/BUILD @@ -266,6 +266,7 @@ cc_library( "src/google/protobuf/compiler/java/java_enum_field_lite.cc", "src/google/protobuf/compiler/java/java_enum_lite.cc", "src/google/protobuf/compiler/java/java_extension.cc", + "src/google/protobuf/compiler/java/java_extension_lite.cc", "src/google/protobuf/compiler/java/java_field.cc", "src/google/protobuf/compiler/java/java_file.cc", "src/google/protobuf/compiler/java/java_generator.cc", @@ -436,6 +437,7 @@ cc_test( "src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc", "src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc", "src/google/protobuf/compiler/cpp/cpp_unittest.cc", + "src/google/protobuf/compiler/cpp/metadata_test.cc", "src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc", "src/google/protobuf/compiler/importer_unittest.cc", "src/google/protobuf/compiler/java/java_doc_comment_unittest.cc", diff --git a/cmake/extract_includes.bat.in b/cmake/extract_includes.bat.in index c76973c9..b593e0c9 100644 --- a/cmake/extract_includes.bat.in +++ b/cmake/extract_includes.bat.in @@ -23,7 +23,6 @@ copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\command_line_ copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\cpp\cpp_generator.h include\google\protobuf\compiler\cpp\cpp_generator.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_generator.h include\google\protobuf\compiler\csharp\csharp_generator.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_names.h include\google\protobuf\compiler\csharp\csharp_names.h -copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\csharp\csharp_options.h include\google\protobuf\compiler\csharp\csharp_options.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\importer.h include\google\protobuf\compiler\importer.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_generator.h include\google\protobuf\compiler\java\java_generator.h copy ${PROTOBUF_SOURCE_WIN32_PATH}\..\src\google\protobuf\compiler\java\java_names.h include\google\protobuf\compiler\java\java_names.h From 3633bcd5e4a2c4b38271c453cec6a8f5c365b949 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 19 Apr 2016 12:40:37 -0400 Subject: [PATCH 082/123] Fix comment typo --- objectivec/GPBCodedOutputStream.h | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/objectivec/GPBCodedOutputStream.h b/objectivec/GPBCodedOutputStream.h index e67efd2d..8272880d 100644 --- a/objectivec/GPBCodedOutputStream.h +++ b/objectivec/GPBCodedOutputStream.h @@ -112,7 +112,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a double for the given field number. - (void)writeDouble:(int32_t)fieldNumber value:(double)value; -/// Write a packaged array of double for the given field number. +/// Write a packed array of double for the given field number. - (void)writeDoubleArray:(int32_t)fieldNumber values:(GPBDoubleArray *)values tag:(uint32_t)tag; @@ -121,7 +121,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a float for the given field number. - (void)writeFloat:(int32_t)fieldNumber value:(float)value; -/// Write a packaged array of float for the given field number. +/// Write a packed array of float for the given field number. - (void)writeFloatArray:(int32_t)fieldNumber values:(GPBFloatArray *)values tag:(uint32_t)tag; @@ -130,7 +130,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a uint64_t for the given field number. - (void)writeUInt64:(int32_t)fieldNumber value:(uint64_t)value; -/// Write a packaged array of uint64_t for the given field number. +/// Write a packed array of uint64_t for the given field number. - (void)writeUInt64Array:(int32_t)fieldNumber values:(GPBUInt64Array *)values tag:(uint32_t)tag; @@ -139,7 +139,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a int64_t for the given field number. - (void)writeInt64:(int32_t)fieldNumber value:(int64_t)value; -/// Write a packaged array of int64_t for the given field number. +/// Write a packed array of int64_t for the given field number. - (void)writeInt64Array:(int32_t)fieldNumber values:(GPBInt64Array *)values tag:(uint32_t)tag; @@ -148,7 +148,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a int32_t for the given field number. - (void)writeInt32:(int32_t)fieldNumber value:(int32_t)value; -/// Write a packaged array of int32_t for the given field number. +/// Write a packed array of int32_t for the given field number. - (void)writeInt32Array:(int32_t)fieldNumber values:(GPBInt32Array *)values tag:(uint32_t)tag; @@ -157,7 +157,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a uint32_t for the given field number. - (void)writeUInt32:(int32_t)fieldNumber value:(uint32_t)value; -/// Write a packaged array of uint32_t for the given field number. +/// Write a packed array of uint32_t for the given field number. - (void)writeUInt32Array:(int32_t)fieldNumber values:(GPBUInt32Array *)values tag:(uint32_t)tag; @@ -166,7 +166,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a uint64_t for the given field number. - (void)writeFixed64:(int32_t)fieldNumber value:(uint64_t)value; -/// Write a packaged array of uint64_t for the given field number. +/// Write a packed array of uint64_t for the given field number. - (void)writeFixed64Array:(int32_t)fieldNumber values:(GPBUInt64Array *)values tag:(uint32_t)tag; @@ -175,7 +175,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a uint32_t for the given field number. - (void)writeFixed32:(int32_t)fieldNumber value:(uint32_t)value; -/// Write a packaged array of uint32_t for the given field number. +/// Write a packed array of uint32_t for the given field number. - (void)writeFixed32Array:(int32_t)fieldNumber values:(GPBUInt32Array *)values tag:(uint32_t)tag; @@ -184,7 +184,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a int32_t for the given field number. - (void)writeSInt32:(int32_t)fieldNumber value:(int32_t)value; -/// Write a packaged array of int32_t for the given field number. +/// Write a packed array of int32_t for the given field number. - (void)writeSInt32Array:(int32_t)fieldNumber values:(GPBInt32Array *)values tag:(uint32_t)tag; @@ -193,7 +193,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a int64_t for the given field number. - (void)writeSInt64:(int32_t)fieldNumber value:(int64_t)value; -/// Write a packaged array of int64_t for the given field number. +/// Write a packed array of int64_t for the given field number. - (void)writeSInt64Array:(int32_t)fieldNumber values:(GPBInt64Array *)values tag:(uint32_t)tag; @@ -202,7 +202,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a int64_t for the given field number. - (void)writeSFixed64:(int32_t)fieldNumber value:(int64_t)value; -/// Write a packaged array of int64_t for the given field number. +/// Write a packed array of int64_t for the given field number. - (void)writeSFixed64Array:(int32_t)fieldNumber values:(GPBInt64Array *)values tag:(uint32_t)tag; @@ -211,7 +211,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a int32_t for the given field number. - (void)writeSFixed32:(int32_t)fieldNumber value:(int32_t)value; -/// Write a packaged array of int32_t for the given field number. +/// Write a packed array of int32_t for the given field number. - (void)writeSFixed32Array:(int32_t)fieldNumber values:(GPBInt32Array *)values tag:(uint32_t)tag; @@ -220,7 +220,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a BOOL for the given field number. - (void)writeBool:(int32_t)fieldNumber value:(BOOL)value; -/// Write a packaged array of BOOL for the given field number. +/// Write a packed array of BOOL for the given field number. - (void)writeBoolArray:(int32_t)fieldNumber values:(GPBBoolArray *)values tag:(uint32_t)tag; @@ -229,7 +229,7 @@ NS_ASSUME_NONNULL_BEGIN /// Write a int32_t for the given field number. - (void)writeEnum:(int32_t)fieldNumber value:(int32_t)value; -/// Write a packaged array of int32_t for the given field number. +/// Write a packed array of int32_t for the given field number. - (void)writeEnumArray:(int32_t)fieldNumber values:(GPBEnumArray *)values tag:(uint32_t)tag; @@ -293,7 +293,7 @@ NS_ASSUME_NONNULL_END //%PDDM-DEFINE _WRITE_PACKABLE_DECLS(NAME, ARRAY_TYPE, TYPE) //%/// Write a TYPE for the given field number. //%- (void)write##NAME:(int32_t)fieldNumber value:(TYPE)value; -//%/// Write a packaged array of TYPE for the given field number. +//%/// Write a packed array of TYPE for the given field number. //%- (void)write##NAME##Array:(int32_t)fieldNumber //% NAME$S values:(GPB##ARRAY_TYPE##Array *)values //% NAME$S tag:(uint32_t)tag; From e664aa6d91724c056e9573eee347bcf21d9e9490 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 19 Apr 2016 13:13:04 -0400 Subject: [PATCH 083/123] Regenerate the WKT to pick up current changes to the proto files. --- objectivec/google/protobuf/Any.pbobjc.h | 41 +++++++++++++++++-- objectivec/google/protobuf/Any.pbobjc.m | 5 +++ objectivec/google/protobuf/Api.pbobjc.h | 5 +++ objectivec/google/protobuf/Api.pbobjc.m | 5 +++ objectivec/google/protobuf/Duration.pbobjc.h | 5 +++ objectivec/google/protobuf/Duration.pbobjc.m | 5 +++ objectivec/google/protobuf/Empty.pbobjc.h | 5 +++ objectivec/google/protobuf/Empty.pbobjc.m | 5 +++ objectivec/google/protobuf/FieldMask.pbobjc.h | 32 +++++++++++++++ objectivec/google/protobuf/FieldMask.pbobjc.m | 5 +++ .../google/protobuf/SourceContext.pbobjc.h | 5 +++ .../google/protobuf/SourceContext.pbobjc.m | 5 +++ objectivec/google/protobuf/Struct.pbobjc.h | 7 +++- objectivec/google/protobuf/Struct.pbobjc.m | 5 +++ objectivec/google/protobuf/Timestamp.pbobjc.h | 5 +++ objectivec/google/protobuf/Timestamp.pbobjc.m | 5 +++ objectivec/google/protobuf/Type.pbobjc.h | 5 +++ objectivec/google/protobuf/Type.pbobjc.m | 5 +++ objectivec/google/protobuf/Wrappers.pbobjc.h | 5 +++ objectivec/google/protobuf/Wrappers.pbobjc.m | 5 +++ 20 files changed, 160 insertions(+), 5 deletions(-) diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h index 79ec0fb7..439e3b37 100644 --- a/objectivec/google/protobuf/Any.pbobjc.h +++ b/objectivec/google/protobuf/Any.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -33,8 +36,36 @@ typedef GPB_ENUM(GPBAny_FieldNumber) { GPBAny_FieldNumber_Value = 2, }; -/// `Any` contains an arbitrary serialized message along with a URL -/// that describes the type of the serialized message. +/// `Any` contains an arbitrary serialized protocol buffer message along with a +/// URL that describes the type of the serialized message. +/// +/// Protobuf library provides support to pack/unpack Any values in the form +/// of utility functions or additional generated methods of the Any type. +/// +/// Example 1: Pack and unpack a message in C++. +/// +/// Foo foo = ...; +/// Any any; +/// any.PackFrom(foo); +/// ... +/// if (any.UnpackTo(&foo)) { +/// ... +/// } +/// +/// Example 2: Pack and unpack a message in Java. +/// +/// Foo foo = ...; +/// Any any = Any.pack(foo); +/// ... +/// if (any.is(Foo.class)) { +/// foo = any.unpack(Foo.class); +/// } +/// +/// The pack methods provided by protobuf library will by default use +/// 'type.googleapis.com/full.type.name' as the type URL and the unpack +/// methods only use the fully qualified type name after the last '/' +/// in the type URL, for example "foo.bar.com/x/y.z" will yield type +/// name "y.z". /// /// /// JSON @@ -67,7 +98,7 @@ typedef GPB_ENUM(GPBAny_FieldNumber) { @interface GPBAny : GPBMessage /// A URL/resource name whose content describes the type of the -/// serialized message. +/// serialized protocol buffer message. /// /// For URLs which use the schema `http`, `https`, or no schema, the /// following restrictions and interpretations apply: @@ -87,7 +118,7 @@ typedef GPB_ENUM(GPBAny_FieldNumber) { /// used with implementation specific semantics. @property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL; -/// Must be valid serialized data of the above specified type. +/// Must be a valid serialized protocol buffer of the above specified type. @property(nonatomic, readwrite, copy, null_resettable) NSData *value; @end @@ -96,4 +127,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Any.pbobjc.m b/objectivec/google/protobuf/Any.pbobjc.m index 7cbf0def..6a1bf894 100644 --- a/objectivec/google/protobuf/Any.pbobjc.m +++ b/objectivec/google/protobuf/Any.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/Any.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBAnyRoot @implementation GPBAnyRoot @@ -85,4 +88,6 @@ typedef struct GPBAny__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Api.pbobjc.h b/objectivec/google/protobuf/Api.pbobjc.h index 3f7e99c6..d66df629 100644 --- a/objectivec/google/protobuf/Api.pbobjc.h +++ b/objectivec/google/protobuf/Api.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN @class GPBMethod; @@ -254,4 +257,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Api.pbobjc.m b/objectivec/google/protobuf/Api.pbobjc.m index 2b2f62ea..45a06e60 100644 --- a/objectivec/google/protobuf/Api.pbobjc.m +++ b/objectivec/google/protobuf/Api.pbobjc.m @@ -7,6 +7,9 @@ #import "google/protobuf/Type.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBApiRoot @implementation GPBApiRoot @@ -340,4 +343,6 @@ typedef struct GPBMixin__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Duration.pbobjc.h b/objectivec/google/protobuf/Duration.pbobjc.h index 3685a614..29888d6c 100644 --- a/objectivec/google/protobuf/Duration.pbobjc.h +++ b/objectivec/google/protobuf/Duration.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -93,4 +96,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Duration.pbobjc.m b/objectivec/google/protobuf/Duration.pbobjc.m index bb79c7a3..7dd6b64a 100644 --- a/objectivec/google/protobuf/Duration.pbobjc.m +++ b/objectivec/google/protobuf/Duration.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/Duration.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBDurationRoot @implementation GPBDurationRoot @@ -80,4 +83,6 @@ typedef struct GPBDuration__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Empty.pbobjc.h b/objectivec/google/protobuf/Empty.pbobjc.h index 6651ef71..f33db017 100644 --- a/objectivec/google/protobuf/Empty.pbobjc.h +++ b/objectivec/google/protobuf/Empty.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -45,4 +48,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Empty.pbobjc.m b/objectivec/google/protobuf/Empty.pbobjc.m index 5d7f8f19..88753aaf 100644 --- a/objectivec/google/protobuf/Empty.pbobjc.m +++ b/objectivec/google/protobuf/Empty.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/Empty.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBEmptyRoot @implementation GPBEmptyRoot @@ -56,4 +59,6 @@ typedef struct GPBEmpty__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h index 931f664c..47a239ba 100644 --- a/objectivec/google/protobuf/FieldMask.pbobjc.h +++ b/objectivec/google/protobuf/FieldMask.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -154,6 +157,33 @@ typedef GPB_ENUM(GPBFieldMask_FieldNumber) { /// { /// mask: "user.displayName,photo" /// } +/// +/// # Field Masks and Oneof Fields +/// +/// Field masks treat fields in oneofs just as regular fields. Consider the +/// following message: +/// +/// message SampleMessage { +/// oneof test_oneof { +/// string name = 4; +/// SubMessage sub_message = 9; +/// } +/// } +/// +/// The field mask can be: +/// +/// mask { +/// paths: "name" +/// } +/// +/// Or: +/// +/// mask { +/// paths: "sub_message" +/// } +/// +/// Note that oneof type names ("test_oneof" in this case) cannot be used in +/// paths. @interface GPBFieldMask : GPBMessage /// The set of field mask paths. @@ -167,4 +197,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/protobuf/FieldMask.pbobjc.m index 36fc758e..8c241afc 100644 --- a/objectivec/google/protobuf/FieldMask.pbobjc.m +++ b/objectivec/google/protobuf/FieldMask.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/FieldMask.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBFieldMaskRoot @implementation GPBFieldMaskRoot @@ -69,4 +72,6 @@ typedef struct GPBFieldMask__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/protobuf/SourceContext.pbobjc.h index 67b6d479..8775348e 100644 --- a/objectivec/google/protobuf/SourceContext.pbobjc.h +++ b/objectivec/google/protobuf/SourceContext.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -46,4 +49,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/protobuf/SourceContext.pbobjc.m index 4e8bf3d2..95007126 100644 --- a/objectivec/google/protobuf/SourceContext.pbobjc.m +++ b/objectivec/google/protobuf/SourceContext.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/SourceContext.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBSourceContextRoot @implementation GPBSourceContextRoot @@ -69,4 +72,6 @@ typedef struct GPBSourceContext__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Struct.pbobjc.h b/objectivec/google/protobuf/Struct.pbobjc.h index e2388e22..3924b4b7 100644 --- a/objectivec/google/protobuf/Struct.pbobjc.h +++ b/objectivec/google/protobuf/Struct.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN @class GPBListValue; @@ -67,7 +70,7 @@ typedef GPB_ENUM(GPBStruct_FieldNumber) { /// The JSON representation for `Struct` is JSON object. @interface GPBStruct : GPBMessage -/// Map of dynamically typed values. +/// Unordered map of dynamically typed values. @property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *fields; /// The number of items in @c fields without causing the array to be created. @property(nonatomic, readonly) NSUInteger fields_Count; @@ -159,4 +162,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Struct.pbobjc.m b/objectivec/google/protobuf/Struct.pbobjc.m index 0601a4b2..60940027 100644 --- a/objectivec/google/protobuf/Struct.pbobjc.m +++ b/objectivec/google/protobuf/Struct.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/Struct.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBStructRoot @implementation GPBStructRoot @@ -265,4 +268,6 @@ typedef struct GPBListValue__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/protobuf/Timestamp.pbobjc.h index b66b323a..925dca84 100644 --- a/objectivec/google/protobuf/Timestamp.pbobjc.h +++ b/objectivec/google/protobuf/Timestamp.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -105,4 +108,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/protobuf/Timestamp.pbobjc.m index 14161159..f35e435d 100644 --- a/objectivec/google/protobuf/Timestamp.pbobjc.m +++ b/objectivec/google/protobuf/Timestamp.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/Timestamp.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBTimestampRoot @implementation GPBTimestampRoot @@ -80,4 +83,6 @@ typedef struct GPBTimestamp__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Type.pbobjc.h b/objectivec/google/protobuf/Type.pbobjc.h index efaeab39..590d970b 100644 --- a/objectivec/google/protobuf/Type.pbobjc.h +++ b/objectivec/google/protobuf/Type.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN @class GPBAny; @@ -365,4 +368,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Type.pbobjc.m b/objectivec/google/protobuf/Type.pbobjc.m index 175c0233..5554a222 100644 --- a/objectivec/google/protobuf/Type.pbobjc.m +++ b/objectivec/google/protobuf/Type.pbobjc.m @@ -7,6 +7,9 @@ #import "google/protobuf/SourceContext.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBTypeRoot @implementation GPBTypeRoot @@ -685,4 +688,6 @@ typedef struct GPBOption__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/protobuf/Wrappers.pbobjc.h index 0ca439a8..46510500 100644 --- a/objectivec/google/protobuf/Wrappers.pbobjc.h +++ b/objectivec/google/protobuf/Wrappers.pbobjc.h @@ -9,6 +9,9 @@ // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + CF_EXTERN_C_BEGIN NS_ASSUME_NONNULL_BEGIN @@ -174,4 +177,6 @@ NS_ASSUME_NONNULL_END CF_EXTERN_C_END +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/protobuf/Wrappers.pbobjc.m index b1b5be69..5cc6c2e4 100644 --- a/objectivec/google/protobuf/Wrappers.pbobjc.m +++ b/objectivec/google/protobuf/Wrappers.pbobjc.m @@ -5,6 +5,9 @@ #import "google/protobuf/Wrappers.pbobjc.h" // @@protoc_insertion_point(imports) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #pragma mark - GPBWrappersRoot @implementation GPBWrappersRoot @@ -412,4 +415,6 @@ typedef struct GPBBytesValue__storage_ { @end +#pragma clang diagnostic pop + // @@protoc_insertion_point(global_scope) From 1b0ff34b90330187e0e32251664c46789c9710d0 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Tue, 19 Apr 2016 15:14:31 -0700 Subject: [PATCH 084/123] Add missing includes in field mask test --- src/google/protobuf/util/field_mask_util_test.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc index b3787857..9b7fb62a 100644 --- a/src/google/protobuf/util/field_mask_util_test.cc +++ b/src/google/protobuf/util/field_mask_util_test.cc @@ -30,6 +30,8 @@ #include +#include + #include #include #include From 75626ed79c726ed9fd96d9d143ce6b6c88413bf8 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Fri, 8 Apr 2016 12:19:10 +0100 Subject: [PATCH 085/123] Add C# codegen changes to enum value names (mostly C++) Overview of changes: - A new C#-specific command-line option, legacy_enum_values to revert to the old behavior - When legacy_enum_values isn't specified, we strip the enum name as a prefix, and PascalCase the value name - A new attribute within the C# code so that we can always tell the original in-proto name Regenerating the C# code with legacy_enum_values leads to code which still compiles and works - but there's more still to do. --- Makefile.am | 1 + .../Google.Protobuf/Google.Protobuf.csproj | 1 + .../Reflection/OriginalNameAttribute.cs | 58 ++++++++++++ .../protobuf/compiler/csharp/csharp_enum.cc | 20 +++- .../compiler/csharp/csharp_generator.cc | 3 + .../csharp/csharp_generator_unittest.cc | 20 +++- .../compiler/csharp/csharp_helpers.cc | 93 +++++++++++++++++++ .../protobuf/compiler/csharp/csharp_helpers.h | 2 + .../protobuf/compiler/csharp/csharp_options.h | 9 +- 9 files changed, 201 insertions(+), 6 deletions(-) create mode 100644 csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs diff --git a/Makefile.am b/Makefile.am index 4b5a44ff..b303a7e2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -154,6 +154,7 @@ csharp_EXTRA_DIST= \ csharp/src/Google.Protobuf/Reflection/MethodDescriptor.cs \ csharp/src/Google.Protobuf/Reflection/OneofAccessor.cs \ csharp/src/Google.Protobuf/Reflection/OneofDescriptor.cs \ + csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs \ csharp/src/Google.Protobuf/Reflection/PackageDescriptor.cs \ csharp/src/Google.Protobuf/Reflection/PartialClasses.cs \ csharp/src/Google.Protobuf/Reflection/ReflectionUtil.cs \ diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.csproj b/csharp/src/Google.Protobuf/Google.Protobuf.csproj index ef524baf..5557612a 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.csproj +++ b/csharp/src/Google.Protobuf/Google.Protobuf.csproj @@ -117,6 +117,7 @@ + diff --git a/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs b/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs new file mode 100644 index 00000000..27f9ab98 --- /dev/null +++ b/csharp/src/Google.Protobuf/Reflection/OriginalNameAttribute.cs @@ -0,0 +1,58 @@ +#region Copyright notice and license +// 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. +#endregion + +using System; + +namespace Google.Protobuf.Reflection +{ + /// + /// Specifies the original name (in the .proto file) of a named element, + /// such as an enum value. + /// + [AttributeUsage(AttributeTargets.Field)] + public class OriginalNameAttribute : Attribute + { + /// + /// The name of the element in the .proto file. + /// + public string Name { get; set; } + + /// + /// Constructs a new attribute instance for the given name. + /// + /// The name of the element in the .proto file. + public OriginalNameAttribute(string name) + { + Name = ProtoPreconditions.CheckNotNull(name, nameof(name)); + } + } +} \ No newline at end of file diff --git a/src/google/protobuf/compiler/csharp/csharp_enum.cc b/src/google/protobuf/compiler/csharp/csharp_enum.cc index 9616f172..bdfcc2be 100644 --- a/src/google/protobuf/compiler/csharp/csharp_enum.cc +++ b/src/google/protobuf/compiler/csharp/csharp_enum.cc @@ -41,6 +41,7 @@ #include #include #include +#include using google::protobuf::internal::scoped_ptr; @@ -64,11 +65,24 @@ void EnumGenerator::Generate(io::Printer* printer) { "access_level", class_access_level(), "name", descriptor_->name()); printer->Indent(); + std::set used_names; for (int i = 0; i < descriptor_->value_count(); i++) { WriteEnumValueDocComment(printer, descriptor_->value(i)); - printer->Print("$name$ = $number$,\n", - "name", descriptor_->value(i)->name(), - "number", SimpleItoa(descriptor_->value(i)->number())); + string original_name = descriptor_->value(i)->name(); + string name = options()->legacy_enum_values + ? descriptor_->value(i)->name() + : GetEnumValueName(descriptor_->name(), descriptor_->value(i)->name()); + // Make sure we don't get any duplicate names due to prefix removal. + while (!used_names.insert(name).second) { + // It's possible we'll end up giving this warning multiple times, but that's better than not at all. + GOOGLE_LOG(WARNING) << "Duplicate enum value " << name << " (originally " << original_name + << ") in " << descriptor_->name() << "; adding underscore to distinguish"; + name += "_"; + } + printer->Print("[pbr::OriginalName(\"$original_name$\")] $name$ = $number$,\n", + "original_name", original_name, + "name", name, + "number", SimpleItoa(descriptor_->value(i)->number())); } printer->Outdent(); printer->Print("}\n"); diff --git a/src/google/protobuf/compiler/csharp/csharp_generator.cc b/src/google/protobuf/compiler/csharp/csharp_generator.cc index c13ed65b..d74e8c88 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator.cc @@ -83,6 +83,9 @@ bool Generator::Generate( cli_options.base_namespace_specified = true; } else if (options[i].first == "internal_access") { cli_options.internal_access = true; + } else if (options[i].first == "legacy_enum_values") { + // TODO: Remove this before final release + cli_options.legacy_enum_values = true; } else { *error = "Unknown generator option: " + options[i].first; return false; diff --git a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc index 7ef7df42..5755fee0 100644 --- a/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc +++ b/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc @@ -30,8 +30,8 @@ #include -#include #include +#include #include #include @@ -45,7 +45,23 @@ namespace compiler { namespace csharp { namespace { -// TODO(jtattermusch): add some tests. +TEST(CSharpEnumValue, PascalCasedPrefixStripping) { + EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "FOO__BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "FOO_BAR_BAZ")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "Foo_BarBaz")); + EXPECT_EQ("Bar", GetEnumValueName("FO_O", "FOO_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("FOO", "F_O_O_BAR")); + EXPECT_EQ("Bar", GetEnumValueName("Foo", "BAR")); + EXPECT_EQ("BarBaz", GetEnumValueName("Foo", "BAR_BAZ")); + EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO")); + EXPECT_EQ("Foo", GetEnumValueName("Foo", "FOO___")); + // Identifiers can't start with digits + EXPECT_EQ("_2Bar", GetEnumValueName("Foo", "FOO_2_BAR")); + EXPECT_EQ("_2", GetEnumValueName("Foo", "FOO___2")); +} } // namespace } // namespace csharp diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index 41265f9a..efd01556 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -178,6 +178,99 @@ std::string UnderscoresToPascalCase(const std::string& input) { return UnderscoresToCamelCase(input, true); } +// Convert a string which is expected to be SHOUTY_CASE (but may not be *precisely* shouty) +// into a PascalCase string. Precise rules implemented: + +// Previous input character Current character Case +// Any Non-alphanumeric Skipped +// None - first char of input Alphanumeric Upper +// Non-letter (e.g. _ or 1) Alphanumeric Upper +// Numeric Alphanumeric Upper +// Lower letter Alphanumeric Same as current +// Upper letter Alphanumeric Lower +std::string ShoutyToPascalCase(const std::string& input) { + string result; + // Simple way of implementing "always start with upper" + char previous = '_'; + for (int i = 0; i < input.size(); i++) { + char current = input[i]; + if (!ascii_isalnum(current)) { + previous = current; + continue; + } + if (!ascii_isalnum(previous)) { + result += ascii_toupper(current); + } else if (ascii_isdigit(previous)) { + result += ascii_toupper(current); + } else if (ascii_islower(previous)) { + result += current; + } else { + result += ascii_tolower(current); + } + previous = current; + } + return result; +} + +// Attempt to remove a prefix from a value, ignoring casing and skipping underscores. +// (foo, foo_bar) => bar - underscore after prefix is skipped +// (FOO, foo_bar) => bar - casing is ignored +// (foo_bar, foobarbaz) => baz - underscore in prefix is ignored +// (foobar, foo_barbaz) => baz - underscore in value is ignored +// (foo, bar) => bar - prefix isn't matched; return original value +std::string TryRemovePrefix(const std::string& prefix, const std::string& value) { + // First normalize to a lower-case no-underscores prefix to match against + std::string prefix_to_match = ""; + for (size_t i = 0; i < prefix.size(); i++) { + if (prefix[i] != '_') { + prefix_to_match += ascii_tolower(prefix[i]); + } + } + + // This keeps track of how much of value we've consumed + size_t prefix_index, value_index; + for (prefix_index = 0, value_index = 0; + prefix_index < prefix_to_match.size() && value_index < value.size(); + value_index++) { + // Skip over underscores in the value + if (value[value_index] == '_') { + continue; + } + if (ascii_tolower(value[value_index]) != prefix_to_match[prefix_index++]) { + // Failed to match the prefix - bail out early. + return value; + } + } + + // If we didn't finish looking through the prefix, we can't strip it. + if (prefix_index < prefix_to_match.size()) { + return value; + } + + // Step over any underscores after the prefix + while (value_index < value.size() && value[value_index] == '_') { + value_index++; + } + + // If there's nothing left (e.g. it was a prefix with only underscores afterwards), don't strip. + if (value_index == value.size()) { + return value; + } + + return value.substr(value_index); +} + +std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) { + std::string stripped = TryRemovePrefix(enum_name, enum_value_name); + std::string result = ShoutyToPascalCase(stripped); + // Just in case we have an enum name of FOO and a value of FOO_2... make sure the returned + // string is a valid identifier. + if (ascii_isdigit(result[0])) { + result = "_" + result; + } + return result; +} + std::string ToCSharpName(const std::string& name, const FileDescriptor* file) { std::string result = GetFileNamespace(file); if (result != "") { diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index eaf85014..8830e957 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -93,6 +93,8 @@ inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_nex std::string UnderscoresToPascalCase(const std::string& input); +std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name); + // TODO(jtattermusch): perhaps we could move this to strutil std::string StringToBase64(const std::string& input); diff --git a/src/google/protobuf/compiler/csharp/csharp_options.h b/src/google/protobuf/compiler/csharp/csharp_options.h index 426fb3b5..4079bf7f 100644 --- a/src/google/protobuf/compiler/csharp/csharp_options.h +++ b/src/google/protobuf/compiler/csharp/csharp_options.h @@ -45,7 +45,8 @@ struct Options { file_extension(".cs"), base_namespace(""), base_namespace_specified(false), - internal_access(false) { + internal_access(false), + legacy_enum_values(false) { } // Extension of the generated file. Defaults to ".cs" string file_extension; @@ -68,6 +69,12 @@ struct Options { // Whether the generated classes should have accessibility level of "internal". // Defaults to false that generates "public" classes. bool internal_access; + // By default, C# codegen now uses PascalCased enum values names, after + // removing the enum type name as a prefix (if it *is* a prefix of the value). + // Setting this option reverts to the previous behavior of just copying the + // value name specified in the .proto file, allowing gradual migration. + // This option will be removed before final release. + bool legacy_enum_values; }; } // namespace csharp From 84ea2c7a81c69ce675d025074d6891a32ea3f629 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Fri, 8 Apr 2016 12:33:09 +0100 Subject: [PATCH 086/123] Regenerate all C# code and make it compile JSON tests fail, as we're not using OriginalNameAttribute yet. --- csharp/src/AddressBook/AddPerson.cs | 6 +- csharp/src/AddressBook/Addressbook.cs | 16 +-- csharp/src/AddressBook/ListPeople.cs | 6 +- .../Conformance.cs | 50 ++++---- .../Google.Protobuf.Conformance/Program.cs | 4 +- .../Google.Protobuf.Test/FieldCodecTest.cs | 2 +- .../GeneratedMessageTest.cs | 32 ++--- .../Google.Protobuf.Test/JsonFormatterTest.cs | 10 +- .../Google.Protobuf.Test/JsonParserTest.cs | 14 +-- .../Reflection/DescriptorsTest.cs | 2 +- .../Reflection/FieldAccessTest.cs | 4 +- .../Google.Protobuf.Test/SampleMessages.cs | 16 +-- .../Google.Protobuf.Test/TestCornerCases.cs | 4 +- .../TestProtos/MapUnittestProto3.cs | 8 +- .../TestProtos/UnittestImportProto3.cs | 8 +- .../TestProtos/UnittestIssues.cs | 32 ++--- .../TestProtos/UnittestProto3.cs | 94 +++++++-------- .../Google.Protobuf/Reflection/Descriptor.cs | 110 +++++++++--------- .../Reflection/FieldDescriptor.cs | 38 +++--- .../src/Google.Protobuf/WellKnownTypes/Api.cs | 20 ++-- .../Google.Protobuf/WellKnownTypes/Struct.cs | 4 +- .../Google.Protobuf/WellKnownTypes/Type.cs | 90 +++++++------- 22 files changed, 285 insertions(+), 285 deletions(-) diff --git a/csharp/src/AddressBook/AddPerson.cs b/csharp/src/AddressBook/AddPerson.cs index 6eeb9f6e..62d1788d 100644 --- a/csharp/src/AddressBook/AddPerson.cs +++ b/csharp/src/AddressBook/AddPerson.cs @@ -73,13 +73,13 @@ namespace Google.Protobuf.Examples.AddressBook switch (type) { case "mobile": - phoneNumber.Type = Person.Types.PhoneType.MOBILE; + phoneNumber.Type = Person.Types.PhoneType.Mobile; break; case "home": - phoneNumber.Type = Person.Types.PhoneType.HOME; + phoneNumber.Type = Person.Types.PhoneType.Home; break; case "work": - phoneNumber.Type = Person.Types.PhoneType.WORK; + phoneNumber.Type = Person.Types.PhoneType.Work; break; default: output.Write("Unknown phone type. Using default."); diff --git a/csharp/src/AddressBook/Addressbook.cs b/csharp/src/AddressBook/Addressbook.cs index 166dd49a..362e1cb6 100644 --- a/csharp/src/AddressBook/Addressbook.cs +++ b/csharp/src/AddressBook/Addressbook.cs @@ -228,9 +228,9 @@ namespace Google.Protobuf.Examples.AddressBook { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Types { public enum PhoneType { - MOBILE = 0, - HOME = 1, - WORK = 2, + [pbr::OriginalName("MOBILE")] Mobile = 0, + [pbr::OriginalName("HOME")] Home = 1, + [pbr::OriginalName("WORK")] Work = 2, } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] @@ -273,7 +273,7 @@ namespace Google.Protobuf.Examples.AddressBook { /// Field number for the "type" field. public const int TypeFieldNumber = 2; - private global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType type_ = global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE; + private global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType type_ = 0; public global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType Type { get { return type_; } set { @@ -300,7 +300,7 @@ namespace Google.Protobuf.Examples.AddressBook { public override int GetHashCode() { int hash = 1; if (Number.Length != 0) hash ^= Number.GetHashCode(); - if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) hash ^= Type.GetHashCode(); + if (Type != 0) hash ^= Type.GetHashCode(); return hash; } @@ -313,7 +313,7 @@ namespace Google.Protobuf.Examples.AddressBook { output.WriteRawTag(10); output.WriteString(Number); } - if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) { + if (Type != 0) { output.WriteRawTag(16); output.WriteEnum((int) Type); } @@ -324,7 +324,7 @@ namespace Google.Protobuf.Examples.AddressBook { if (Number.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(Number); } - if (Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) { + if (Type != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); } return size; @@ -337,7 +337,7 @@ namespace Google.Protobuf.Examples.AddressBook { if (other.Number.Length != 0) { Number = other.Number; } - if (other.Type != global::Google.Protobuf.Examples.AddressBook.Person.Types.PhoneType.MOBILE) { + if (other.Type != 0) { Type = other.Type; } } diff --git a/csharp/src/AddressBook/ListPeople.cs b/csharp/src/AddressBook/ListPeople.cs index 3979430f..3758c1bc 100644 --- a/csharp/src/AddressBook/ListPeople.cs +++ b/csharp/src/AddressBook/ListPeople.cs @@ -55,13 +55,13 @@ namespace Google.Protobuf.Examples.AddressBook { switch (phoneNumber.Type) { - case Person.Types.PhoneType.MOBILE: + case Person.Types.PhoneType.Mobile: Console.Write(" Mobile phone #: "); break; - case Person.Types.PhoneType.HOME: + case Person.Types.PhoneType.Home: Console.Write(" Home phone #: "); break; - case Person.Types.PhoneType.WORK: + case Person.Types.PhoneType.Work: Console.Write(" Work phone #: "); break; } diff --git a/csharp/src/Google.Protobuf.Conformance/Conformance.cs b/csharp/src/Google.Protobuf.Conformance/Conformance.cs index 7d85d28c..1674a673 100644 --- a/csharp/src/Google.Protobuf.Conformance/Conformance.cs +++ b/csharp/src/Google.Protobuf.Conformance/Conformance.cs @@ -199,15 +199,15 @@ namespace Conformance { } #region Enums public enum WireFormat { - UNSPECIFIED = 0, - PROTOBUF = 1, - JSON = 2, + [pbr::OriginalName("UNSPECIFIED")] Unspecified = 0, + [pbr::OriginalName("PROTOBUF")] Protobuf = 1, + [pbr::OriginalName("JSON")] Json = 2, } public enum ForeignEnum { - FOREIGN_FOO = 0, - FOREIGN_BAR = 1, - FOREIGN_BAZ = 2, + [pbr::OriginalName("FOREIGN_FOO")] ForeignFoo = 0, + [pbr::OriginalName("FOREIGN_BAR")] ForeignBar = 1, + [pbr::OriginalName("FOREIGN_BAZ")] ForeignBaz = 2, } #endregion @@ -278,7 +278,7 @@ namespace Conformance { /// Field number for the "requested_output_format" field. public const int RequestedOutputFormatFieldNumber = 3; - private global::Conformance.WireFormat requestedOutputFormat_ = global::Conformance.WireFormat.UNSPECIFIED; + private global::Conformance.WireFormat requestedOutputFormat_ = 0; /// /// Which format should the testee serialize its message to? /// @@ -328,7 +328,7 @@ namespace Conformance { int hash = 1; if (payloadCase_ == PayloadOneofCase.ProtobufPayload) hash ^= ProtobufPayload.GetHashCode(); if (payloadCase_ == PayloadOneofCase.JsonPayload) hash ^= JsonPayload.GetHashCode(); - if (RequestedOutputFormat != global::Conformance.WireFormat.UNSPECIFIED) hash ^= RequestedOutputFormat.GetHashCode(); + if (RequestedOutputFormat != 0) hash ^= RequestedOutputFormat.GetHashCode(); hash ^= (int) payloadCase_; return hash; } @@ -346,7 +346,7 @@ namespace Conformance { output.WriteRawTag(18); output.WriteString(JsonPayload); } - if (RequestedOutputFormat != global::Conformance.WireFormat.UNSPECIFIED) { + if (RequestedOutputFormat != 0) { output.WriteRawTag(24); output.WriteEnum((int) RequestedOutputFormat); } @@ -360,7 +360,7 @@ namespace Conformance { if (payloadCase_ == PayloadOneofCase.JsonPayload) { size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonPayload); } - if (RequestedOutputFormat != global::Conformance.WireFormat.UNSPECIFIED) { + if (RequestedOutputFormat != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) RequestedOutputFormat); } return size; @@ -370,7 +370,7 @@ namespace Conformance { if (other == null) { return; } - if (other.RequestedOutputFormat != global::Conformance.WireFormat.UNSPECIFIED) { + if (other.RequestedOutputFormat != 0) { RequestedOutputFormat = other.RequestedOutputFormat; } switch (other.PayloadCase) { @@ -1044,7 +1044,7 @@ namespace Conformance { /// Field number for the "optional_nested_enum" field. public const int OptionalNestedEnumFieldNumber = 21; - private global::Conformance.TestAllTypes.Types.NestedEnum optionalNestedEnum_ = global::Conformance.TestAllTypes.Types.NestedEnum.FOO; + private global::Conformance.TestAllTypes.Types.NestedEnum optionalNestedEnum_ = 0; public global::Conformance.TestAllTypes.Types.NestedEnum OptionalNestedEnum { get { return optionalNestedEnum_; } set { @@ -1054,7 +1054,7 @@ namespace Conformance { /// Field number for the "optional_foreign_enum" field. public const int OptionalForeignEnumFieldNumber = 22; - private global::Conformance.ForeignEnum optionalForeignEnum_ = global::Conformance.ForeignEnum.FOREIGN_FOO; + private global::Conformance.ForeignEnum optionalForeignEnum_ = 0; public global::Conformance.ForeignEnum OptionalForeignEnum { get { return optionalForeignEnum_; } set { @@ -2079,8 +2079,8 @@ namespace Conformance { if (OptionalBytes.Length != 0) hash ^= OptionalBytes.GetHashCode(); if (optionalNestedMessage_ != null) hash ^= OptionalNestedMessage.GetHashCode(); if (optionalForeignMessage_ != null) hash ^= OptionalForeignMessage.GetHashCode(); - if (OptionalNestedEnum != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) hash ^= OptionalNestedEnum.GetHashCode(); - if (OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) hash ^= OptionalForeignEnum.GetHashCode(); + if (OptionalNestedEnum != 0) hash ^= OptionalNestedEnum.GetHashCode(); + if (OptionalForeignEnum != 0) hash ^= OptionalForeignEnum.GetHashCode(); if (OptionalStringPiece.Length != 0) hash ^= OptionalStringPiece.GetHashCode(); if (OptionalCord.Length != 0) hash ^= OptionalCord.GetHashCode(); if (recursiveMessage_ != null) hash ^= RecursiveMessage.GetHashCode(); @@ -2247,11 +2247,11 @@ namespace Conformance { output.WriteRawTag(154, 1); output.WriteMessage(OptionalForeignMessage); } - if (OptionalNestedEnum != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) { + if (OptionalNestedEnum != 0) { output.WriteRawTag(168, 1); output.WriteEnum((int) OptionalNestedEnum); } - if (OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) { + if (OptionalForeignEnum != 0) { output.WriteRawTag(176, 1); output.WriteEnum((int) OptionalForeignEnum); } @@ -2492,10 +2492,10 @@ namespace Conformance { if (optionalForeignMessage_ != null) { size += 2 + pb::CodedOutputStream.ComputeMessageSize(OptionalForeignMessage); } - if (OptionalNestedEnum != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) { + if (OptionalNestedEnum != 0) { size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OptionalNestedEnum); } - if (OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) { + if (OptionalForeignEnum != 0) { size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) OptionalForeignEnum); } if (OptionalStringPiece.Length != 0) { @@ -2719,10 +2719,10 @@ namespace Conformance { } OptionalForeignMessage.MergeFrom(other.OptionalForeignMessage); } - if (other.OptionalNestedEnum != global::Conformance.TestAllTypes.Types.NestedEnum.FOO) { + if (other.OptionalNestedEnum != 0) { OptionalNestedEnum = other.OptionalNestedEnum; } - if (other.OptionalForeignEnum != global::Conformance.ForeignEnum.FOREIGN_FOO) { + if (other.OptionalForeignEnum != 0) { OptionalForeignEnum = other.OptionalForeignEnum; } if (other.OptionalStringPiece.Length != 0) { @@ -3448,13 +3448,13 @@ namespace Conformance { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Types { public enum NestedEnum { - FOO = 0, - BAR = 1, - BAZ = 2, + [pbr::OriginalName("FOO")] Foo = 0, + [pbr::OriginalName("BAR")] Bar = 1, + [pbr::OriginalName("BAZ")] Baz = 2, /// /// Intentionally negative. /// - NEG = -1, + [pbr::OriginalName("NEG")] Neg = -1, } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] diff --git a/csharp/src/Google.Protobuf.Conformance/Program.cs b/csharp/src/Google.Protobuf.Conformance/Program.cs index f3f7e295..19827c48 100644 --- a/csharp/src/Google.Protobuf.Conformance/Program.cs +++ b/csharp/src/Google.Protobuf.Conformance/Program.cs @@ -109,10 +109,10 @@ namespace Google.Protobuf.Conformance { switch (request.RequestedOutputFormat) { - case global::Conformance.WireFormat.JSON: + case global::Conformance.WireFormat.Json: var formatter = new JsonFormatter(new JsonFormatter.Settings(false, typeRegistry)); return new ConformanceResponse { JsonPayload = formatter.Format(message) }; - case global::Conformance.WireFormat.PROTOBUF: + case global::Conformance.WireFormat.Protobuf: return new ConformanceResponse { ProtobufPayload = message.ToByteString() }; default: throw new Exception("Unsupported request output format: " + request.PayloadCase); diff --git a/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs index 38ba227f..c616470e 100644 --- a/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs +++ b/csharp/src/Google.Protobuf.Test/FieldCodecTest.cs @@ -58,7 +58,7 @@ namespace Google.Protobuf new FieldCodecTestData(FieldCodec.ForFloat(100), 1234.5f, "Float"), new FieldCodecTestData(FieldCodec.ForDouble(100), 1234567890.5d, "Double"), new FieldCodecTestData( - FieldCodec.ForEnum(100, t => (int) t, t => (ForeignEnum) t), ForeignEnum.FOREIGN_BAZ, "Enum"), + FieldCodec.ForEnum(100, t => (int) t, t => (ForeignEnum) t), ForeignEnum.ForeignBaz, "Enum"), new FieldCodecTestData( FieldCodec.ForMessage(100, ForeignMessage.Parser), new ForeignMessage { C = 10 }, "Message"), }; diff --git a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs index 5c2a052b..8b153d69 100644 --- a/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs +++ b/csharp/src/Google.Protobuf.Test/GeneratedMessageTest.cs @@ -66,13 +66,13 @@ namespace Google.Protobuf Assert.AreEqual(0, message.SingleFixed32); Assert.AreEqual(0L, message.SingleFixed64); Assert.AreEqual(0.0f, message.SingleFloat); - Assert.AreEqual(ForeignEnum.FOREIGN_UNSPECIFIED, message.SingleForeignEnum); + Assert.AreEqual(ForeignEnum.ForeignUnspecified, message.SingleForeignEnum); Assert.IsNull(message.SingleForeignMessage); - Assert.AreEqual(ImportEnum.IMPORT_ENUM_UNSPECIFIED, message.SingleImportEnum); + Assert.AreEqual(ImportEnum.Unspecified, message.SingleImportEnum); Assert.IsNull(message.SingleImportMessage); Assert.AreEqual(0, message.SingleInt32); Assert.AreEqual(0L, message.SingleInt64); - Assert.AreEqual(TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED, message.SingleNestedEnum); + Assert.AreEqual(TestAllTypes.Types.NestedEnum.Unspecified, message.SingleNestedEnum); Assert.IsNull(message.SingleNestedMessage); Assert.IsNull(message.SinglePublicImportMessage); Assert.AreEqual(0, message.SingleSfixed32); @@ -145,13 +145,13 @@ namespace Google.Protobuf SingleFixed32 = 23, SingleFixed64 = 1234567890123, SingleFloat = 12.25f, - SingleForeignEnum = ForeignEnum.FOREIGN_BAR, + SingleForeignEnum = ForeignEnum.ForeignBar, SingleForeignMessage = new ForeignMessage { C = 10 }, - SingleImportEnum = ImportEnum.IMPORT_BAZ, + SingleImportEnum = ImportEnum.ImportBaz, SingleImportMessage = new ImportMessage { D = 20 }, SingleInt32 = 100, SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, SinglePublicImportMessage = new PublicImportMessage { E = 54 }, SingleSfixed32 = -123, @@ -179,13 +179,13 @@ namespace Google.Protobuf RepeatedFixed32 = { uint.MaxValue, 23 }, RepeatedFixed64 = { ulong.MaxValue, 1234567890123 }, RepeatedFloat = { 100f, 12.25f }, - RepeatedForeignEnum = { ForeignEnum.FOREIGN_FOO, ForeignEnum.FOREIGN_BAR }, + RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar }, RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } }, - RepeatedImportEnum = { ImportEnum.IMPORT_BAZ, ImportEnum.IMPORT_ENUM_UNSPECIFIED }, + RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified }, RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } }, RepeatedInt32 = { 100, 200 }, RepeatedInt64 = { 3210987654321, long.MaxValue }, - RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.NEG }, + RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } }, RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } }, RepeatedSfixed32 = { -123, 123 }, @@ -224,8 +224,8 @@ namespace Google.Protobuf { 5, new ForeignMessage() }, }, MapInt32Enum = { - { 1, MapEnum.MAP_ENUM_BAR }, - { 2000, MapEnum.MAP_ENUM_FOO } + { 1, MapEnum.Bar }, + { 2000, MapEnum.Foo } } }; @@ -249,7 +249,7 @@ namespace Google.Protobuf Assert.AreEqual(1, parsed.MapInt32Bytes.Count); Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]); } - + [Test] public void MapWithOnlyValue() { @@ -449,7 +449,7 @@ namespace Google.Protobuf SingleFloat = 12.25f, SingleInt32 = 100, SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, SingleSfixed32 = -123, SingleSfixed64 = -12345678901234, SingleSint32 = -456, @@ -479,7 +479,7 @@ namespace Google.Protobuf RepeatedFloat = { 100f, 12.25f }, RepeatedInt32 = { 100, 200 }, RepeatedInt64 = { 3210987654321, long.MaxValue }, - RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.NEG }, + RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, RepeatedSfixed32 = { -123, 123 }, RepeatedSfixed64 = { -12345678901234, 12345678901234 }, RepeatedSint32 = { -456, 100 }, @@ -670,7 +670,7 @@ namespace Google.Protobuf { // 130, 3 is the message tag // 1 is the data length - but there's no data. - var data = new byte[] { 130, 3, 1 }; + var data = new byte[] { 130, 3, 1 }; Assert.Throws(() => TestAllTypes.Parser.ParseFrom(data)); } @@ -720,4 +720,4 @@ namespace Google.Protobuf Assert.AreEqual("{ \"c\": 31 }", writer.ToString()); } } -} +} \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs index 344d727b..0b6cd7e6 100644 --- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs @@ -75,13 +75,13 @@ namespace Google.Protobuf SingleFixed32 = 23, SingleFixed64 = 1234567890123, SingleFloat = 12.25f, - SingleForeignEnum = ForeignEnum.FOREIGN_BAR, + SingleForeignEnum = ForeignEnum.ForeignBar, SingleForeignMessage = new ForeignMessage { C = 10 }, - SingleImportEnum = ImportEnum.IMPORT_BAZ, + SingleImportEnum = ImportEnum.ImportBaz, SingleImportMessage = new ImportMessage { D = 20 }, SingleInt32 = 100, SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, SinglePublicImportMessage = new PublicImportMessage { E = 54 }, SingleSfixed32 = -123, @@ -174,14 +174,14 @@ namespace Google.Protobuf [Test] public void UnknownEnumValueNumeric_RepeatedField() { - var message = new TestAllTypes { RepeatedForeignEnum = { ForeignEnum.FOREIGN_BAZ, (ForeignEnum) 100, ForeignEnum.FOREIGN_FOO } }; + var message = new TestAllTypes { RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } }; AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 100, 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message)); } [Test] public void UnknownEnumValueNumeric_MapField() { - var message = new TestMap { MapInt32Enum = { { 1, MapEnum.MAP_ENUM_FOO }, { 2, (MapEnum) 100 }, { 3, MapEnum.MAP_ENUM_BAR } } }; + var message = new TestMap { MapInt32Enum = { { 1, MapEnum.Foo }, { 2, (MapEnum) 100 }, { 3, MapEnum.Bar } } }; AssertJson("{ 'mapInt32Enum': { '1': 'MAP_ENUM_FOO', '2': 100, '3': 'MAP_ENUM_BAR' } }", JsonFormatter.Default.Format(message)); } diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs index d21da58a..684f52b4 100644 --- a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs @@ -142,8 +142,8 @@ namespace Google.Protobuf [TestCase(typeof(DoubleValue), "1.5", 1.5d)] public void Wrappers_Standalone(System.Type wrapperType, string json, object expectedValue) { - IMessage parsed = (IMessage) Activator.CreateInstance(wrapperType); - IMessage expected = (IMessage) Activator.CreateInstance(wrapperType); + IMessage parsed = (IMessage)Activator.CreateInstance(wrapperType); + IMessage expected = (IMessage)Activator.CreateInstance(wrapperType); JsonParser.Default.Merge(parsed, "null"); Assert.AreEqual(expected, parsed); @@ -640,7 +640,7 @@ namespace Google.Protobuf var parsed = Timestamp.Parser.ParseJson(json); Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString()); } - + [Test] [TestCase("2015-10-09 14:46:23.123456789Z", Description = "No T between date and time")] [TestCase("2015/10/09T14:46:23.123456789Z", Description = "Wrong date separators")] @@ -886,9 +886,9 @@ namespace Google.Protobuf } [Test] - [TestCase("\"FOREIGN_BAR\"", ForeignEnum.FOREIGN_BAR)] - [TestCase("5", ForeignEnum.FOREIGN_BAR)] - [TestCase("100", (ForeignEnum) 100)] + [TestCase("\"FOREIGN_BAR\"", ForeignEnum.ForeignBar)] + [TestCase("5", ForeignEnum.ForeignBar)] + [TestCase("100", (ForeignEnum)100)] public void EnumValid(string value, ForeignEnum expectedValue) { string json = "{ \"singleForeignEnum\": " + value + " }"; @@ -922,4 +922,4 @@ namespace Google.Protobuf return '"' + text + '"'; } } -} +} \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs index 086a4e98..52d5a676 100644 --- a/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs +++ b/csharp/src/Google.Protobuf.Test/Reflection/DescriptorsTest.cs @@ -195,7 +195,7 @@ namespace Google.Protobuf.Reflection Assert.AreEqual(value, enumType.Values[1]); Assert.AreEqual("FOREIGN_FOO", value.Name); Assert.AreEqual(4, value.Number); - Assert.AreEqual((int) ForeignEnum.FOREIGN_FOO, value.Number); + Assert.AreEqual((int) ForeignEnum.ForeignFoo, value.Number); Assert.AreEqual(value, enumType.FindValueByNumber(4)); Assert.Null(enumType.FindValueByName("NO_SUCH_VALUE")); for (int i = 0; i < enumType.Values.Count; i++) diff --git a/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs b/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs index 936e41c6..a488af30 100644 --- a/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs +++ b/csharp/src/Google.Protobuf.Test/Reflection/FieldAccessTest.cs @@ -128,7 +128,7 @@ namespace Google.Protobuf.Reflection fields[TestAllTypes.SingleInt32FieldNumber].Accessor.SetValue(message, 500); fields[TestAllTypes.SingleStringFieldNumber].Accessor.SetValue(message, "It's a string"); fields[TestAllTypes.SingleBytesFieldNumber].Accessor.SetValue(message, ByteString.CopyFrom(99, 98, 97)); - fields[TestAllTypes.SingleForeignEnumFieldNumber].Accessor.SetValue(message, ForeignEnum.FOREIGN_FOO); + fields[TestAllTypes.SingleForeignEnumFieldNumber].Accessor.SetValue(message, ForeignEnum.ForeignFoo); fields[TestAllTypes.SingleForeignMessageFieldNumber].Accessor.SetValue(message, new ForeignMessage { C = 12345 }); fields[TestAllTypes.SingleDoubleFieldNumber].Accessor.SetValue(message, 20150701.5); @@ -138,7 +138,7 @@ namespace Google.Protobuf.Reflection SingleInt32 = 500, SingleString = "It's a string", SingleBytes = ByteString.CopyFrom(99, 98, 97), - SingleForeignEnum = ForeignEnum.FOREIGN_FOO, + SingleForeignEnum = ForeignEnum.ForeignFoo, SingleForeignMessage = new ForeignMessage { C = 12345 }, SingleDouble = 20150701.5 }; diff --git a/csharp/src/Google.Protobuf.Test/SampleMessages.cs b/csharp/src/Google.Protobuf.Test/SampleMessages.cs index 8a9c7f86..ffa4e2a7 100644 --- a/csharp/src/Google.Protobuf.Test/SampleMessages.cs +++ b/csharp/src/Google.Protobuf.Test/SampleMessages.cs @@ -54,13 +54,13 @@ namespace Google.Protobuf SingleFixed32 = 23, SingleFixed64 = 1234567890123, SingleFloat = 12.25f, - SingleForeignEnum = ForeignEnum.FOREIGN_BAR, + SingleForeignEnum = ForeignEnum.ForeignBar, SingleForeignMessage = new ForeignMessage { C = 10 }, - SingleImportEnum = ImportEnum.IMPORT_BAZ, + SingleImportEnum = ImportEnum.ImportBaz, SingleImportMessage = new ImportMessage { D = 20 }, SingleInt32 = 100, SingleInt64 = 3210987654321, - SingleNestedEnum = TestAllTypes.Types.NestedEnum.FOO, + SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, SinglePublicImportMessage = new PublicImportMessage { E = 54 }, SingleSfixed32 = -123, @@ -76,13 +76,13 @@ namespace Google.Protobuf RepeatedFixed32 = { UInt32.MaxValue, 23 }, RepeatedFixed64 = { UInt64.MaxValue, 1234567890123 }, RepeatedFloat = { 100f, 12.25f }, - RepeatedForeignEnum = { ForeignEnum.FOREIGN_FOO, ForeignEnum.FOREIGN_BAR }, + RepeatedForeignEnum = { ForeignEnum.ForeignFoo, ForeignEnum.ForeignBar }, RepeatedForeignMessage = { new ForeignMessage(), new ForeignMessage { C = 10 } }, - RepeatedImportEnum = { ImportEnum.IMPORT_BAZ, ImportEnum.IMPORT_ENUM_UNSPECIFIED }, + RepeatedImportEnum = { ImportEnum.ImportBaz, ImportEnum.Unspecified }, RepeatedImportMessage = { new ImportMessage { D = 20 }, new ImportMessage { D = 25 } }, RepeatedInt32 = { 100, 200 }, RepeatedInt64 = { 3210987654321, Int64.MaxValue }, - RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.FOO, TestAllTypes.Types.NestedEnum.NEG }, + RepeatedNestedEnum = { TestAllTypes.Types.NestedEnum.Foo, TestAllTypes.Types.NestedEnum.Neg }, RepeatedNestedMessage = { new TestAllTypes.Types.NestedMessage { Bb = 35 }, new TestAllTypes.Types.NestedMessage { Bb = 10 } }, RepeatedPublicImportMessage = { new PublicImportMessage { E = 54 }, new PublicImportMessage { E = -1 } }, RepeatedSfixed32 = { -123, 123 }, @@ -92,8 +92,8 @@ namespace Google.Protobuf RepeatedString = { "foo", "bar" }, RepeatedUint32 = { UInt32.MaxValue, UInt32.MinValue }, RepeatedUint64 = { UInt64.MaxValue, UInt32.MinValue }, - OneofString = "Oneof string" + OneofString = "Oneof string" }; } } -} +} \ No newline at end of file diff --git a/csharp/src/Google.Protobuf.Test/TestCornerCases.cs b/csharp/src/Google.Protobuf.Test/TestCornerCases.cs index 03fa1855..248f5fa9 100644 --- a/csharp/src/Google.Protobuf.Test/TestCornerCases.cs +++ b/csharp/src/Google.Protobuf.Test/TestCornerCases.cs @@ -43,8 +43,8 @@ namespace Google.Protobuf NegativeEnumMessage msg = new NegativeEnumMessage { Value = NegativeEnum.MinusOne, - Values = { NegativeEnum.NEGATIVE_ENUM_ZERO, NegativeEnum.MinusOne, NegativeEnum.FiveBelow }, - PackedValues = { NegativeEnum.NEGATIVE_ENUM_ZERO, NegativeEnum.MinusOne, NegativeEnum.FiveBelow } + Values = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow }, + PackedValues = { NegativeEnum.Zero, NegativeEnum.MinusOne, NegativeEnum.FiveBelow } }; Assert.AreEqual(58, msg.CalculateSize()); diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs index 27c04787..3ba4a2b6 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/MapUnittestProto3.cs @@ -164,9 +164,9 @@ namespace Google.Protobuf.TestProtos { } #region Enums public enum MapEnum { - MAP_ENUM_FOO = 0, - MAP_ENUM_BAR = 1, - MAP_ENUM_BAZ = 2, + [pbr::OriginalName("MAP_ENUM_FOO")] Foo = 0, + [pbr::OriginalName("MAP_ENUM_BAR")] Bar = 1, + [pbr::OriginalName("MAP_ENUM_BAZ")] Baz = 2, } #endregion @@ -1358,7 +1358,7 @@ namespace Google.Protobuf.TestProtos { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Types { public enum Type { - TYPE_FOO = 0, + [pbr::OriginalName("TYPE_FOO")] Foo = 0, } } diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs index 7b824dc7..263e17c0 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestImportProto3.cs @@ -42,10 +42,10 @@ namespace Google.Protobuf.TestProtos { } #region Enums public enum ImportEnum { - IMPORT_ENUM_UNSPECIFIED = 0, - IMPORT_FOO = 7, - IMPORT_BAR = 8, - IMPORT_BAZ = 9, + [pbr::OriginalName("IMPORT_ENUM_UNSPECIFIED")] Unspecified = 0, + [pbr::OriginalName("IMPORT_FOO")] ImportFoo = 7, + [pbr::OriginalName("IMPORT_BAR")] ImportBar = 8, + [pbr::OriginalName("IMPORT_BAZ")] ImportBaz = 9, } #endregion diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs index 586f01c8..7d4451b0 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestIssues.cs @@ -66,14 +66,14 @@ namespace UnitTest.Issues.TestProtos { } #region Enums public enum NegativeEnum { - NEGATIVE_ENUM_ZERO = 0, - FiveBelow = -5, - MinusOne = -1, + [pbr::OriginalName("NEGATIVE_ENUM_ZERO")] Zero = 0, + [pbr::OriginalName("FiveBelow")] FiveBelow = -5, + [pbr::OriginalName("MinusOne")] MinusOne = -1, } public enum DeprecatedEnum { - DEPRECATED_ZERO = 0, - one = 1, + [pbr::OriginalName("DEPRECATED_ZERO")] DeprecatedZero = 0, + [pbr::OriginalName("one")] One = 1, } #endregion @@ -356,7 +356,7 @@ namespace UnitTest.Issues.TestProtos { /// Field number for the "value" field. public const int ValueFieldNumber = 1; - private global::UnitTest.Issues.TestProtos.NegativeEnum value_ = global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO; + private global::UnitTest.Issues.TestProtos.NegativeEnum value_ = 0; public global::UnitTest.Issues.TestProtos.NegativeEnum Value { get { return value_; } set { @@ -401,7 +401,7 @@ namespace UnitTest.Issues.TestProtos { public override int GetHashCode() { int hash = 1; - if (Value != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) hash ^= Value.GetHashCode(); + if (Value != 0) hash ^= Value.GetHashCode(); hash ^= values_.GetHashCode(); hash ^= packedValues_.GetHashCode(); return hash; @@ -412,7 +412,7 @@ namespace UnitTest.Issues.TestProtos { } public void WriteTo(pb::CodedOutputStream output) { - if (Value != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) { + if (Value != 0) { output.WriteRawTag(8); output.WriteEnum((int) Value); } @@ -422,7 +422,7 @@ namespace UnitTest.Issues.TestProtos { public int CalculateSize() { int size = 0; - if (Value != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) { + if (Value != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Value); } size += values_.CalculateSize(_repeated_values_codec); @@ -434,7 +434,7 @@ namespace UnitTest.Issues.TestProtos { if (other == null) { return; } - if (other.Value != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) { + if (other.Value != 0) { Value = other.Value; } values_.Add(other.values_); @@ -620,7 +620,7 @@ namespace UnitTest.Issues.TestProtos { /// Field number for the "EnumValue" field. public const int EnumValueFieldNumber = 5; - private global::UnitTest.Issues.TestProtos.DeprecatedEnum enumValue_ = global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO; + private global::UnitTest.Issues.TestProtos.DeprecatedEnum enumValue_ = 0; [global::System.ObsoleteAttribute()] public global::UnitTest.Issues.TestProtos.DeprecatedEnum EnumValue { get { return enumValue_; } @@ -665,7 +665,7 @@ namespace UnitTest.Issues.TestProtos { hash ^= primitiveArray_.GetHashCode(); if (messageValue_ != null) hash ^= MessageValue.GetHashCode(); hash ^= messageArray_.GetHashCode(); - if (EnumValue != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) hash ^= EnumValue.GetHashCode(); + if (EnumValue != 0) hash ^= EnumValue.GetHashCode(); hash ^= enumArray_.GetHashCode(); return hash; } @@ -685,7 +685,7 @@ namespace UnitTest.Issues.TestProtos { output.WriteMessage(MessageValue); } messageArray_.WriteTo(output, _repeated_messageArray_codec); - if (EnumValue != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) { + if (EnumValue != 0) { output.WriteRawTag(40); output.WriteEnum((int) EnumValue); } @@ -702,7 +702,7 @@ namespace UnitTest.Issues.TestProtos { size += 1 + pb::CodedOutputStream.ComputeMessageSize(MessageValue); } size += messageArray_.CalculateSize(_repeated_messageArray_codec); - if (EnumValue != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) { + if (EnumValue != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) EnumValue); } size += enumArray_.CalculateSize(_repeated_enumArray_codec); @@ -724,7 +724,7 @@ namespace UnitTest.Issues.TestProtos { MessageValue.MergeFrom(other.MessageValue); } messageArray_.Add(other.messageArray_); - if (other.EnumValue != global::UnitTest.Issues.TestProtos.DeprecatedEnum.DEPRECATED_ZERO) { + if (other.EnumValue != 0) { EnumValue = other.EnumValue; } enumArray_.Add(other.enumArray_); @@ -1435,7 +1435,7 @@ namespace UnitTest.Issues.TestProtos { public const int NameFieldNumber = 1; private string name_ = ""; /// - /// json_name field options are not properly handled during deserialization + /// Message for testing the effects for of the json_name option /// public string Name { get { return name_; } diff --git a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs index d8465448..b8d159bb 100644 --- a/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs +++ b/csharp/src/Google.Protobuf.Test/TestProtos/UnittestProto3.cs @@ -193,39 +193,39 @@ namespace Google.Protobuf.TestProtos { } #region Enums public enum ForeignEnum { - FOREIGN_UNSPECIFIED = 0, - FOREIGN_FOO = 4, - FOREIGN_BAR = 5, - FOREIGN_BAZ = 6, + [pbr::OriginalName("FOREIGN_UNSPECIFIED")] ForeignUnspecified = 0, + [pbr::OriginalName("FOREIGN_FOO")] ForeignFoo = 4, + [pbr::OriginalName("FOREIGN_BAR")] ForeignBar = 5, + [pbr::OriginalName("FOREIGN_BAZ")] ForeignBaz = 6, } /// /// Test an enum that has multiple values with the same number. /// public enum TestEnumWithDupValue { - TEST_ENUM_WITH_DUP_VALUE_UNSPECIFIED = 0, - FOO1 = 1, - BAR1 = 2, - BAZ = 3, - FOO2 = 1, - BAR2 = 2, + [pbr::OriginalName("TEST_ENUM_WITH_DUP_VALUE_UNSPECIFIED")] Unspecified = 0, + [pbr::OriginalName("FOO1")] Foo1 = 1, + [pbr::OriginalName("BAR1")] Bar1 = 2, + [pbr::OriginalName("BAZ")] Baz = 3, + [pbr::OriginalName("FOO2")] Foo2 = 1, + [pbr::OriginalName("BAR2")] Bar2 = 2, } /// /// Test an enum with large, unordered values. /// public enum TestSparseEnum { - TEST_SPARSE_ENUM_UNSPECIFIED = 0, - SPARSE_A = 123, - SPARSE_B = 62374, - SPARSE_C = 12589234, - SPARSE_D = -15, - SPARSE_E = -53452, + [pbr::OriginalName("TEST_SPARSE_ENUM_UNSPECIFIED")] Unspecified = 0, + [pbr::OriginalName("SPARSE_A")] SparseA = 123, + [pbr::OriginalName("SPARSE_B")] SparseB = 62374, + [pbr::OriginalName("SPARSE_C")] SparseC = 12589234, + [pbr::OriginalName("SPARSE_D")] SparseD = -15, + [pbr::OriginalName("SPARSE_E")] SparseE = -53452, /// /// In proto3, value 0 must be the first one specified /// SPARSE_F = 0; /// - SPARSE_G = 2, + [pbr::OriginalName("SPARSE_G")] SparseG = 2, } #endregion @@ -505,7 +505,7 @@ namespace Google.Protobuf.TestProtos { /// Field number for the "single_nested_enum" field. public const int SingleNestedEnumFieldNumber = 21; - private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum singleNestedEnum_ = global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED; + private global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum singleNestedEnum_ = 0; public global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum SingleNestedEnum { get { return singleNestedEnum_; } set { @@ -515,7 +515,7 @@ namespace Google.Protobuf.TestProtos { /// Field number for the "single_foreign_enum" field. public const int SingleForeignEnumFieldNumber = 22; - private global::Google.Protobuf.TestProtos.ForeignEnum singleForeignEnum_ = global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED; + private global::Google.Protobuf.TestProtos.ForeignEnum singleForeignEnum_ = 0; public global::Google.Protobuf.TestProtos.ForeignEnum SingleForeignEnum { get { return singleForeignEnum_; } set { @@ -525,7 +525,7 @@ namespace Google.Protobuf.TestProtos { /// Field number for the "single_import_enum" field. public const int SingleImportEnumFieldNumber = 23; - private global::Google.Protobuf.TestProtos.ImportEnum singleImportEnum_ = global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED; + private global::Google.Protobuf.TestProtos.ImportEnum singleImportEnum_ = 0; public global::Google.Protobuf.TestProtos.ImportEnum SingleImportEnum { get { return singleImportEnum_; } set { @@ -892,9 +892,9 @@ namespace Google.Protobuf.TestProtos { if (singleNestedMessage_ != null) hash ^= SingleNestedMessage.GetHashCode(); if (singleForeignMessage_ != null) hash ^= SingleForeignMessage.GetHashCode(); if (singleImportMessage_ != null) hash ^= SingleImportMessage.GetHashCode(); - if (SingleNestedEnum != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) hash ^= SingleNestedEnum.GetHashCode(); - if (SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) hash ^= SingleForeignEnum.GetHashCode(); - if (SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) hash ^= SingleImportEnum.GetHashCode(); + if (SingleNestedEnum != 0) hash ^= SingleNestedEnum.GetHashCode(); + if (SingleForeignEnum != 0) hash ^= SingleForeignEnum.GetHashCode(); + if (SingleImportEnum != 0) hash ^= SingleImportEnum.GetHashCode(); if (singlePublicImportMessage_ != null) hash ^= SinglePublicImportMessage.GetHashCode(); hash ^= repeatedInt32_.GetHashCode(); hash ^= repeatedInt64_.GetHashCode(); @@ -1003,15 +1003,15 @@ namespace Google.Protobuf.TestProtos { output.WriteRawTag(162, 1); output.WriteMessage(SingleImportMessage); } - if (SingleNestedEnum != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) { + if (SingleNestedEnum != 0) { output.WriteRawTag(168, 1); output.WriteEnum((int) SingleNestedEnum); } - if (SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) { + if (SingleForeignEnum != 0) { output.WriteRawTag(176, 1); output.WriteEnum((int) SingleForeignEnum); } - if (SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) { + if (SingleImportEnum != 0) { output.WriteRawTag(184, 1); output.WriteEnum((int) SingleImportEnum); } @@ -1115,13 +1115,13 @@ namespace Google.Protobuf.TestProtos { if (singleImportMessage_ != null) { size += 2 + pb::CodedOutputStream.ComputeMessageSize(SingleImportMessage); } - if (SingleNestedEnum != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) { + if (SingleNestedEnum != 0) { size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleNestedEnum); } - if (SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) { + if (SingleForeignEnum != 0) { size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleForeignEnum); } - if (SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) { + if (SingleImportEnum != 0) { size += 2 + pb::CodedOutputStream.ComputeEnumSize((int) SingleImportEnum); } if (singlePublicImportMessage_ != null) { @@ -1231,13 +1231,13 @@ namespace Google.Protobuf.TestProtos { } SingleImportMessage.MergeFrom(other.SingleImportMessage); } - if (other.SingleNestedEnum != global::Google.Protobuf.TestProtos.TestAllTypes.Types.NestedEnum.NESTED_ENUM_UNSPECIFIED) { + if (other.SingleNestedEnum != 0) { SingleNestedEnum = other.SingleNestedEnum; } - if (other.SingleForeignEnum != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) { + if (other.SingleForeignEnum != 0) { SingleForeignEnum = other.SingleForeignEnum; } - if (other.SingleImportEnum != global::Google.Protobuf.TestProtos.ImportEnum.IMPORT_ENUM_UNSPECIFIED) { + if (other.SingleImportEnum != 0) { SingleImportEnum = other.SingleImportEnum; } if (other.singlePublicImportMessage_ != null) { @@ -1526,14 +1526,14 @@ namespace Google.Protobuf.TestProtos { [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public static partial class Types { public enum NestedEnum { - NESTED_ENUM_UNSPECIFIED = 0, - FOO = 1, - BAR = 2, - BAZ = 3, + [pbr::OriginalName("NESTED_ENUM_UNSPECIFIED")] Unspecified = 0, + [pbr::OriginalName("FOO")] Foo = 1, + [pbr::OriginalName("BAR")] Bar = 2, + [pbr::OriginalName("BAZ")] Baz = 3, /// /// Intentionally negative. /// - NEG = -1, + [pbr::OriginalName("NEG")] Neg = -1, } [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] @@ -2793,7 +2793,7 @@ namespace Google.Protobuf.TestProtos { /// Field number for the "EnumField" field. public const int EnumFieldFieldNumber = 3; - private global::Google.Protobuf.TestProtos.ForeignEnum enumField_ = global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED; + private global::Google.Protobuf.TestProtos.ForeignEnum enumField_ = 0; public global::Google.Protobuf.TestProtos.ForeignEnum EnumField { get { return enumField_; } set { @@ -2873,7 +2873,7 @@ namespace Google.Protobuf.TestProtos { int hash = 1; if (PrimitiveField != 0) hash ^= PrimitiveField.GetHashCode(); if (StringField.Length != 0) hash ^= StringField.GetHashCode(); - if (EnumField != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) hash ^= EnumField.GetHashCode(); + if (EnumField != 0) hash ^= EnumField.GetHashCode(); if (messageField_ != null) hash ^= MessageField.GetHashCode(); hash ^= repeatedPrimitiveField_.GetHashCode(); hash ^= repeatedStringField_.GetHashCode(); @@ -2895,7 +2895,7 @@ namespace Google.Protobuf.TestProtos { output.WriteRawTag(18); output.WriteString(StringField); } - if (EnumField != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) { + if (EnumField != 0) { output.WriteRawTag(24); output.WriteEnum((int) EnumField); } @@ -2917,7 +2917,7 @@ namespace Google.Protobuf.TestProtos { if (StringField.Length != 0) { size += 1 + pb::CodedOutputStream.ComputeStringSize(StringField); } - if (EnumField != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) { + if (EnumField != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) EnumField); } if (messageField_ != null) { @@ -2940,7 +2940,7 @@ namespace Google.Protobuf.TestProtos { if (other.StringField.Length != 0) { StringField = other.StringField; } - if (other.EnumField != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) { + if (other.EnumField != 0) { EnumField = other.EnumField; } if (other.messageField_ != null) { @@ -3370,7 +3370,7 @@ namespace Google.Protobuf.TestProtos { /// Field number for the "sparse_enum" field. public const int SparseEnumFieldNumber = 1; - private global::Google.Protobuf.TestProtos.TestSparseEnum sparseEnum_ = global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED; + private global::Google.Protobuf.TestProtos.TestSparseEnum sparseEnum_ = 0; public global::Google.Protobuf.TestProtos.TestSparseEnum SparseEnum { get { return sparseEnum_; } set { @@ -3395,7 +3395,7 @@ namespace Google.Protobuf.TestProtos { public override int GetHashCode() { int hash = 1; - if (SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) hash ^= SparseEnum.GetHashCode(); + if (SparseEnum != 0) hash ^= SparseEnum.GetHashCode(); return hash; } @@ -3404,7 +3404,7 @@ namespace Google.Protobuf.TestProtos { } public void WriteTo(pb::CodedOutputStream output) { - if (SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) { + if (SparseEnum != 0) { output.WriteRawTag(8); output.WriteEnum((int) SparseEnum); } @@ -3412,7 +3412,7 @@ namespace Google.Protobuf.TestProtos { public int CalculateSize() { int size = 0; - if (SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) { + if (SparseEnum != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) SparseEnum); } return size; @@ -3422,7 +3422,7 @@ namespace Google.Protobuf.TestProtos { if (other == null) { return; } - if (other.SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) { + if (other.SparseEnum != 0) { SparseEnum = other.SparseEnum; } } diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs index 7de7b5fc..c003c0ff 100644 --- a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs @@ -1291,7 +1291,7 @@ namespace Google.Protobuf.Reflection { /// Field number for the "label" field. public const int LabelFieldNumber = 4; - private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label label_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL; + private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label label_ = 0; public global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label Label { get { return label_; } set { @@ -1301,7 +1301,7 @@ namespace Google.Protobuf.Reflection { /// Field number for the "type" field. public const int TypeFieldNumber = 5; - private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type type_ = global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE; + private global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type type_ = 0; /// /// If type_name is set, this need not be set. If both this and type_name /// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. @@ -1429,8 +1429,8 @@ namespace Google.Protobuf.Reflection { int hash = 1; if (Name.Length != 0) hash ^= Name.GetHashCode(); if (Number != 0) hash ^= Number.GetHashCode(); - if (Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) hash ^= Label.GetHashCode(); - if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) hash ^= Type.GetHashCode(); + if (Label != 0) hash ^= Label.GetHashCode(); + if (Type != 0) hash ^= Type.GetHashCode(); if (TypeName.Length != 0) hash ^= TypeName.GetHashCode(); if (Extendee.Length != 0) hash ^= Extendee.GetHashCode(); if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode(); @@ -1457,11 +1457,11 @@ namespace Google.Protobuf.Reflection { output.WriteRawTag(24); output.WriteInt32(Number); } - if (Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) { + if (Label != 0) { output.WriteRawTag(32); output.WriteEnum((int) Label); } - if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) { + if (Type != 0) { output.WriteRawTag(40); output.WriteEnum((int) Type); } @@ -1495,10 +1495,10 @@ namespace Google.Protobuf.Reflection { if (Number != 0) { size += 1 + pb::CodedOutputStream.ComputeInt32Size(Number); } - if (Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) { + if (Label != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Label); } - if (Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) { + if (Type != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Type); } if (TypeName.Length != 0) { @@ -1532,10 +1532,10 @@ namespace Google.Protobuf.Reflection { if (other.Number != 0) { Number = other.Number; } - if (other.Label != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) { + if (other.Label != 0) { Label = other.Label; } - if (other.Type != global::Google.Protobuf.Reflection.FieldDescriptorProto.Types.Type.TYPE_DOUBLE) { + if (other.Type != 0) { Type = other.Type; } if (other.TypeName.Length != 0) { @@ -1624,59 +1624,59 @@ namespace Google.Protobuf.Reflection { /// 0 is reserved for errors. /// Order is weird for historical reasons. /// - TYPE_DOUBLE = 1, - TYPE_FLOAT = 2, + [pbr::OriginalName("TYPE_DOUBLE")] Double = 1, + [pbr::OriginalName("TYPE_FLOAT")] Float = 2, /// /// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if /// negative values are likely. /// - TYPE_INT64 = 3, - TYPE_UINT64 = 4, + [pbr::OriginalName("TYPE_INT64")] Int64 = 3, + [pbr::OriginalName("TYPE_UINT64")] Uint64 = 4, /// /// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if /// negative values are likely. /// - TYPE_INT32 = 5, - TYPE_FIXED64 = 6, - TYPE_FIXED32 = 7, - TYPE_BOOL = 8, - TYPE_STRING = 9, + [pbr::OriginalName("TYPE_INT32")] Int32 = 5, + [pbr::OriginalName("TYPE_FIXED64")] Fixed64 = 6, + [pbr::OriginalName("TYPE_FIXED32")] Fixed32 = 7, + [pbr::OriginalName("TYPE_BOOL")] Bool = 8, + [pbr::OriginalName("TYPE_STRING")] String = 9, /// /// Tag-delimited aggregate. /// - TYPE_GROUP = 10, + [pbr::OriginalName("TYPE_GROUP")] Group = 10, /// /// Length-delimited aggregate. /// - TYPE_MESSAGE = 11, + [pbr::OriginalName("TYPE_MESSAGE")] Message = 11, /// /// New in version 2. /// - TYPE_BYTES = 12, - TYPE_UINT32 = 13, - TYPE_ENUM = 14, - TYPE_SFIXED32 = 15, - TYPE_SFIXED64 = 16, + [pbr::OriginalName("TYPE_BYTES")] Bytes = 12, + [pbr::OriginalName("TYPE_UINT32")] Uint32 = 13, + [pbr::OriginalName("TYPE_ENUM")] Enum = 14, + [pbr::OriginalName("TYPE_SFIXED32")] Sfixed32 = 15, + [pbr::OriginalName("TYPE_SFIXED64")] Sfixed64 = 16, /// /// Uses ZigZag encoding. /// - TYPE_SINT32 = 17, + [pbr::OriginalName("TYPE_SINT32")] Sint32 = 17, /// /// Uses ZigZag encoding. /// - TYPE_SINT64 = 18, + [pbr::OriginalName("TYPE_SINT64")] Sint64 = 18, } internal enum Label { /// /// 0 is reserved for errors /// - LABEL_OPTIONAL = 1, - LABEL_REQUIRED = 2, + [pbr::OriginalName("LABEL_OPTIONAL")] Optional = 1, + [pbr::OriginalName("LABEL_REQUIRED")] Required = 2, /// /// TODO(sanjay): Should we add LABEL_MAP? /// - LABEL_REPEATED = 3, + [pbr::OriginalName("LABEL_REPEATED")] Repeated = 3, } } @@ -2666,7 +2666,7 @@ namespace Google.Protobuf.Reflection { /// Field number for the "optimize_for" field. public const int OptimizeForFieldNumber = 9; - private global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode optimizeFor_ = global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED; + private global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode optimizeFor_ = 0; public global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode OptimizeFor { get { return optimizeFor_; } set { @@ -2854,7 +2854,7 @@ namespace Google.Protobuf.Reflection { if (JavaMultipleFiles != false) hash ^= JavaMultipleFiles.GetHashCode(); if (JavaGenerateEqualsAndHash != false) hash ^= JavaGenerateEqualsAndHash.GetHashCode(); if (JavaStringCheckUtf8 != false) hash ^= JavaStringCheckUtf8.GetHashCode(); - if (OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) hash ^= OptimizeFor.GetHashCode(); + if (OptimizeFor != 0) hash ^= OptimizeFor.GetHashCode(); if (GoPackage.Length != 0) hash ^= GoPackage.GetHashCode(); if (CcGenericServices != false) hash ^= CcGenericServices.GetHashCode(); if (JavaGenericServices != false) hash ^= JavaGenericServices.GetHashCode(); @@ -2881,7 +2881,7 @@ namespace Google.Protobuf.Reflection { output.WriteRawTag(66); output.WriteString(JavaOuterClassname); } - if (OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) { + if (OptimizeFor != 0) { output.WriteRawTag(72); output.WriteEnum((int) OptimizeFor); } @@ -2953,7 +2953,7 @@ namespace Google.Protobuf.Reflection { if (JavaStringCheckUtf8 != false) { size += 2 + 1; } - if (OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) { + if (OptimizeFor != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) OptimizeFor); } if (GoPackage.Length != 0) { @@ -3006,7 +3006,7 @@ namespace Google.Protobuf.Reflection { if (other.JavaStringCheckUtf8 != false) { JavaStringCheckUtf8 = other.JavaStringCheckUtf8; } - if (other.OptimizeFor != global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode.SPEED) { + if (other.OptimizeFor != 0) { OptimizeFor = other.OptimizeFor; } if (other.GoPackage.Length != 0) { @@ -3125,15 +3125,15 @@ namespace Google.Protobuf.Reflection { /// /// Generate complete code for parsing, serialization, /// - SPEED = 1, + [pbr::OriginalName("SPEED")] Speed = 1, /// /// etc. /// - CODE_SIZE = 2, + [pbr::OriginalName("CODE_SIZE")] CodeSize = 2, /// /// Generate code using MessageLite and the lite runtime. /// - LITE_RUNTIME = 3, + [pbr::OriginalName("LITE_RUNTIME")] LiteRuntime = 3, } } @@ -3436,7 +3436,7 @@ namespace Google.Protobuf.Reflection { /// Field number for the "ctype" field. public const int CtypeFieldNumber = 1; - private global::Google.Protobuf.Reflection.FieldOptions.Types.CType ctype_ = global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING; + private global::Google.Protobuf.Reflection.FieldOptions.Types.CType ctype_ = 0; /// /// The ctype option instructs the C++ code generator to use a different /// representation of the field than it normally would. See the specific @@ -3469,7 +3469,7 @@ namespace Google.Protobuf.Reflection { /// Field number for the "jstype" field. public const int JstypeFieldNumber = 6; - private global::Google.Protobuf.Reflection.FieldOptions.Types.JSType jstype_ = global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL; + private global::Google.Protobuf.Reflection.FieldOptions.Types.JSType jstype_ = 0; /// /// The jstype option determines the JavaScript type used for values of the /// field. The option is permitted only for 64 bit integral and fixed types @@ -3591,9 +3591,9 @@ namespace Google.Protobuf.Reflection { public override int GetHashCode() { int hash = 1; - if (Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) hash ^= Ctype.GetHashCode(); + if (Ctype != 0) hash ^= Ctype.GetHashCode(); if (Packed != false) hash ^= Packed.GetHashCode(); - if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) hash ^= Jstype.GetHashCode(); + if (Jstype != 0) hash ^= Jstype.GetHashCode(); if (Lazy != false) hash ^= Lazy.GetHashCode(); if (Deprecated != false) hash ^= Deprecated.GetHashCode(); if (Weak != false) hash ^= Weak.GetHashCode(); @@ -3606,7 +3606,7 @@ namespace Google.Protobuf.Reflection { } public void WriteTo(pb::CodedOutputStream output) { - if (Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) { + if (Ctype != 0) { output.WriteRawTag(8); output.WriteEnum((int) Ctype); } @@ -3622,7 +3622,7 @@ namespace Google.Protobuf.Reflection { output.WriteRawTag(40); output.WriteBool(Lazy); } - if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) { + if (Jstype != 0) { output.WriteRawTag(48); output.WriteEnum((int) Jstype); } @@ -3635,13 +3635,13 @@ namespace Google.Protobuf.Reflection { public int CalculateSize() { int size = 0; - if (Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) { + if (Ctype != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Ctype); } if (Packed != false) { size += 1 + 1; } - if (Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) { + if (Jstype != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Jstype); } if (Lazy != false) { @@ -3661,13 +3661,13 @@ namespace Google.Protobuf.Reflection { if (other == null) { return; } - if (other.Ctype != global::Google.Protobuf.Reflection.FieldOptions.Types.CType.STRING) { + if (other.Ctype != 0) { Ctype = other.Ctype; } if (other.Packed != false) { Packed = other.Packed; } - if (other.Jstype != global::Google.Protobuf.Reflection.FieldOptions.Types.JSType.JS_NORMAL) { + if (other.Jstype != 0) { Jstype = other.Jstype; } if (other.Lazy != false) { @@ -3729,24 +3729,24 @@ namespace Google.Protobuf.Reflection { /// /// Default mode. /// - STRING = 0, - CORD = 1, - STRING_PIECE = 2, + [pbr::OriginalName("STRING")] String = 0, + [pbr::OriginalName("CORD")] Cord = 1, + [pbr::OriginalName("STRING_PIECE")] StringPiece = 2, } internal enum JSType { /// /// Use the default type. /// - JS_NORMAL = 0, + [pbr::OriginalName("JS_NORMAL")] JsNormal = 0, /// /// Use JavaScript strings. /// - JS_STRING = 1, + [pbr::OriginalName("JS_STRING")] JsString = 1, /// /// Use JavaScript numbers. /// - JS_NUMBER = 2, + [pbr::OriginalName("JS_NUMBER")] JsNumber = 2, } } diff --git a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs index de6e5717..6c6f6ee0 100644 --- a/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/FieldDescriptor.cs @@ -133,41 +133,41 @@ namespace Google.Protobuf.Reflection { switch (type) { - case FieldDescriptorProto.Types.Type.TYPE_DOUBLE: + case FieldDescriptorProto.Types.Type.Double: return FieldType.Double; - case FieldDescriptorProto.Types.Type.TYPE_FLOAT: + case FieldDescriptorProto.Types.Type.Float: return FieldType.Float; - case FieldDescriptorProto.Types.Type.TYPE_INT64: + case FieldDescriptorProto.Types.Type.Int64: return FieldType.Int64; - case FieldDescriptorProto.Types.Type.TYPE_UINT64: + case FieldDescriptorProto.Types.Type.Uint64: return FieldType.UInt64; - case FieldDescriptorProto.Types.Type.TYPE_INT32: + case FieldDescriptorProto.Types.Type.Int32: return FieldType.Int32; - case FieldDescriptorProto.Types.Type.TYPE_FIXED64: + case FieldDescriptorProto.Types.Type.Fixed64: return FieldType.Fixed64; - case FieldDescriptorProto.Types.Type.TYPE_FIXED32: + case FieldDescriptorProto.Types.Type.Fixed32: return FieldType.Fixed32; - case FieldDescriptorProto.Types.Type.TYPE_BOOL: + case FieldDescriptorProto.Types.Type.Bool: return FieldType.Bool; - case FieldDescriptorProto.Types.Type.TYPE_STRING: + case FieldDescriptorProto.Types.Type.String: return FieldType.String; - case FieldDescriptorProto.Types.Type.TYPE_GROUP: + case FieldDescriptorProto.Types.Type.Group: return FieldType.Group; - case FieldDescriptorProto.Types.Type.TYPE_MESSAGE: + case FieldDescriptorProto.Types.Type.Message: return FieldType.Message; - case FieldDescriptorProto.Types.Type.TYPE_BYTES: + case FieldDescriptorProto.Types.Type.Bytes: return FieldType.Bytes; - case FieldDescriptorProto.Types.Type.TYPE_UINT32: + case FieldDescriptorProto.Types.Type.Uint32: return FieldType.UInt32; - case FieldDescriptorProto.Types.Type.TYPE_ENUM: + case FieldDescriptorProto.Types.Type.Enum: return FieldType.Enum; - case FieldDescriptorProto.Types.Type.TYPE_SFIXED32: + case FieldDescriptorProto.Types.Type.Sfixed32: return FieldType.SFixed32; - case FieldDescriptorProto.Types.Type.TYPE_SFIXED64: + case FieldDescriptorProto.Types.Type.Sfixed64: return FieldType.SFixed64; - case FieldDescriptorProto.Types.Type.TYPE_SINT32: + case FieldDescriptorProto.Types.Type.Sint32: return FieldType.SInt32; - case FieldDescriptorProto.Types.Type.TYPE_SINT64: + case FieldDescriptorProto.Types.Type.Sint64: return FieldType.SInt64; default: throw new ArgumentException("Invalid type specified"); @@ -177,7 +177,7 @@ namespace Google.Protobuf.Reflection /// /// Returns true if this field is a repeated field; false otherwise. /// - public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; + public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.Repeated; /// /// Returns true if this field is a map field; false otherwise. diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs index de7aea3a..e568a2c9 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Api.cs @@ -185,7 +185,7 @@ namespace Google.Protobuf.WellKnownTypes { /// Field number for the "syntax" field. public const int SyntaxFieldNumber = 7; - private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2; + private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0; /// /// The source syntax of the service. /// @@ -225,7 +225,7 @@ namespace Google.Protobuf.WellKnownTypes { if (Version.Length != 0) hash ^= Version.GetHashCode(); if (sourceContext_ != null) hash ^= SourceContext.GetHashCode(); hash ^= mixins_.GetHashCode(); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode(); + if (Syntax != 0) hash ^= Syntax.GetHashCode(); return hash; } @@ -249,7 +249,7 @@ namespace Google.Protobuf.WellKnownTypes { output.WriteMessage(SourceContext); } mixins_.WriteTo(output, _repeated_mixins_codec); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { output.WriteRawTag(56); output.WriteEnum((int) Syntax); } @@ -269,7 +269,7 @@ namespace Google.Protobuf.WellKnownTypes { size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext); } size += mixins_.CalculateSize(_repeated_mixins_codec); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax); } return size; @@ -294,7 +294,7 @@ namespace Google.Protobuf.WellKnownTypes { SourceContext.MergeFrom(other.SourceContext); } mixins_.Add(other.mixins_); - if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (other.Syntax != 0) { Syntax = other.Syntax; } } @@ -458,7 +458,7 @@ namespace Google.Protobuf.WellKnownTypes { /// Field number for the "syntax" field. public const int SyntaxFieldNumber = 7; - private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2; + private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0; /// /// The source syntax of this method. /// @@ -498,7 +498,7 @@ namespace Google.Protobuf.WellKnownTypes { if (ResponseTypeUrl.Length != 0) hash ^= ResponseTypeUrl.GetHashCode(); if (ResponseStreaming != false) hash ^= ResponseStreaming.GetHashCode(); hash ^= options_.GetHashCode(); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode(); + if (Syntax != 0) hash ^= Syntax.GetHashCode(); return hash; } @@ -528,7 +528,7 @@ namespace Google.Protobuf.WellKnownTypes { output.WriteBool(ResponseStreaming); } options_.WriteTo(output, _repeated_options_codec); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { output.WriteRawTag(56); output.WriteEnum((int) Syntax); } @@ -552,7 +552,7 @@ namespace Google.Protobuf.WellKnownTypes { size += 1 + 1; } size += options_.CalculateSize(_repeated_options_codec); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax); } return size; @@ -578,7 +578,7 @@ namespace Google.Protobuf.WellKnownTypes { ResponseStreaming = other.ResponseStreaming; } options_.Add(other.options_); - if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (other.Syntax != 0) { Syntax = other.Syntax; } } diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs index 8e2ce8cf..c9da30d5 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs @@ -59,7 +59,7 @@ namespace Google.Protobuf.WellKnownTypes { /// /// Null value. /// - NULL_VALUE = 0, + [pbr::OriginalName("NULL_VALUE")] NullValue = 0, } #endregion @@ -234,7 +234,7 @@ namespace Google.Protobuf.WellKnownTypes { /// Represents a null value. /// public global::Google.Protobuf.WellKnownTypes.NullValue NullValue { - get { return kindCase_ == KindOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : global::Google.Protobuf.WellKnownTypes.NullValue.NULL_VALUE; } + get { return kindCase_ == KindOneofCase.NullValue ? (global::Google.Protobuf.WellKnownTypes.NullValue) kind_ : 0; } set { kind_ = value; kindCase_ = KindOneofCase.NullValue; diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs index 8faa1d1c..657c2464 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Type.cs @@ -79,11 +79,11 @@ namespace Google.Protobuf.WellKnownTypes { /// /// Syntax `proto2`. /// - SYNTAX_PROTO2 = 0, + [pbr::OriginalName("SYNTAX_PROTO2")] Proto2 = 0, /// /// Syntax `proto3`. /// - SYNTAX_PROTO3 = 1, + [pbr::OriginalName("SYNTAX_PROTO3")] Proto3 = 1, } #endregion @@ -188,7 +188,7 @@ namespace Google.Protobuf.WellKnownTypes { /// Field number for the "syntax" field. public const int SyntaxFieldNumber = 6; - private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2; + private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0; /// /// The source syntax. /// @@ -226,7 +226,7 @@ namespace Google.Protobuf.WellKnownTypes { hash ^= oneofs_.GetHashCode(); hash ^= options_.GetHashCode(); if (sourceContext_ != null) hash ^= SourceContext.GetHashCode(); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode(); + if (Syntax != 0) hash ^= Syntax.GetHashCode(); return hash; } @@ -246,7 +246,7 @@ namespace Google.Protobuf.WellKnownTypes { output.WriteRawTag(42); output.WriteMessage(SourceContext); } - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { output.WriteRawTag(48); output.WriteEnum((int) Syntax); } @@ -263,7 +263,7 @@ namespace Google.Protobuf.WellKnownTypes { if (sourceContext_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext); } - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax); } return size; @@ -285,7 +285,7 @@ namespace Google.Protobuf.WellKnownTypes { } SourceContext.MergeFrom(other.SourceContext); } - if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (other.Syntax != 0) { Syntax = other.Syntax; } } @@ -371,7 +371,7 @@ namespace Google.Protobuf.WellKnownTypes { /// Field number for the "kind" field. public const int KindFieldNumber = 1; - private global::Google.Protobuf.WellKnownTypes.Field.Types.Kind kind_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN; + private global::Google.Protobuf.WellKnownTypes.Field.Types.Kind kind_ = 0; /// /// The field type. /// @@ -384,7 +384,7 @@ namespace Google.Protobuf.WellKnownTypes { /// Field number for the "cardinality" field. public const int CardinalityFieldNumber = 2; - private global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality cardinality_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN; + private global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality cardinality_ = 0; /// /// The field cardinality. /// @@ -526,8 +526,8 @@ namespace Google.Protobuf.WellKnownTypes { public override int GetHashCode() { int hash = 1; - if (Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) hash ^= Kind.GetHashCode(); - if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) hash ^= Cardinality.GetHashCode(); + if (Kind != 0) hash ^= Kind.GetHashCode(); + if (Cardinality != 0) hash ^= Cardinality.GetHashCode(); if (Number != 0) hash ^= Number.GetHashCode(); if (Name.Length != 0) hash ^= Name.GetHashCode(); if (TypeUrl.Length != 0) hash ^= TypeUrl.GetHashCode(); @@ -544,11 +544,11 @@ namespace Google.Protobuf.WellKnownTypes { } public void WriteTo(pb::CodedOutputStream output) { - if (Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) { + if (Kind != 0) { output.WriteRawTag(8); output.WriteEnum((int) Kind); } - if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) { + if (Cardinality != 0) { output.WriteRawTag(16); output.WriteEnum((int) Cardinality); } @@ -585,10 +585,10 @@ namespace Google.Protobuf.WellKnownTypes { public int CalculateSize() { int size = 0; - if (Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) { + if (Kind != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Kind); } - if (Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) { + if (Cardinality != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Cardinality); } if (Number != 0) { @@ -620,10 +620,10 @@ namespace Google.Protobuf.WellKnownTypes { if (other == null) { return; } - if (other.Kind != global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN) { + if (other.Kind != 0) { Kind = other.Kind; } - if (other.Cardinality != global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN) { + if (other.Cardinality != 0) { Cardinality = other.Cardinality; } if (other.Number != 0) { @@ -712,79 +712,79 @@ namespace Google.Protobuf.WellKnownTypes { /// /// Field type unknown. /// - TYPE_UNKNOWN = 0, + [pbr::OriginalName("TYPE_UNKNOWN")] TypeUnknown = 0, /// /// Field type double. /// - TYPE_DOUBLE = 1, + [pbr::OriginalName("TYPE_DOUBLE")] TypeDouble = 1, /// /// Field type float. /// - TYPE_FLOAT = 2, + [pbr::OriginalName("TYPE_FLOAT")] TypeFloat = 2, /// /// Field type int64. /// - TYPE_INT64 = 3, + [pbr::OriginalName("TYPE_INT64")] TypeInt64 = 3, /// /// Field type uint64. /// - TYPE_UINT64 = 4, + [pbr::OriginalName("TYPE_UINT64")] TypeUint64 = 4, /// /// Field type int32. /// - TYPE_INT32 = 5, + [pbr::OriginalName("TYPE_INT32")] TypeInt32 = 5, /// /// Field type fixed64. /// - TYPE_FIXED64 = 6, + [pbr::OriginalName("TYPE_FIXED64")] TypeFixed64 = 6, /// /// Field type fixed32. /// - TYPE_FIXED32 = 7, + [pbr::OriginalName("TYPE_FIXED32")] TypeFixed32 = 7, /// /// Field type bool. /// - TYPE_BOOL = 8, + [pbr::OriginalName("TYPE_BOOL")] TypeBool = 8, /// /// Field type string. /// - TYPE_STRING = 9, + [pbr::OriginalName("TYPE_STRING")] TypeString = 9, /// /// Field type group. Proto2 syntax only, and deprecated. /// - TYPE_GROUP = 10, + [pbr::OriginalName("TYPE_GROUP")] TypeGroup = 10, /// /// Field type message. /// - TYPE_MESSAGE = 11, + [pbr::OriginalName("TYPE_MESSAGE")] TypeMessage = 11, /// /// Field type bytes. /// - TYPE_BYTES = 12, + [pbr::OriginalName("TYPE_BYTES")] TypeBytes = 12, /// /// Field type uint32. /// - TYPE_UINT32 = 13, + [pbr::OriginalName("TYPE_UINT32")] TypeUint32 = 13, /// /// Field type enum. /// - TYPE_ENUM = 14, + [pbr::OriginalName("TYPE_ENUM")] TypeEnum = 14, /// /// Field type sfixed32. /// - TYPE_SFIXED32 = 15, + [pbr::OriginalName("TYPE_SFIXED32")] TypeSfixed32 = 15, /// /// Field type sfixed64. /// - TYPE_SFIXED64 = 16, + [pbr::OriginalName("TYPE_SFIXED64")] TypeSfixed64 = 16, /// /// Field type sint32. /// - TYPE_SINT32 = 17, + [pbr::OriginalName("TYPE_SINT32")] TypeSint32 = 17, /// /// Field type sint64. /// - TYPE_SINT64 = 18, + [pbr::OriginalName("TYPE_SINT64")] TypeSint64 = 18, } /// @@ -794,19 +794,19 @@ namespace Google.Protobuf.WellKnownTypes { /// /// For fields with unknown cardinality. /// - CARDINALITY_UNKNOWN = 0, + [pbr::OriginalName("CARDINALITY_UNKNOWN")] Unknown = 0, /// /// For optional fields. /// - CARDINALITY_OPTIONAL = 1, + [pbr::OriginalName("CARDINALITY_OPTIONAL")] Optional = 1, /// /// For required fields. Proto2 syntax only. /// - CARDINALITY_REQUIRED = 2, + [pbr::OriginalName("CARDINALITY_REQUIRED")] Required = 2, /// /// For repeated fields. /// - CARDINALITY_REPEATED = 3, + [pbr::OriginalName("CARDINALITY_REPEATED")] Repeated = 3, } } @@ -900,7 +900,7 @@ namespace Google.Protobuf.WellKnownTypes { /// Field number for the "syntax" field. public const int SyntaxFieldNumber = 5; - private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2; + private global::Google.Protobuf.WellKnownTypes.Syntax syntax_ = 0; /// /// The source syntax. /// @@ -936,7 +936,7 @@ namespace Google.Protobuf.WellKnownTypes { hash ^= enumvalue_.GetHashCode(); hash ^= options_.GetHashCode(); if (sourceContext_ != null) hash ^= SourceContext.GetHashCode(); - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) hash ^= Syntax.GetHashCode(); + if (Syntax != 0) hash ^= Syntax.GetHashCode(); return hash; } @@ -955,7 +955,7 @@ namespace Google.Protobuf.WellKnownTypes { output.WriteRawTag(34); output.WriteMessage(SourceContext); } - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { output.WriteRawTag(40); output.WriteEnum((int) Syntax); } @@ -971,7 +971,7 @@ namespace Google.Protobuf.WellKnownTypes { if (sourceContext_ != null) { size += 1 + pb::CodedOutputStream.ComputeMessageSize(SourceContext); } - if (Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (Syntax != 0) { size += 1 + pb::CodedOutputStream.ComputeEnumSize((int) Syntax); } return size; @@ -992,7 +992,7 @@ namespace Google.Protobuf.WellKnownTypes { } SourceContext.MergeFrom(other.SourceContext); } - if (other.Syntax != global::Google.Protobuf.WellKnownTypes.Syntax.SYNTAX_PROTO2) { + if (other.Syntax != 0) { Syntax = other.Syntax; } } From 790f4c8e3743c28c30e6f052cb3f5535490c87e4 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Fri, 8 Apr 2016 13:22:42 +0100 Subject: [PATCH 087/123] Use the original name in JSON formatting. (JSON parsing already does the right thing.) --- .../Google.Protobuf/Google.Protobuf.nuspec | 2 + csharp/src/Google.Protobuf/JsonFormatter.cs | 45 ++++++++++++++++++- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec index f51bc89a..2892b8bf 100644 --- a/csharp/src/Google.Protobuf/Google.Protobuf.nuspec +++ b/csharp/src/Google.Protobuf/Google.Protobuf.nuspec @@ -33,10 +33,12 @@ + + diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index cbd9366c..73a4f64b 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -39,6 +39,7 @@ using Google.Protobuf.WellKnownTypes; using System.IO; using System.Linq; using System.Collections.Generic; +using System.Reflection; namespace Google.Protobuf { @@ -420,9 +421,10 @@ namespace Google.Protobuf } else if (value is System.Enum) { - if (System.Enum.IsDefined(value.GetType(), value)) + string name = OriginalEnumValueHelper.GetOriginalName(value); + if (name != null) { - WriteString(writer, value.ToString()); + WriteString(writer, name); } else { @@ -877,5 +879,44 @@ namespace Google.Protobuf TypeRegistry = ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry)); } } + + // Effectively a cache of mapping from enum values to the original name as specified in the proto file, + // fetched by reflection. + // The need for this is unfortunate, as is its unbounded size, but realistically it shouldn't cause issues. + private static class OriginalEnumValueHelper + { + // TODO: In the future we might want to use ConcurrentDictionary, at the point where all + // the platforms we target have it. + private static readonly Dictionary> dictionaries + = new Dictionary>(); + + internal static string GetOriginalName(object value) + { + var enumType = value.GetType(); + Dictionary nameMapping; + lock (dictionaries) + { + if (!dictionaries.TryGetValue(enumType, out nameMapping)) + { + nameMapping = GetNameMapping(enumType); + dictionaries[enumType] = nameMapping; + } + } + + string originalName; + // If this returns false, originalName will be null, which is what we want. + nameMapping.TryGetValue(value, out originalName); + return originalName; + } + + private static Dictionary GetNameMapping(System.Type enumType) => + enumType.GetTypeInfo().DeclaredFields + .Where(f => f.IsStatic) + .ToDictionary(f => f.GetValue(null), + f => f.GetCustomAttributes() + .FirstOrDefault() + // If the attribute hasn't been applied, fall back to the name of the field. + ?.Name ?? f.Name); + } } } From d90d615f716c6d2f0ede2b2ce23705d4c502ea45 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Tue, 12 Apr 2016 09:32:08 +0100 Subject: [PATCH 088/123] Attempt to fix AppVeyor build by exporting GetEnumValueName --- src/google/protobuf/compiler/csharp/csharp_helpers.cc | 5 +++++ src/google/protobuf/compiler/csharp/csharp_helpers.h | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.cc b/src/google/protobuf/compiler/csharp/csharp_helpers.cc index efd01556..6c154c5a 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.cc +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.cc @@ -260,6 +260,11 @@ std::string TryRemovePrefix(const std::string& prefix, const std::string& value) return value.substr(value_index); } +// Format the enum value name in a pleasant way for C#: +// - Strip the enum name as a prefix if possible +// - Convert to PascalCase. +// For example, an enum called Color with a value of COLOR_BLUE should +// result in an enum value in C# called just Blue std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name) { std::string stripped = TryRemovePrefix(enum_name, enum_value_name); std::string result = ShoutyToPascalCase(stripped); diff --git a/src/google/protobuf/compiler/csharp/csharp_helpers.h b/src/google/protobuf/compiler/csharp/csharp_helpers.h index 8830e957..1563ca7e 100644 --- a/src/google/protobuf/compiler/csharp/csharp_helpers.h +++ b/src/google/protobuf/compiler/csharp/csharp_helpers.h @@ -36,6 +36,7 @@ #define GOOGLE_PROTOBUF_COMPILER_CSHARP_HELPERS_H__ #include +#include #include #include #include @@ -93,7 +94,9 @@ inline std::string UnderscoresToCamelCase(const std::string& input, bool cap_nex std::string UnderscoresToPascalCase(const std::string& input); -std::string GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name); +// Note that we wouldn't normally want to export this (we're not expecting +// it to be used outside libprotoc itself) but this exposes it for testing. +std::string LIBPROTOBUF_EXPORT GetEnumValueName(const std::string& enum_name, const std::string& enum_value_name); // TODO(jtattermusch): perhaps we could move this to strutil std::string StringToBase64(const std::string& input); From 511f28b73a066f4e7c5b4eeedc5b465e81451fc4 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 19 Apr 2016 17:57:17 -0400 Subject: [PATCH 089/123] ObjC support for failing the build in the generated WKTs are out of date - Always generated into a temp directory so we can see if things changed. - Add a flag to control exiting with error when stale vs updating. This should let the continuous builds error out when ObjC needs to have the checked in sources updated. --- objectivec/DevTools/full_mac_build.sh | 40 +++++++------------------ objectivec/generate_well_known_types.sh | 29 +++++++++++++++++- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/objectivec/DevTools/full_mac_build.sh b/objectivec/DevTools/full_mac_build.sh index 4d4930dc..ff51d9f0 100755 --- a/objectivec/DevTools/full_mac_build.sh +++ b/objectivec/DevTools/full_mac_build.sh @@ -26,8 +26,9 @@ OPTIONS: Issue a clean before the normal build. -a, --autogen Start by rerunning autogen & configure. - -r, --regenerate-cpp-descriptors - The descriptor.proto is checked in generated, cause it to regenerate. + -r, --regenerate-descriptors + Run generate_descriptor_proto.sh to regenerate all the checked in + proto sources. -j #, --jobs # Force the number of parallel jobs (useful for debugging build issues). --core-only @@ -71,7 +72,7 @@ fi DO_AUTOGEN=no DO_CLEAN=no -REGEN_CPP_DESCRIPTORS=no +REGEN_DESCRIPTORS=no CORE_ONLY=no DO_XCODE_IOS_TESTS=yes DO_XCODE_OSX_TESTS=yes @@ -88,8 +89,8 @@ while [[ $# != 0 ]]; do -a | --autogen ) DO_AUTOGEN=yes ;; - -r | --regenerate-cpp-descriptors ) - REGEN_CPP_DESCRIPTORS=yes + -r | --regenerate-descriptors ) + REGEN_DESCRIPTORS=yes ;; -j | --jobs ) shift @@ -164,8 +165,8 @@ if [[ "${DO_CLEAN}" == "yes" ]] ; then fi fi -if [[ "${REGEN_CPP_DESCRIPTORS}" == "yes" ]] ; then - header "Regenerating the C++ descriptor sources." +if [[ "${REGEN_DESCRIPTORS}" == "yes" ]] ; then + header "Regenerating the descriptor sources." ./generate_descriptor_proto.sh -j "${NUM_MAKE_JOBS}" fi @@ -184,29 +185,8 @@ else cd .. fi -header "Ensuring the ObjC descriptors are current." -# Find the newest input file (protos, compiler, and the generator script). -# (these patterns catch some extra stuff, but better to over sample than under) -readonly NewestInput=$(find \ - src/google/protobuf/*.proto \ - src/.libs src/*.la src/protoc \ - objectivec/generate_well_known_types.sh \ - -type f -print0 \ - | xargs -0 stat -f "%m %N" \ - | sort -n | tail -n1 | cut -f2- -d" ") -# Find the oldest output file. -readonly OldestOutput=$(find \ - "${ProtoRootDir}/objectivec/google" \ - -type f -print0 \ - | xargs -0 stat -f "%m %N" \ - | sort -n -r | tail -n1 | cut -f2- -d" ") -# If the newest input is newer than the oldest output, regenerate. -if [[ "${NewestInput}" -nt "${OldestOutput}" ]] ; then - echo ">> Newest input is newer than oldest output, regenerating." - objectivec/generate_well_known_types.sh -j "${NUM_MAKE_JOBS}" -else - echo ">> Newest input is older than oldest output, no need to regenerating." -fi +# Ensure the WKT sources checked in are current. +objectivec/generate_well_known_types.sh --check-only -j "${NUM_MAKE_JOBS}" header "Checking on the ObjC Runtime Code" objectivec/DevTools/pddm_tests.py diff --git a/objectivec/generate_well_known_types.sh b/objectivec/generate_well_known_types.sh index be9b38a5..73be50ff 100755 --- a/objectivec/generate_well_known_types.sh +++ b/objectivec/generate_well_known_types.sh @@ -12,6 +12,13 @@ set -eu readonly ScriptDir=$(dirname "$(echo $0 | sed -e "s,^\([^/]\),$(pwd)/\1,")") readonly ProtoRootDir="${ScriptDir}/.." +# Flag for continuous integration to check that everything is current. +CHECK_ONLY=0 +if [[ $# -ge 1 && ( "$1" == "--check-only" ) ]] ; then + CHECK_ONLY=1 + shift +fi + pushd "${ProtoRootDir}" > /dev/null if test ! -e src/google/protobuf/stubs/common.h; then @@ -46,4 +53,24 @@ declare -a RUNTIME_PROTO_FILES=( \ google/protobuf/type.proto \ google/protobuf/wrappers.proto) -./protoc --objc_out="${ProtoRootDir}/objectivec" ${RUNTIME_PROTO_FILES[@]} +# Generate to a temp directory to see if they match. +TMP_DIR=$(mktemp -d) +trap "rm -rf ${TMP_DIR}" EXIT +./protoc --objc_out="${TMP_DIR}" ${RUNTIME_PROTO_FILES[@]} +set +e +diff -r "${TMP_DIR}/google" "${ProtoRootDir}/objectivec/google" > /dev/null +if [[ $? -eq 0 ]] ; then + echo "Generated source for WellKnownTypes is current." + exit 0 +fi +set -e + +# If check only mode, error out. +if [[ "${CHECK_ONLY}" == 1 ]] ; then + echo "ERROR: The WKTs need to be regenerated! Run $0" + exit 1 +fi + +# Copy them over. +echo "Copying over updated WellKnownType sources." +cp -r "${TMP_DIR}/google/" "${ProtoRootDir}/objectivec/google/" From c588ac42a2d8d0b6cb3163c6ee256fc9d771627e Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 20 Apr 2016 17:19:42 +0100 Subject: [PATCH 090/123] Regenerate well-known types for C# (There are documentation changes and new fields in descriptor.proto that have resulted in changes to the serialized descriptor, but no breaking changes for C#.) --- .../Google.Protobuf/Reflection/Descriptor.cs | 125 +++++++----------- .../src/Google.Protobuf/WellKnownTypes/Any.cs | 43 +++++- .../WellKnownTypes/Duration.cs | 7 +- .../Google.Protobuf/WellKnownTypes/Empty.cs | 7 +- .../WellKnownTypes/FieldMask.cs | 27 ++++ .../Google.Protobuf/WellKnownTypes/Struct.cs | 9 +- .../WellKnownTypes/Timestamp.cs | 7 +- .../WellKnownTypes/Wrappers.cs | 8 +- 8 files changed, 130 insertions(+), 103 deletions(-) diff --git a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs index c003c0ff..fa138dfe 100644 --- a/csharp/src/Google.Protobuf/Reflection/Descriptor.cs +++ b/csharp/src/Google.Protobuf/Reflection/Descriptor.cs @@ -80,7 +80,7 @@ namespace Google.Protobuf.Reflection { "EhMKC291dHB1dF90eXBlGAMgASgJEi8KB29wdGlvbnMYBCABKAsyHi5nb29n", "bGUucHJvdG9idWYuTWV0aG9kT3B0aW9ucxIfChBjbGllbnRfc3RyZWFtaW5n", "GAUgASgIOgVmYWxzZRIfChBzZXJ2ZXJfc3RyZWFtaW5nGAYgASgIOgVmYWxz", - "ZSKuBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwKFGph", + "ZSKHBQoLRmlsZU9wdGlvbnMSFAoMamF2YV9wYWNrYWdlGAEgASgJEhwKFGph", "dmFfb3V0ZXJfY2xhc3NuYW1lGAggASgJEiIKE2phdmFfbXVsdGlwbGVfZmls", "ZXMYCiABKAg6BWZhbHNlEiwKHWphdmFfZ2VuZXJhdGVfZXF1YWxzX2FuZF9o", "YXNoGBQgASgIOgVmYWxzZRIlChZqYXZhX3N0cmluZ19jaGVja191dGY4GBsg", @@ -91,54 +91,53 @@ namespace Google.Protobuf.Reflection { "cHlfZ2VuZXJpY19zZXJ2aWNlcxgSIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl", "ZBgXIAEoCDoFZmFsc2USHwoQY2NfZW5hYmxlX2FyZW5hcxgfIAEoCDoFZmFs", "c2USGQoRb2JqY19jbGFzc19wcmVmaXgYJCABKAkSGAoQY3NoYXJwX25hbWVz", - "cGFjZRglIAEoCRIrCh9qYXZhbmFub191c2VfZGVwcmVjYXRlZF9wYWNrYWdl", - "GCYgASgIQgIYARJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n", + "cGFjZRglIAEoCRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5n", "b29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbiI6CgxPcHRpbWl6", "ZU1vZGUSCQoFU1BFRUQQARINCglDT0RFX1NJWkUQAhIQCgxMSVRFX1JVTlRJ", - "TUUQAyoJCOgHEICAgIACIuYBCg5NZXNzYWdlT3B0aW9ucxImChdtZXNzYWdl", - "X3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9fc3RhbmRhcmRf", - "ZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoKZGVwcmVjYXRl", - "ZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMKFHVuaW50ZXJw", - "cmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVy", - "cHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAMKDEZpZWxkT3B0aW9ucxI6CgVj", - "dHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlvbnMuQ1R5", - "cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBlGAYgASgOMiQu", - "Z29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6CUpTX05PUk1B", - "TBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMgASgIOgVm", - "YWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29w", + "TUUQAyoJCOgHEICAgIACSgQIJhAnIuYBCg5NZXNzYWdlT3B0aW9ucxImChdt", + "ZXNzYWdlX3NldF93aXJlX2Zvcm1hdBgBIAEoCDoFZmFsc2USLgofbm9fc3Rh", + "bmRhcmRfZGVzY3JpcHRvcl9hY2Nlc3NvchgCIAEoCDoFZmFsc2USGQoKZGVw", + "cmVjYXRlZBgDIAEoCDoFZmFsc2USEQoJbWFwX2VudHJ5GAcgASgIEkMKFHVu", + "aW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5V", + "bmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIimAMKDEZpZWxkT3B0aW9u", + "cxI6CgVjdHlwZRgBIAEoDjIjLmdvb2dsZS5wcm90b2J1Zi5GaWVsZE9wdGlv", + "bnMuQ1R5cGU6BlNUUklORxIOCgZwYWNrZWQYAiABKAgSPwoGanN0eXBlGAYg", + "ASgOMiQuZ29vZ2xlLnByb3RvYnVmLkZpZWxkT3B0aW9ucy5KU1R5cGU6CUpT", + "X05PUk1BTBITCgRsYXp5GAUgASgIOgVmYWxzZRIZCgpkZXByZWNhdGVkGAMg", + "ASgIOgVmYWxzZRITCgR3ZWFrGAogASgIOgVmYWxzZRJDChR1bmludGVycHJl", + "dGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnBy", + "ZXRlZE9wdGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoM", + "U1RSSU5HX1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpT", + "X1NUUklORxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAIijQEKC0VudW1P", + "cHRpb25zEhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyAB", + "KAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdv", + "b2dsZS5wcm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIi", + "fQoQRW51bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxz", + "ZRJDChR1bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJv", + "dG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNlcnZp", + "Y2VPcHRpb25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVuaW50", + "ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5Vbmlu", + "dGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIiegoNTWV0aG9kT3B0aW9ucxIZ", + "CgpkZXByZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29w", "dGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9w", - "dGlvbiIvCgVDVHlwZRIKCgZTVFJJTkcQABIICgRDT1JEEAESEAoMU1RSSU5H", - "X1BJRUNFEAIiNQoGSlNUeXBlEg0KCUpTX05PUk1BTBAAEg0KCUpTX1NUUklO", - "RxABEg0KCUpTX05VTUJFUhACKgkI6AcQgICAgAIijQEKC0VudW1PcHRpb25z", - "EhMKC2FsbG93X2FsaWFzGAIgASgIEhkKCmRlcHJlY2F0ZWQYAyABKAg6BWZh", - "bHNlEkMKFHVuaW50ZXJwcmV0ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5w", - "cm90b2J1Zi5VbmludGVycHJldGVkT3B0aW9uKgkI6AcQgICAgAIifQoQRW51", - "bVZhbHVlT3B0aW9ucxIZCgpkZXByZWNhdGVkGAEgASgIOgVmYWxzZRJDChR1", - "bmludGVycHJldGVkX29wdGlvbhjnByADKAsyJC5nb29nbGUucHJvdG9idWYu", - "VW5pbnRlcnByZXRlZE9wdGlvbioJCOgHEICAgIACInsKDlNlcnZpY2VPcHRp", - "b25zEhkKCmRlcHJlY2F0ZWQYISABKAg6BWZhbHNlEkMKFHVuaW50ZXJwcmV0", - "ZWRfb3B0aW9uGOcHIAMoCzIkLmdvb2dsZS5wcm90b2J1Zi5VbmludGVycHJl", - "dGVkT3B0aW9uKgkI6AcQgICAgAIiegoNTWV0aG9kT3B0aW9ucxIZCgpkZXBy", - "ZWNhdGVkGCEgASgIOgVmYWxzZRJDChR1bmludGVycHJldGVkX29wdGlvbhjn", - "ByADKAsyJC5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbioJ", - "COgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5hbWUYAiAD", - "KAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlvbi5OYW1l", - "UGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0aXZlX2lu", - "dF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSABKAMSFAoM", - "ZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEoDBIXCg9h", - "Z2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFtZV9wYXJ0", - "GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291cmNlQ29kZUlu", - "Zm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYuU291cmNl", - "Q29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBhdGgYASADKAVC", - "AhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29tbWVudHMYAyAB", - "KAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVhZGluZ19kZXRh", - "Y2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29kZUluZm8SQQoK", - "YW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5HZW5lcmF0ZWRD", - "b2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoEcGF0aBgBIAMo", - "BUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4YAyABKAUSCwoD", - "ZW5kGAQgASgFQlgKE2NvbS5nb29nbGUucHJvdG9idWZCEERlc2NyaXB0b3JQ", - "cm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdvb2dsZS5Qcm90b2J1Zi5S", - "ZWZsZWN0aW9u")); + "dGlvbioJCOgHEICAgIACIp4CChNVbmludGVycHJldGVkT3B0aW9uEjsKBG5h", + "bWUYAiADKAsyLS5nb29nbGUucHJvdG9idWYuVW5pbnRlcnByZXRlZE9wdGlv", + "bi5OYW1lUGFydBIYChBpZGVudGlmaWVyX3ZhbHVlGAMgASgJEhoKEnBvc2l0", + "aXZlX2ludF92YWx1ZRgEIAEoBBIaChJuZWdhdGl2ZV9pbnRfdmFsdWUYBSAB", + "KAMSFAoMZG91YmxlX3ZhbHVlGAYgASgBEhQKDHN0cmluZ192YWx1ZRgHIAEo", + "DBIXCg9hZ2dyZWdhdGVfdmFsdWUYCCABKAkaMwoITmFtZVBhcnQSEQoJbmFt", + "ZV9wYXJ0GAEgAigJEhQKDGlzX2V4dGVuc2lvbhgCIAIoCCLVAQoOU291cmNl", + "Q29kZUluZm8SOgoIbG9jYXRpb24YASADKAsyKC5nb29nbGUucHJvdG9idWYu", + "U291cmNlQ29kZUluZm8uTG9jYXRpb24ahgEKCExvY2F0aW9uEhAKBHBhdGgY", + "ASADKAVCAhABEhAKBHNwYW4YAiADKAVCAhABEhgKEGxlYWRpbmdfY29tbWVu", + "dHMYAyABKAkSGQoRdHJhaWxpbmdfY29tbWVudHMYBCABKAkSIQoZbGVhZGlu", + "Z19kZXRhY2hlZF9jb21tZW50cxgGIAMoCSKnAQoRR2VuZXJhdGVkQ29kZUlu", + "Zm8SQQoKYW5ub3RhdGlvbhgBIAMoCzItLmdvb2dsZS5wcm90b2J1Zi5HZW5l", + "cmF0ZWRDb2RlSW5mby5Bbm5vdGF0aW9uGk8KCkFubm90YXRpb24SEAoEcGF0", + "aBgBIAMoBUICEAESEwoLc291cmNlX2ZpbGUYAiABKAkSDQoFYmVnaW4YAyAB", + "KAUSCwoDZW5kGAQgASgFQlgKE2NvbS5nb29nbGUucHJvdG9idWZCEERlc2Ny", + "aXB0b3JQcm90b3NIAVoKZGVzY3JpcHRvcqICA0dQQqoCGkdvb2dsZS5Qcm90", + "b2J1Zi5SZWZsZWN0aW9u")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { @@ -152,7 +151,7 @@ namespace Google.Protobuf.Reflection { new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumValueDescriptorProto), global::Google.Protobuf.Reflection.EnumValueDescriptorProto.Parser, new[]{ "Name", "Number", "Options" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.ServiceDescriptorProto), global::Google.Protobuf.Reflection.ServiceDescriptorProto.Parser, new[]{ "Name", "Method", "Options" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MethodDescriptorProto), global::Google.Protobuf.Reflection.MethodDescriptorProto.Parser, new[]{ "Name", "InputType", "OutputType", "Options", "ClientStreaming", "ServerStreaming" }, null, null, null), - new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), global::Google.Protobuf.Reflection.FileOptions.Parser, new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "JavananoUseDeprecatedPackage", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null), + new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FileOptions), global::Google.Protobuf.Reflection.FileOptions.Parser, new[]{ "JavaPackage", "JavaOuterClassname", "JavaMultipleFiles", "JavaGenerateEqualsAndHash", "JavaStringCheckUtf8", "OptimizeFor", "GoPackage", "CcGenericServices", "JavaGenericServices", "PyGenericServices", "Deprecated", "CcEnableArenas", "ObjcClassPrefix", "CsharpNamespace", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FileOptions.Types.OptimizeMode) }, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.MessageOptions), global::Google.Protobuf.Reflection.MessageOptions.Parser, new[]{ "MessageSetWireFormat", "NoStandardDescriptorAccessor", "Deprecated", "MapEntry", "UninterpretedOption" }, null, null, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.FieldOptions), global::Google.Protobuf.Reflection.FieldOptions.Parser, new[]{ "Ctype", "Packed", "Jstype", "Lazy", "Deprecated", "Weak", "UninterpretedOption" }, null, new[]{ typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.CType), typeof(global::Google.Protobuf.Reflection.FieldOptions.Types.JSType) }, null), new pbr::GeneratedClrTypeInfo(typeof(global::Google.Protobuf.Reflection.EnumOptions), global::Google.Protobuf.Reflection.EnumOptions.Parser, new[]{ "AllowAlias", "Deprecated", "UninterpretedOption" }, null, null, null), @@ -2563,7 +2562,6 @@ namespace Google.Protobuf.Reflection { ccEnableArenas_ = other.ccEnableArenas_; objcClassPrefix_ = other.objcClassPrefix_; csharpNamespace_ = other.csharpNamespace_; - javananoUseDeprecatedPackage_ = other.javananoUseDeprecatedPackage_; uninterpretedOption_ = other.uninterpretedOption_.Clone(); } @@ -2790,21 +2788,6 @@ namespace Google.Protobuf.Reflection { } } - /// Field number for the "javanano_use_deprecated_package" field. - public const int JavananoUseDeprecatedPackageFieldNumber = 38; - private bool javananoUseDeprecatedPackage_; - /// - /// Whether the nano proto compiler should generate in the deprecated non-nano - /// suffixed package. - /// - [global::System.ObsoleteAttribute()] - public bool JavananoUseDeprecatedPackage { - get { return javananoUseDeprecatedPackage_; } - set { - javananoUseDeprecatedPackage_ = value; - } - } - /// Field number for the "uninterpreted_option" field. public const int UninterpretedOptionFieldNumber = 999; private static readonly pb::FieldCodec _repeated_uninterpretedOption_codec @@ -2842,7 +2825,6 @@ namespace Google.Protobuf.Reflection { if (CcEnableArenas != other.CcEnableArenas) return false; if (ObjcClassPrefix != other.ObjcClassPrefix) return false; if (CsharpNamespace != other.CsharpNamespace) return false; - if (JavananoUseDeprecatedPackage != other.JavananoUseDeprecatedPackage) return false; if(!uninterpretedOption_.Equals(other.uninterpretedOption_)) return false; return true; } @@ -2863,7 +2845,6 @@ namespace Google.Protobuf.Reflection { if (CcEnableArenas != false) hash ^= CcEnableArenas.GetHashCode(); if (ObjcClassPrefix.Length != 0) hash ^= ObjcClassPrefix.GetHashCode(); if (CsharpNamespace.Length != 0) hash ^= CsharpNamespace.GetHashCode(); - if (JavananoUseDeprecatedPackage != false) hash ^= JavananoUseDeprecatedPackage.GetHashCode(); hash ^= uninterpretedOption_.GetHashCode(); return hash; } @@ -2929,10 +2910,6 @@ namespace Google.Protobuf.Reflection { output.WriteRawTag(170, 2); output.WriteString(CsharpNamespace); } - if (JavananoUseDeprecatedPackage != false) { - output.WriteRawTag(176, 2); - output.WriteBool(JavananoUseDeprecatedPackage); - } uninterpretedOption_.WriteTo(output, _repeated_uninterpretedOption_codec); } @@ -2980,9 +2957,6 @@ namespace Google.Protobuf.Reflection { if (CsharpNamespace.Length != 0) { size += 2 + pb::CodedOutputStream.ComputeStringSize(CsharpNamespace); } - if (JavananoUseDeprecatedPackage != false) { - size += 2 + 1; - } size += uninterpretedOption_.CalculateSize(_repeated_uninterpretedOption_codec); return size; } @@ -3033,9 +3007,6 @@ namespace Google.Protobuf.Reflection { if (other.CsharpNamespace.Length != 0) { CsharpNamespace = other.CsharpNamespace; } - if (other.JavananoUseDeprecatedPackage != false) { - JavananoUseDeprecatedPackage = other.JavananoUseDeprecatedPackage; - } uninterpretedOption_.Add(other.uninterpretedOption_); } @@ -3102,10 +3073,6 @@ namespace Google.Protobuf.Reflection { CsharpNamespace = input.ReadString(); break; } - case 304: { - JavananoUseDeprecatedPackage = input.ReadBool(); - break; - } case 7994: { uninterpretedOption_.AddEntriesFrom(input, _repeated_uninterpretedOption_codec); break; diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs index 48cd99a1..fd4e65b5 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Any.cs @@ -24,9 +24,10 @@ namespace Google.Protobuf.WellKnownTypes { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "Chlnb29nbGUvcHJvdG9idWYvYW55LnByb3RvEg9nb29nbGUucHJvdG9idWYi", - "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQksKE2Nv", - "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAGgAQGiAgNHUEKqAh5Hb29n", - "bGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw==")); + "JgoDQW55EhAKCHR5cGVfdXJsGAEgASgJEg0KBXZhbHVlGAIgASgMQnIKE2Nv", + "bS5nb29nbGUucHJvdG9idWZCCEFueVByb3RvUAFaJWdpdGh1Yi5jb20vZ29s", + "YW5nL3Byb3RvYnVmL3B0eXBlcy9hbnmgAQGiAgNHUEKqAh5Hb29nbGUuUHJv", + "dG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { @@ -38,8 +39,36 @@ namespace Google.Protobuf.WellKnownTypes { } #region Messages /// - /// `Any` contains an arbitrary serialized message along with a URL - /// that describes the type of the serialized message. + /// `Any` contains an arbitrary serialized protocol buffer message along with a + /// URL that describes the type of the serialized message. + /// + /// Protobuf library provides support to pack/unpack Any values in the form + /// of utility functions or additional generated methods of the Any type. + /// + /// Example 1: Pack and unpack a message in C++. + /// + /// Foo foo = ...; + /// Any any; + /// any.PackFrom(foo); + /// ... + /// if (any.UnpackTo(&foo)) { + /// ... + /// } + /// + /// Example 2: Pack and unpack a message in Java. + /// + /// Foo foo = ...; + /// Any any = Any.pack(foo); + /// ... + /// if (any.is(Foo.class)) { + /// foo = any.unpack(Foo.class); + /// } + /// + /// The pack methods provided by protobuf library will by default use + /// 'type.googleapis.com/full.type.name' as the type URL and the unpack + /// methods only use the fully qualified type name after the last '/' + /// in the type URL, for example "foo.bar.com/x/y.z" will yield type + /// name "y.z". /// /// JSON /// ==== @@ -102,7 +131,7 @@ namespace Google.Protobuf.WellKnownTypes { private string typeUrl_ = ""; /// /// A URL/resource name whose content describes the type of the - /// serialized message. + /// serialized protocol buffer message. /// /// For URLs which use the schema `http`, `https`, or no schema, the /// following restrictions and interpretations apply: @@ -132,7 +161,7 @@ namespace Google.Protobuf.WellKnownTypes { public const int ValueFieldNumber = 2; private pb::ByteString value_ = pb::ByteString.Empty; /// - /// Must be valid serialized data of the above specified type. + /// Must be a valid serialized protocol buffer of the above specified type. /// public pb::ByteString Value { get { return value_; } diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs index 73e221d4..f17358f4 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Duration.cs @@ -25,9 +25,10 @@ namespace Google.Protobuf.WellKnownTypes { string.Concat( "Ch5nb29nbGUvcHJvdG9idWYvZHVyYXRpb24ucHJvdG8SD2dvb2dsZS5wcm90", "b2J1ZiIqCghEdXJhdGlvbhIPCgdzZWNvbmRzGAEgASgDEg0KBW5hbm9zGAIg", - "ASgFQlAKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAaAB", - "AaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJv", - "dG8z")); + "ASgFQnwKE2NvbS5nb29nbGUucHJvdG9idWZCDUR1cmF0aW9uUHJvdG9QAVoq", + "Z2l0aHViLmNvbS9nb2xhbmcvcHJvdG9idWYvcHR5cGVzL2R1cmF0aW9uoAEB", + "ogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5cGVzYgZwcm90", + "bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs index 6cad4124..e08ea240 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Empty.cs @@ -24,9 +24,10 @@ namespace Google.Protobuf.WellKnownTypes { byte[] descriptorData = global::System.Convert.FromBase64String( string.Concat( "Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1", - "ZiIHCgVFbXB0eUJQChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv", - "UAGgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw", - "ZXNiBnByb3RvMw==")); + "ZiIHCgVFbXB0eUJ5ChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv", + "UAFaJ2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy9lbXB0eaAB", + "AfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG", + "cHJvdG8z")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs index 2ba2b96f..79a0319f 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/FieldMask.cs @@ -159,6 +159,33 @@ namespace Google.Protobuf.WellKnownTypes { /// { /// mask: "user.displayName,photo" /// } + /// + /// # Field Masks and Oneof Fields + /// + /// Field masks treat fields in oneofs just as regular fields. Consider the + /// following message: + /// + /// message SampleMessage { + /// oneof test_oneof { + /// string name = 4; + /// SubMessage sub_message = 9; + /// } + /// } + /// + /// The field mask can be: + /// + /// mask { + /// paths: "name" + /// } + /// + /// Or: + /// + /// mask { + /// paths: "sub_message" + /// } + /// + /// Note that oneof type names ("test_oneof" in this case) cannot be used in + /// paths. /// [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] public sealed partial class FieldMask : pb::IMessage { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs index c9da30d5..edc8940d 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Struct.cs @@ -34,9 +34,10 @@ namespace Google.Protobuf.WellKnownTypes { "ABIwCgpsaXN0X3ZhbHVlGAYgASgLMhouZ29vZ2xlLnByb3RvYnVmLkxpc3RW", "YWx1ZUgAQgYKBGtpbmQiMwoJTGlzdFZhbHVlEiYKBnZhbHVlcxgBIAMoCzIW", "Lmdvb2dsZS5wcm90b2J1Zi5WYWx1ZSobCglOdWxsVmFsdWUSDgoKTlVMTF9W", - "QUxVRRAAQk4KE2NvbS5nb29nbGUucHJvdG9idWZCC1N0cnVjdFByb3RvUAGg", - "AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnBy", - "b3RvMw==")); + "QUxVRRAAQoEBChNjb20uZ29vZ2xlLnByb3RvYnVmQgtTdHJ1Y3RQcm90b1AB", + "WjFnaXRodWIuY29tL2dvbGFuZy9wcm90b2J1Zi9wdHlwZXMvc3RydWN0O3N0", + "cnVjdHBioAEBogIDR1BCqgIeR29vZ2xlLlByb3RvYnVmLldlbGxLbm93blR5", + "cGVzYgZwcm90bzM=")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.NullValue), }, new pbr::GeneratedClrTypeInfo[] { @@ -108,7 +109,7 @@ namespace Google.Protobuf.WellKnownTypes { = new pbc::MapField.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Value.Parser), 10); private readonly pbc::MapField fields_ = new pbc::MapField(); /// - /// Map of dynamically typed values. + /// Unordered map of dynamically typed values. /// public pbc::MapField Fields { get { return fields_; } diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs index 318b0f61..053b88bd 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Timestamp.cs @@ -25,9 +25,10 @@ namespace Google.Protobuf.WellKnownTypes { string.Concat( "Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv", "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY", - "AiABKAVCVAoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q", - "AaABAfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBl", - "c2IGcHJvdG8z")); + "AiABKAVCgQEKE2NvbS5nb29nbGUucHJvdG9idWZCDlRpbWVzdGFtcFByb3Rv", + "UAFaK2dpdGh1Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy90aW1lc3Rh", + "bXCgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw", + "ZXNiBnByb3RvMw==")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs index d6796d1a..c8867d0e 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/Wrappers.cs @@ -29,10 +29,10 @@ namespace Google.Protobuf.WellKnownTypes { "KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1", "ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo", "DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS", - "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJT", - "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQH4AQGi", - "AgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3Rv", - "Mw==")); + "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJ/", + "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAFaKmdpdGh1", + "Yi5jb20vZ29sYW5nL3Byb3RvYnVmL3B0eXBlcy93cmFwcGVyc6ABAfgBAaIC", + "A0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IGcHJvdG8z")); descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, new pbr::FileDescriptor[] { }, new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] { From 8052dc75a973253c9cd02148a19f56613bad667f Mon Sep 17 00:00:00 2001 From: Feng Xiao Date: Tue, 19 Apr 2016 15:29:18 -0700 Subject: [PATCH 091/123] Add a docs directory and move the third-party add-ons page here. --- docs/third_party.md | 147 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 docs/third_party.md diff --git a/docs/third_party.md b/docs/third_party.md new file mode 100644 index 00000000..69ed6a38 --- /dev/null +++ b/docs/third_party.md @@ -0,0 +1,147 @@ +# Third-Party Add-ons for Protocol Buffers + +This page lists code related to Protocol Buffers which is developed and maintained by third parties. You may find this code useful, but note that **these projects are not affiliated with or endorsed by Google (unless explicitly marked)**; try them at your own risk. Also note that many projects here are in the early stages of development and not production-ready. + +If you have a project that should be listed here, please [send us a pull request](https://github.com/google/protobuf/pulls) to update this page. + +## Programming Languages + +These are projects we know about implementing Protocol Buffers for other programming languages: +* Action Script: http://code.google.com/p/protobuf-actionscript3/ +* Action Script: https://code.google.com/p/protoc-gen-as3/ +* Action Script: https://github.com/matrix3d/JProtoc +* C: https://github.com/protobuf-c/protobuf-c +* C: http://koti.kapsi.fi/jpa/nanopb/ +* C: https://github.com/cloudwu/pbc/ +* C: https://github.com/haberman/upb/wiki +* C: https://github.com/squidfunk/protobluff +* C++: https://github.com/google/protobuf (Google-official implementation) +* C/C++: http://spbc.sf.net/ +* C#: http://code.google.com/p/protobuf-csharp-port +* C#: http://code.google.com/p/protosharp/ +* C#: https://silentorbit.com/protobuf/ +* C#/.NET/WCF/VB: http://code.google.com/p/protobuf-net/ +* Clojure: http://github.com/ninjudd/clojure-protobuf +* Common Lisp: http://www.prism.gatech.edu/~ndantam3/docs/s-protobuf/ +* Common Lisp: http://github.com/brown/protobuf +* D: https://github.com/msoucy/dproto +* D: http://256.makerslocal.org/wiki/index.php/ProtocolBuffer +* D: https://github.com/opticron/ProtocolBuffer +* Dart: https://github.com/dart-lang/dart-protobuf (runtime) https://github.com/dart-lang/dart-protoc-plugin (code generator) +* Delphi: http://sourceforge.net/projects/protobuf-delphi/ +* Delphi: http://fundementals.sourceforge.net/dl.html +* Elixir: https://github.com/jeremyong/exprotoc +* Erlang: http://github.com/ngerakines/erlang_protobuffs/tree/master +* Erlang: http://piqi.org/ +* Erlang: https://code.google.com/p/protoc-gen-erl/ +* Erlang: https://github.com/basho/erlang_protobuffs +* Go: https://github.com/golang/protobuf (Google-official implementation) +* Go: http://code.google.com/p/goprotobuf/ +* Go: https://github.com/akunspy/gopbuf +* Haskell: http://hackage.haskell.org/package/hprotoc +* Haxe: https://github.com/Atry/protoc-gen-haxe +* Java: https://github.com/google/protobuf (Google-official implementation) +* Java/Android: https://github.com/square/wire +* Java ME: http://code.google.com/p/protobuf-javame/ +* Java ME: http://swingme.sourceforge.net/encode.shtml +* Java ME: http://github.com/ponderingpanda/protobuf-j2me +* Java ME: http://code.google.com/p/protobuf-j2me/ +* Javascript: http://code.google.com/p/protobuf-js/ +* Javascript: http://github.com/sirikata/protojs +* Javascript: https://github.com/dcodeIO/ProtoBuf.js +* Javascript: http://code.google.com/p/protobuf-for-node/ +* Javascript: http://code.google.com/p/protostuff/ +* Julia: https://github.com/tanmaykm/ProtoBuf.jl +* Lua: http://code.google.com/p/protoc-gen-lua/ +* Lua: http://github.com/indygreg/lua-protobuf +* Lua: https://github.com/Neopallium/lua-pb +* Matlab: http://code.google.com/p/protobuf-matlab/ +* Mercury: http://code.google.com/p/protobuf-mercury/ +* Objective C: http://code.google.com/p/protobuf-objc/ +* Objective C: https://github.com/alexeyxo/protobuf-objc +* OCaml: http://piqi.org/ +* Perl: http://groups.google.com/group/protobuf-perl +* Perl: http://search.cpan.org/perldoc?Google::ProtocolBuffers +* Perl/XS: http://code.google.com/p/protobuf-perlxs/ +* PHP: http://code.google.com/p/pb4php/ +* PHP: https://github.com/allegro/php-protobuf/ +* PHP: https://github.com/chobie/php-protocolbuffers +* PHP: http://drslump.github.com/Protobuf-PHP +* Prolog: http://www.swi-prolog.org/pldoc/package/protobufs.html +* Python: https://github.com/google/protobuf (Google-official implementation) +* Python: http://eigenein.github.com/protobuf/ +* R: http://cran.r-project.org/package=RProtoBuf +* Ruby: http://code.google.com/p/ruby-protobuf/ +* Ruby: http://github.com/mozy/ruby-protocol-buffers +* Ruby: https://github.com/bmizerany/beefcake/tree/master/lib/beefcake +* Ruby: https://github.com/localshred/protobuf +* Rust: https://github.com/stepancheg/rust-protobuf/ +* Scala: http://github.com/jeffplaisance/scala-protobuf +* Scala: http://code.google.com/p/protobuf-scala +* Scala: https://github.com/SandroGrzicic/ScalaBuff +* Scala: http://trueaccord.github.io/ScalaPB/ +* Swift: https://github.com/alexeyxo/protobuf-swift +* Vala: https://launchpad.net/protobuf-vala +* Visual Basic: http://code.google.com/p/protobuf-net/ + +## RPC Implementations + +GRPC (http://www.grpc.io/) is Google's RPC implementation for Protocol Buffers. There are other third-party RPC implementations as well. Some of these actually work with Protocol Buffers service definitions (defined using the `service` keyword in `.proto` files) while others just use Protocol Buffers message objects. + +* https://github.com/grpc/grpc (C++, Node.js, Python, Ruby, Objective-C, PHP, C#, Google-official implementation) +* http://zeroc.com/ice.html (Multiple languages) +* http://code.google.com/p/protobuf-net/ (C#/.NET/WCF/VB) +* https://launchpad.net/txprotobuf/ (Python) +* https://github.com/modeswitch/protobuf-rpc (Python) +* http://code.google.com/p/protobuf-socket-rpc/ (Java, Python) +* http://code.google.com/p/proto-streamer/ (Java) +* http://code.google.com/p/server1/ (C++) +* http://deltavsoft.com/RcfUserGuide/Protobufs (C++) +* http://code.google.com/p/protobuf-mina-rpc/ (Python client, Java server) +* http://code.google.com/p/casocklib/ (C++) +* http://code.google.com/p/cxf-protobuf/ (Java) +* http://code.google.com/p/protobuf-remote/ (C++/C#) +* http://code.google.com/p/protobuf-rpc-pro/ (Java) +* https://code.google.com/p/protorpc/ (Go/C++) +* https://code.google.com/p/eneter-protobuf-serializer/ (Java/.NET) +* http://www.deltavsoft.com/RCFProto.html (C++/Java/Python/C#) +* https://github.com/robbinfan/claire-protorpc (C++) +* https://github.com/BaiduPS/sofa-pbrpc (C++) +* https://github.com/ebencheung/arab (C++) +* http://code.google.com/p/protobuf-csharp-rpc/ (C#) +* https://github.com/thesamet/rpcz (C++/Python, based on ZeroMQ) +* https://github.com/w359405949/libmaid (C++, Python) +* https://github.com/madwyn/libpbrpc (C++) + +## Other Utilities + +There are miscellaneous other things you may find useful as a Protocol Buffers developer. + +* [NetBeans IDE plugin](http://code.google.com/p/protobuf-netbeans-plugin/) +* [Wireshark/Ethereal packet sniffer plugin](http://code.google.com/p/protobuf-wireshark/) +* [Alternate encodings (JSON, XML, HTML) for Java protobufs](http://code.google.com/p/protobuf-java-format/) +* [Another JSON encoder/decoder for Java](https://github.com/sijuv/protobuf-codec) +* [Editor for serialized protobufs](http://code.google.com/p/protobufeditor/) +* [Intellij IDEA plugin](http://github.com/nnmatveev/idea-plugin-protobuf) +* [TextMate syntax highlighting](http://github.com/michaeledgar/protobuf-tmbundle) +* [Oracle PL SQL plugin](http://code.google.com/p/protocol-buffer-plsql/) +* [Eclipse editor for protobuf (from Google)](http://code.google.com/p/protobuf-dt/) +* [C++ Builder compatible protobuf](https://github.com/saadware/protobuf-cppbuilder) +* Maven Protocol Compiler Plugin + * https://github.com/sergei-ivanov/maven-protoc-plugin/ + * http://igor-petruk.github.com/protobuf-maven-plugin/ + * http://code.google.com/p/maven-protoc-plugin/ + * https://github.com/os72/protoc-jar-maven-plugin +* [Documentation generator plugin (Markdown/HTML/DocBook/...)](https://github.com/estan/protoc-gen-doc) +* [DocBook generator for .proto files](http://code.google.com/p/protoc-gen-docbook/) +* [Protobuf for nginx module](https://github.com/dbcode/protobuf-nginx/) +* [RSpec matchers and Cucumber step defs for testing Protocol Buffers](https://github.com/connamara/protobuf_spec) +* [Sbt plugin for Protocol Buffers](https://github.com/Atry/sbt-cppp) +* [Gradle Protobuf Plugin](https://github.com/aantono/gradle-plugin-protobuf) +* [Multi-platform executable JAR and Java API for protoc](https://github.com/os72/protoc-jar) +* [Python scripts to convert between Protocol Buffers and JSON](https://github.com/NextTuesday/py-pb-converters) +* [Visual Studio Language Service support for Protocol Buffers](http://visualstudiogallery.msdn.microsoft.com/4bc0f38c-b058-4e05-ae38-155e053c19c5) +* [C++ library for serialization/de-serialization between Protocol Buffers and JSON.](https://github.com/yinqiwen/pbjson) +* [ProtoBuf with Java EE7 Expression Language 3.0; pure Java ProtoBuf Parser and Builder.](https://github.com/protobufel/protobuf-el) +* [Notepad++ Syntax Highlighting for .proto files](https://github.com/chai2010/notepadplus-protobuf) +* [Linter for .proto files](https://github.com/ckaznocha/protoc-gen-lint) From f4f9aec52f5b4c46ff32fb9527229da081a14e11 Mon Sep 17 00:00:00 2001 From: Petr Prokhorenkov Date: Thu, 14 Apr 2016 11:17:54 +0300 Subject: [PATCH 092/123] Fix bug with silent message corruption in LITE_RUNTIME. A protobuf message will be corrupted in the following scenario: 1. Use LITE_RUNTIME. 2. Have an optional enum field following some other field. 3. Update protocol by adding new values to the enum. 4. Have an old client parse and serialize a message having enum field set to a value the client does not understand. 5. Field preceeding the enum is now corrupted. The bug is due to the fact that optimized fallthrough in parser code does not update variablle 'tag' when jumping to the parser code for the next field. --- .../protobuf/compiler/cpp/cpp_enum_field.cc | 6 +++-- src/google/protobuf/lite_unittest.cc | 27 +++++++++++++++++++ src/google/protobuf/unittest_lite.proto | 19 +++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 824e2205..06cb18d1 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -36,6 +36,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -142,8 +143,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { } else { printer->Print( "} else {\n" - " unknown_fields_stream.WriteVarint32(tag);\n" - " unknown_fields_stream.WriteVarint32(value);\n"); + " unknown_fields_stream.WriteVarint32($tag$);\n" + " unknown_fields_stream.WriteVarint32(value);\n", + "tag", SimpleItoa(internal::WireFormat::MakeTag(descriptor_))); } printer->Print(variables_, "}\n"); diff --git a/src/google/protobuf/lite_unittest.cc b/src/google/protobuf/lite_unittest.cc index d1948ab5..3ca3fbaf 100644 --- a/src/google/protobuf/lite_unittest.cc +++ b/src/google/protobuf/lite_unittest.cc @@ -686,6 +686,33 @@ int main(int argc, char* argv[]) { EXPECT_TRUE(map_message.IsInitialized()); } + { + // Check that adding more values to enum does not corrupt message + // when passed through an old client. + protobuf_unittest::V2MessageLite v2_message; + v2_message.set_int_field(800); + // Set enum field to the value not understood by the old client. + v2_message.set_enum_field(protobuf_unittest::V2_SECOND); + string v2_bytes = v2_message.SerializeAsString(); + + protobuf_unittest::V1MessageLite v1_message; + v1_message.ParseFromString(v2_bytes); + EXPECT_TRUE(v1_message.IsInitialized()); + EXPECT_EQ(v1_message.int_field(), v2_message.int_field()); + // V1 client does not understand V2_SECOND value, so it discards it and + // uses default value instead. + EXPECT_EQ(v1_message.enum_field(), protobuf_unittest::V1_FIRST); + + // However, when re-serialized, it should preserve enum value. + string v1_bytes = v1_message.SerializeAsString(); + + protobuf_unittest::V2MessageLite same_v2_message; + same_v2_message.ParseFromString(v1_bytes); + + EXPECT_EQ(v2_message.int_field(), same_v2_message.int_field()); + EXPECT_EQ(v2_message.enum_field(), same_v2_message.enum_field()); + } + std::cout << "PASS" << std::endl; return 0; } diff --git a/src/google/protobuf/unittest_lite.proto b/src/google/protobuf/unittest_lite.proto index 41ed845f..878ec7c1 100644 --- a/src/google/protobuf/unittest_lite.proto +++ b/src/google/protobuf/unittest_lite.proto @@ -386,3 +386,22 @@ message TestEmptyMessageLite{ message TestEmptyMessageWithExtensionsLite { extensions 1 to max; } + +enum V1EnumLite { + V1_FIRST = 1; +} + +enum V2EnumLite { + V2_FIRST = 1; + V2_SECOND = 2; +} + +message V1MessageLite { + required int32 int_field = 1; + optional V1EnumLite enum_field = 2 [ default = V1_FIRST ]; +} + +message V2MessageLite { + required int32 int_field = 1; + optional V2EnumLite enum_field = 2 [ default = V2_FIRST ]; +} From db93833bc656e7a0b8d851b1fefdb5c0b5d5b178 Mon Sep 17 00:00:00 2001 From: Jakub Kukul Date: Fri, 22 Apr 2016 16:04:27 +0200 Subject: [PATCH 093/123] Added serialVersionUID to ExtendableMessage. --- .../src/main/java/com/google/protobuf/GeneratedMessage.java | 2 ++ 1 file changed, 2 insertions(+) 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 a50afe55..ea79df3e 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -795,6 +795,8 @@ public abstract class GeneratedMessage extends AbstractMessage extends GeneratedMessage implements ExtendableMessageOrBuilder { + private static final long serialVersionUID = 1L; + private final FieldSet extensions; protected ExtendableMessage() { From 385755e13bd1574c5ff7e00a0546547ba4546d41 Mon Sep 17 00:00:00 2001 From: Tony Allevato Date: Fri, 22 Apr 2016 09:15:14 -0700 Subject: [PATCH 094/123] Add initial design document for Swift protocol buffers. (#1442) * Add initial design doc for Swift protocol buffers. --- docs/swift/DesignDoc.md | 674 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 docs/swift/DesignDoc.md diff --git a/docs/swift/DesignDoc.md b/docs/swift/DesignDoc.md new file mode 100644 index 00000000..364a4d3f --- /dev/null +++ b/docs/swift/DesignDoc.md @@ -0,0 +1,674 @@ +# Protocol Buffers in Swift + +## Objective + +This document describes the user-facing API and internal implementation of +proto2 and proto3 messages in Apple’s Swift programming language. + +One of the key goals of protobufs is to provide idiomatic APIs for each +language. In that vein, **interoperability with Objective-C is a non-goal of +this proposal.** Protobuf users who need to pass messages between Objective-C +and Swift code in the same application should use the existing Objective-C proto +library. The goal of the effort described here is to provide an API for protobuf +messages that uses features specific to Swift—optional types, algebraic +enumerated types, value types, and so forth—in a natural way that will delight, +rather than surprise, users of the language. + +## Naming + +* By convention, both typical protobuf message names and Swift structs/classes + are `UpperCamelCase`, so for most messages, the name of a message can be the + same as the name of its generated type. (However, see the discussion below + about prefixes under [Packages](#packages).) + +* Enum cases in protobufs typically are `UPPERCASE_WITH_UNDERSCORES`, whereas + in Swift they are `lowerCamelCase` (as of the Swift 3 API design + guidelines). We will transform the names to match Swift convention, using + a whitelist similar to the Objective-C compiler plugin to handle commonly + used acronyms. + +* Typical fields in proto messages are `lowercase_with_underscores`, while in + Swift they are `lowerCamelCase`. We will transform the names to match + Swift convention by removing the underscores and uppercasing the subsequent + letter. + +## Swift reserved words + +Swift has a large set of reserved words—some always reserved and some +contextually reserved (that is, they can be used as identifiers in contexts +where they would not be confused). As of Swift 2.2, the set of always-reserved +words is: + +``` +_, #available, #column, #else, #elseif, #endif, #file, #function, #if, #line, +#selector, as, associatedtype, break, case, catch, class, continue, default, +defer, deinit, do, dynamicType, else, enum, extension, fallthrough, false, for, +func, guard, if, import, in, init, inout, internal, is, let, nil, operator, +private, protocol, public, repeat, rethrows, return, self, Self, static, +struct, subscript, super, switch, throw, throws, true, try, typealias, var, +where, while +``` + +The set of contextually reserved words is: + +``` +associativity, convenience, dynamic, didSet, final, get, infix, indirect, +lazy, left, mutating, none, nonmutating, optional, override, postfix, +precedence, prefix, Protocol, required, right, set, Type, unowned, weak, +willSet +``` + +It is possible to use any reserved word as an identifier by escaping it with +backticks (for example, ``let `class` = 5``). Other name-mangling schemes would +require us to transform the names themselves (for example, by appending an +underscore), which requires us to then ensure that the new name does not collide +with something else in the same namespace. + +While the backtick feature may not be widely known by all Swift developers, a +small amount of user education can address this and it seems like the best +approach. We can unconditionally surround all property names with backticks to +simplify generation. + +Some remapping will still be required, though, to avoid collisions between +generated properties and the names of methods and properties defined in the base +protocol/implementation of messages. + +# Features of Protocol Buffers + +This section describes how the features of the protocol buffer syntaxes (proto2 +and proto3) map to features in Swift—what the code generated from a proto will +look like, and how it will be implemented in the underlying library. + +## Packages + +Modules are the main form of namespacing in Swift, but they are not declared +using syntactic constructs like namespaces in C++ or packages in Java. Instead, +they are tied to build targets in Xcode (or, in the future with open-source +Swift, declarations in a Swift Package Manager manifest). They also do not +easily support nesting submodules (Clang module maps support this, but pure +Swift does not yet provide a way to define submodules). + +We will generate types with fully-qualified underscore-delimited names. For +example, a message `Baz` in package `foo.bar` would generate a struct named +`Foo_Bar_Baz`. For each fully-qualified proto message, there will be exactly one +unique type symbol emitted in the generated binary. + +Users are likely to balk at the ugliness of underscore-delimited names for every +generated type. To improve upon this situation, we will add a new string file +level option, `swift_package_typealias`, that can be added to `.proto` files. +When present, this will cause `typealias`es to be added to the generated Swift +messages that replace the package name prefix with the provided string. For +example, the following `.proto` file: + +```protobuf +option swift_package_typealias = "FBP"; +package foo.bar; + +message Baz { + // Message fields +} +``` + +would generate the following Swift source: + +```swift +public struct Foo_Bar_Baz { + // Message fields and other methods +} + +typealias FBPBaz = Foo_Bar_Baz +``` + +It should be noted that this type alias is recorded in the generated +`.swiftmodule` so that code importing the module can refer to it, but it does +not cause a new symbol to be generated in the compiled binary (i.e., we do not +risk compiled size bloat by adding `typealias`es for every type). + +Other strategies to handle packages that were considered and rejected can be +found in [Appendix A](#appendix-a-rejected-strategies-to-handle-packages). + +## Messages + +Proto messages are natural value types and we will generate messages as structs +instead of classes. Users will benefit from Swift’s built-in behavior with +regard to mutability. We will define a `ProtoMessage` protocol that defines the +common methods and properties for all messages (such as serialization) and also +lets users treat messages polymorphically. Any shared method implementations +that do not differ between individual messages can be implemented in a protocol +extension. + +The backing storage itself for fields of a message will be managed by a +`ProtoFieldStorage` type that uses an internal dictionary keyed by field number, +and whose values are the value of the field with that number (up-cast to Swift’s +`Any` type). This class will provide type-safe getters and setters so that +generated messages can manipulate this storage, and core serialization logic +will live here as well. Furthermore, factoring the storage out into a separate +type, rather than inlining the fields as stored properties in the message +itself, lets us implement copy-on-write efficiently to support passing around +large messages. (Furthermore, because the messages themselves are value types, +inlining fields is not possible if the fields are submessages of the same type, +or a type that eventually includes a submessage of the same type.) + +### Required fields (proto2 only) + +Required fields in proto2 messages seem like they could be naturally represented +by non-optional properties in Swift, but this presents some problems/concerns. + +Serialization APIs permit partial serialization, which allows required fields to +remain unset. Furthermore, other language APIs still provide `has*` and `clear*` +methods for required fields, and knowing whether a property has a value when the +message is in memory is still useful. + +For example, an e-mail draft message may have the “to” address required on the +wire, but when the user constructs it in memory, it doesn’t make sense to force +a value until they provide one. We only want to force a value to be present when +the message is serialized to the wire. Using non-optional properties prevents +this use case, and makes client usage awkward because the user would be forced +to select a sentinel or placeholder value for any required fields at the time +the message was created. + +### Default values + +In proto2, fields can have a default value specified that may be a value other +than the default value for its corresponding language type (for example, a +default value of 5 instead of 0 for an integer). When reading a field that is +not explicitly set, the user expects to get that value. This makes Swift +optionals (i.e., `Foo?`) unsuitable for fields in general. Unfortunately, we +cannot implement our own “enhanced optional” type without severely complicating +usage (Swift’s use of type inference and its lack of implicit conversions would +require manual unwrapping of every property value). + +Instead, we can use **implicitly unwrapped optionals.** For example, a property +generated for a field of type `int32` would have Swift type `Int32!`. These +properties would behave with the following characteristics, which mirror the +nil-resettable properties used elsewhere in Apple’s SDKs (for example, +`UIView.tintColor`): + +* Assigning a non-nil value to a property sets the field to that value. +* Assigning nil to a property clears the field (its internal representation is + nilled out). +* Reading the value of a property returns its value if it is set, or returns + its default value if it is not set. Reading a property never returns nil. + +The final point in the list above implies that the optional cannot be checked to +determine if the field is set to a value other than its default: it will never +be nil. Instead, we must provide `has*` methods for each field to allow the user +to check this. These methods will be public in proto2. In proto3, these methods +will be private (if generated at all), since the user can test the returned +value against the zero value for that type. + +### Autocreation of nested messages + +For convenience, dotting into an unset field representing a nested message will +return an instance of that message with default values. As in the Objective-C +implementation, this does not actually cause the field to be set until the +returned message is mutated. Fortunately, thanks to the way mutability of value +types is implemented in Swift, the language automatically handles the +reassignment-on-mutation for us. A static singleton instance containing default +values can be associated with each message that can be returned when reading, so +copies are only made by the Swift runtime when mutation occurs. For example, +given the following proto: + +```protobuf +message Node { + Node child = 1; + string value = 2 [default = "foo"]; +} +``` + +The following Swift code would act as commented, where setting deeply nested +properties causes the copies and mutations to occur as the assignment statement +is unwound: + +```swift +var node = Node() + +let s = node.child.child.value +// 1. node.child returns the "default Node". +// 2. Reading .child on the result of (1) returns the same default Node. +// 3. Reading .value on the result of (2) returns the default value "foo". + +node.child.child.value = "bar" +// 4. Setting .value on the default Node causes a copy to be made and sets +// the property on that copy. Subsequently, the language updates the +// value of "node.child.child" to point to that copy. +// 5. Updating "node.child.child" in (4) requires another copy, because +// "node.child" was also the instance of the default node. The copy is +// assigned back to "node.child". +// 6. Setting "node.child" in (5) is a simple value reassignment, since +// "node" is a mutable var. +``` + +In other words, the generated messages do not internally have to manage parental +relationships to backfill the appropriate properties on mutation. Swift provides +this for free. + +## Scalar value fields + +Proto scalar value fields will map to Swift types in the following way: + +.proto Type | Swift Type +----------- | ------------------- +`double` | `Double` +`float` | `Float` +`int32` | `Int32` +`int64` | `Int64` +`uint32` | `UInt32` +`uint64` | `UInt64` +`sint32` | `Int32` +`sint64` | `Int64` +`fixed32` | `UInt32` +`fixed64` | `UInt64` +`sfixed32` | `Int32` +`sfixed64` | `Int64` +`bool` | `Bool` +`string` | `String` +`bytes` | `Foundation.NSData` + +The proto spec defines a number of integral types that map to the same Swift +type; for example, `intXX`, `sintXX`, and `sfixedXX` are all signed integers, +and `uintXX` and `fixedXX` are both unsigned integers. No other language +implementation distinguishes these further, so we do not do so either. The +rationale is that the various types only serve to distinguish how the value is +**encoded on the wire**; once loaded in memory, the user is not concerned about +these variations. + +Swift’s lack of implicit conversions among types will make it slightly annoying +to use these types in a context expecting an `Int`, or vice-versa, but since +this is a data-interchange format with explicitly-sized fields, we should not +hide that information from the user. Users will have to explicitly write +`Int(message.myField)`, for example. + +## Embedded message fields + +Embedded message fields can be represented using an optional variable of the +generated message type. Thus, the message + +```protobuf +message Foo { + Bar bar = 1; +} +``` + +would be represented in Swift as + +```swift +public struct Foo: ProtoMessage { + public var bar: Bar! { + get { ... } + set { ... } + } +} +``` + +If the user explicitly sets `bar` to nil, or if it was never set when read from +the wire, retrieving the value of `bar` would return a default, statically +allocated instance of `Bar` containing default values for its fields. This +achieves the desired behavior for default values in the same way that scalar +fields are designed, and also allows users to deep-drill into complex object +graphs to get or set fields without checking for nil at each step. + +## Enum fields + +The design and implementation of enum fields will differ somewhat drastically +depending on whether the message being generated is a proto2 or proto3 message. + +### proto2 enums + +For proto2, we do not need to be concerned about unknown enum values, so we can +use the simple raw-value enum syntax provided by Swift. So the following enum in +proto2: + +```protobuf +enum ContentType { + TEXT = 0; + IMAGE = 1; +} +``` + +would become this Swift enum: + +```swift +public enum ContentType: Int32, NilLiteralConvertible { + case text = 0 + case image = 1 + + public init(nilLiteral: ()) { + self = .text + } +} +``` + +See below for the discussion about `NilLiteralConvertible`. + +### proto3 enums + +For proto3, we need to be able to preserve unknown enum values that may come +across the wire so that they can be written back if unmodified. We can +accomplish this in Swift by using a case with an associated value for unknowns. +So the following enum in proto3: + +```protobuf +enum ContentType { + TEXT = 0; + IMAGE = 1; +} +``` + +would become this Swift enum: + +```swift +public enum ContentType: RawRepresentable, NilLiteralConvertible { + case text + case image + case UNKNOWN_VALUE(Int32) + + public typealias RawValue = Int32 + + public init(nilLiteral: ()) { + self = .text + } + + public init(rawValue: RawValue) { + switch rawValue { + case 0: self = .text + case 1: self = .image + default: self = .UNKNOWN_VALUE(rawValue) + } + + public var rawValue: RawValue { + switch self { + case .text: return 0 + case .image: return 1 + case .UNKNOWN_VALUE(let value): return value + } + } +} +``` + +Note that the use of a parameterized case prevents us from inheriting from the +raw `Int32` type; Swift does not allow an enum with a raw type to have cases +with arguments. Instead, we must implement the raw value initializer and +computed property manually. The `UNKNOWN_VALUE` case is explicitly chosen to be +"ugly" so that it stands out and does not conflict with other possible case +names. + +Using this approach, proto3 consumers must always have a default case or handle +the `.UNKNOWN_VALUE` case to satisfy case exhaustion in a switch statement; the +Swift compiler considers it an error if switch statements are not exhaustive. + +### NilLiteralConvertible conformance + +This is required to clean up the usage of enum-typed properties in switch +statements. Unlike other field types, enum properties cannot be +implicitly-unwrapped optionals without requiring that uses in switch statements +be explicitly unwrapped. For example, if we consider a message with the enum +above, this usage will fail to compile: + +```swift +// Without NilLiteralConvertible conformance on ContentType +public struct SomeMessage: ProtoMessage { + public var contentType: ContentType! { ... } +} + +// ERROR: no case named text or image +switch someMessage.contentType { + case .text: { ... } + case .image: { ... } +} +``` + +Even though our implementation guarantees that `contentType` will never be nil, +if it is an optional type, its cases would be `some` and `none`, not the cases +of the underlying enum type. In order to use it in this context, the user must +write `someMessage.contentType!` in their switch statement. + +Making the enum itself `NilLiteralConvertible` permits us to make the property +non-optional, so the user can still set it to nil to clear it (i.e., reset it to +its default value), while eliminating the need to explicitly unwrap it in a +switch statement. + +```swift +// With NilLiteralConvertible conformance on ContentType +public struct SomeMessage: ProtoMessage { + // Note that the property type is no longer optional + public var contentType: ContentType { ... } +} + +// OK: Compiles and runs as expected +switch someMessage.contentType { + case .text: { ... } + case .image: { ... } +} + +// The enum can be reset to its default value this way +someMessage.contentType = nil +``` + +One minor oddity with this approach is that nil will be auto-converted to the +default value of the enum in any context, not just field assignment. In other +words, this is valid: + +```swift +func foo(contentType: ContentType) { ... } +foo(nil) // Inside foo, contentType == .text +``` + +That being said, the advantage of being able to simultaneously support +nil-resettability and switch-without-unwrapping outweighs this side effect, +especially if appropriately documented. It is our hope that a new form of +resettable properties will be added to Swift that eliminates this inconsistency. +Some community members have already drafted or sent proposals for review that +would benefit our designs: + +* [SE-0030: Property Behaviors] + (https://github.com/apple/swift-evolution/blob/master/proposals/0030-property-behavior-decls.md) +* [Drafted: Resettable Properties] + (https://github.com/patters/swift-evolution/blob/master/proposals/0000-resettable-properties.md) + +### Enum aliases + +The `allow_alias` option in protobuf slightly complicates the use of Swift enums +to represent that type, because raw values of cases in an enum must be unique. +Swift lets us define static variables in an enum that alias actual cases. For +example, the following protobuf enum: + +```protobuf +enum Foo { + option allow_alias = true; + BAR = 0; + BAZ = 0; +} +``` + +will be represented in Swift as: + +```swift +public enum Foo: Int32, NilLiteralConvertible { + case bar = 0 + static public let baz = bar + + // ... etc. +} + +// Can still use .baz shorthand to reference the alias in contexts +// where the type is inferred +``` + +That is, we use the first name as the actual case and use static variables for +the other aliases. One drawback to this approach is that the static aliases +cannot be used as cases in a switch statement (the compiler emits the error +*“Enum case ‘baz’ not found in type ‘Foo’”*). However, in our own code bases, +there are only a few places where enum aliases are not mere renamings of an +older value, but they also don’t appear to be the type of value that one would +expect to switch on (for example, a group of named constants representing +metrics rather than a set of options), so this restriction is not significant. + +This strategy also implies that changing the name of an enum and adding the old +name as an alias below the new name will be a breaking change in the generated +Swift code. + +## Oneof types + +The `oneof` feature represents a “variant/union” data type that maps nicely to +Swift enums with associated values (algebraic types). These fields can also be +accessed independently though, and, specifically in the case of proto2, it’s +reasonable to expect access to default values when accessing a field that is not +explicitly set. + +Taking all this into account, we can represent a `oneof` in Swift with two sets +of constructs: + +* Properties in the message that correspond to the `oneof` fields. +* A nested enum named after the `oneof` and which provides the corresponding + field values as case arguments. + +This approach fulfills the needs of proto consumers by providing a +Swift-idiomatic way of simultaneously checking which field is set and accessing +its value, providing individual properties to access the default values +(important for proto2), and safely allows a field to be moved into a `oneof` +without breaking clients. + +Consider the following proto: + +```protobuf +message MyMessage { + oneof record { + string name = 1 [default = "unnamed"]; + int32 id_number = 2 [default = 0]; + } +} +``` + +In Swift, we would generate an enum, a property for that enum, and properties +for the fields themselves: + +```swift +public struct MyMessage: ProtoMessage { + public enum Record: NilLiteralConvertible { + case name(String) + case idNumber(Int32) + case NOT_SET + + public init(nilLiteral: ()) { self = .NOT_SET } + } + + // This is the "Swifty" way of accessing the value + public var record: Record { ... } + + // Direct access to the underlying fields + public var name: String! { ... } + public var idNumber: Int32! { ... } +} +``` + +This makes both usage patterns possible: + +```swift +// Usage 1: Case-based dispatch +switch message.record { + case .name(let name): + // Do something with name if it was explicitly set + case .idNumber(let id): + // Do something with id_number if it was explicitly set + case .NOT_SET: + // Do something if it’s not set +} + +// Usage 2: Direct access for default value fallback +// Sets the label text to the name if it was explicitly set, or to +// "unnamed" (the default value for the field) if id_number was set +// instead +let myLabel = UILabel() +myLabel.text = message.name +``` + +As with proto enums, the generated `oneof` enum conforms to +`NilLiteralConvertible` to avoid switch statement issues. Setting the property +to nil will clear it (i.e., reset it to `NOT_SET`). + +## Unknown Fields (proto2 only) + +To be written. + +## Extensions (proto2 only) + +To be written. + +## Reflection and Descriptors + +We will not include reflection or descriptors in the first version of the Swift +library. The use cases for reflection on mobile are not as strong and the static +data to represent the descriptors would add bloat when we wish to keep the code +size small. + +In the future, we will investigate whether they can be included as extensions +which might be able to be excluded from a build and/or automatically dead +stripped by the compiler if they are not used. + +## Appendix A: Rejected strategies to handle packages + +### Each package is its own Swift module + +Each proto package could be declared as its own Swift module, replacing dots +with underscores (e.g., package `foo.bar` becomes module `Foo_Bar`). Then, users +would simply import modules containing whatever proto modules they want to use +and refer to the generated types by their short names. + +**This solution is simply not possible, however.** Swift modules cannot +circularly reference each other, but there is no restriction against proto +packages doing so. Circular imports are forbidden (e.g., `foo.proto` importing +`bar.proto` importing `foo.proto`), but nothing prevents package `foo` from +using a type in package `bar` which uses a different type in package `foo`, as +long as there is no import cycle. If these packages were generated as Swift +modules, then `Foo` would contain an `import Bar` statement and `Bar` would +contain an `import Foo` statement, and there is no way to compile this. + +### Ad hoc namespacing with structs + +We can “fake” namespaces in Swift by declaring empty structs with private +initializers. Since modules are constructed based on compiler arguments, not by +syntactic constructs, and because there is no pure Swift way to define +submodules (even though Clang module maps support this), there is no +source-drive way to group generated code into namespaces aside from this +approach. + +Types can be added to those intermediate package structs using Swift extensions. +For example, a message `Baz` in package `foo.bar` could be represented in Swift +as follows: + +```swift +public struct Foo { + private init() {} +} + +public extension Foo { + public struct Bar { + private init() {} + } +} + +public extension Foo.Bar { + public struct Baz { + // Message fields and other methods + } +} + +let baz = Foo.Bar.Baz() +``` + +Each of these constructs would actually be defined in a separate file; Swift +lets us keep them separate and add multiple structs to a single “namespace” +through extensions. + +Unfortunately, these intermediate structs generate symbols of their own +(metatype information in the data segment). This becomes problematic if multiple +build targets contain Swift sources generated from different messages in the +same package. At link time, these symbols would collide, resulting in multiple +definition errors. + +This approach also has the disadvantage that there is no automatic “short” way +to refer to the generated messages at the deepest nesting levels; since this use +of structs is a hack around the lack of namespaces, there is no equivalent to +import (Java) or using (C++) to simplify this. Users would have to declare type +aliases to make this cleaner, or we would have to generate them for users. From d419ca10b4521e87d0be62f6df4ede97d63c7ee2 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 22 Apr 2016 14:11:39 -0700 Subject: [PATCH 095/123] Updated upb and simplified ruby code a bit with new upb method. --- ruby/ext/google/protobuf_c/encode_decode.c | 7 +- ruby/ext/google/protobuf_c/message.c | 38 +- ruby/ext/google/protobuf_c/upb.c | 1404 +++++++++++--------- ruby/ext/google/protobuf_c/upb.h | 1379 ++++++++++--------- 4 files changed, 1579 insertions(+), 1249 deletions(-) diff --git a/ruby/ext/google/protobuf_c/encode_decode.c b/ruby/ext/google/protobuf_c/encode_decode.c index 9bc7273e..f6bea50f 100644 --- a/ruby/ext/google/protobuf_c/encode_decode.c +++ b/ruby/ext/google/protobuf_c/encode_decode.c @@ -656,7 +656,6 @@ static const upb_json_parsermethod *msgdef_jsonparsermethod(Descriptor* desc) { #define STACK_ENV_STACKBYTES 4096 typedef struct { upb_env env; - upb_seededalloc alloc; const char* ruby_error_template; char allocbuf[STACK_ENV_STACKBYTES]; } stackenv; @@ -681,16 +680,12 @@ static bool env_error_func(void* ud, const upb_status* status) { static void stackenv_init(stackenv* se, const char* errmsg) { se->ruby_error_template = errmsg; - upb_env_init(&se->env); - upb_seededalloc_init(&se->alloc, &se->allocbuf, STACK_ENV_STACKBYTES); - upb_env_setallocfunc( - &se->env, upb_seededalloc_getallocfunc(&se->alloc), &se->alloc); + upb_env_init2(&se->env, se->allocbuf, sizeof(se->allocbuf), NULL); upb_env_seterrorfunc(&se->env, env_error_func, se); } static void stackenv_uninit(stackenv* se) { upb_env_uninit(&se->env); - upb_seededalloc_uninit(&se->alloc); } /* diff --git a/ruby/ext/google/protobuf_c/message.c b/ruby/ext/google/protobuf_c/message.c index 3a51fe47..e16250f3 100644 --- a/ruby/ext/google/protobuf_c/message.c +++ b/ruby/ext/google/protobuf_c/message.c @@ -151,32 +151,30 @@ VALUE Message_method_missing(int argc, VALUE* argv, VALUE _self) { name_len--; } - // Check for a oneof name first. - o = upb_msgdef_ntoo(self->descriptor->msgdef, - name, name_len); + // See if this name corresponds to either a oneof or field in this message. + if (!upb_msgdef_lookupname(self->descriptor->msgdef, name, name_len, &f, + &o)) { + return rb_call_super(argc, argv); + } + if (o != NULL) { + // This is a oneof -- return which field inside the oneof is set. if (setter) { rb_raise(rb_eRuntimeError, "Oneof accessors are read-only."); } return which_oneof_field(self, o); - } - - // Otherwise, check for a field with that name. - f = upb_msgdef_ntof(self->descriptor->msgdef, - name, name_len); - - if (f == NULL) { - return rb_call_super(argc, argv); - } - - if (setter) { - if (argc < 2) { - rb_raise(rb_eArgError, "No value provided to setter."); - } - layout_set(self->descriptor->layout, Message_data(self), f, argv[1]); - return Qnil; } else { - return layout_get(self->descriptor->layout, Message_data(self), f); + // This is a field -- get or set the field's value. + assert(f); + if (setter) { + if (argc < 2) { + rb_raise(rb_eArgError, "No value provided to setter."); + } + layout_set(self->descriptor->layout, Message_data(self), f, argv[1]); + return Qnil; + } else { + return layout_get(self->descriptor->layout, Message_data(self), f); + } } } diff --git a/ruby/ext/google/protobuf_c/upb.c b/ruby/ext/google/protobuf_c/upb.c index 212f1e0e..74a2a1db 100644 --- a/ruby/ext/google/protobuf_c/upb.c +++ b/ruby/ext/google/protobuf_c/upb.c @@ -12,7 +12,7 @@ typedef struct { } str_t; static str_t *newstr(const char *data, size_t len) { - str_t *ret = malloc(sizeof(*ret) + len); + str_t *ret = upb_gmalloc(sizeof(*ret) + len); if (!ret) return NULL; ret->len = len; memcpy(ret->str, data, len); @@ -20,7 +20,7 @@ static str_t *newstr(const char *data, size_t len) { return ret; } -static void freestr(str_t *s) { free(s); } +static void freestr(str_t *s) { upb_gfree(s); } /* isalpha() etc. from are locale-dependent, which we don't want. */ static bool upb_isbetween(char c, char low, char high) { @@ -65,6 +65,22 @@ static bool upb_isident(const char *str, size_t len, bool full, upb_status *s) { return !start; } +static bool upb_isoneof(const upb_refcounted *def) { + return def->vtbl == &upb_oneofdef_vtbl; +} + +static bool upb_isfield(const upb_refcounted *def) { + return def->vtbl == &upb_fielddef_vtbl; +} + +static const upb_oneofdef *upb_trygetoneof(const upb_refcounted *def) { + return upb_isoneof(def) ? (const upb_oneofdef*)def : NULL; +} + +static const upb_fielddef *upb_trygetfield(const upb_refcounted *def) { + return upb_isfield(def) ? (const upb_fielddef*)def : NULL; +} + /* upb_def ********************************************************************/ @@ -88,9 +104,18 @@ const char *upb_def_name(const upb_def *d) { bool upb_def_setfullname(upb_def *def, const char *fullname, upb_status *s) { assert(!upb_def_isfrozen(def)); - if (!upb_isident(fullname, strlen(fullname), true, s)) return false; - free((void*)def->fullname); - def->fullname = upb_strdup(fullname); + if (!upb_isident(fullname, strlen(fullname), true, s)) { + return false; + } + + fullname = upb_gstrdup(fullname); + if (!fullname) { + upb_upberr_setoom(s); + return false; + } + + upb_gfree((void*)def->fullname); + def->fullname = fullname; return true; } @@ -123,7 +148,7 @@ static bool upb_def_init(upb_def *def, upb_deftype_t type, } static void upb_def_uninit(upb_def *def) { - free((void*)def->fullname); + upb_gfree((void*)def->fullname); } static const char *msgdef_name(const upb_msgdef *m) { @@ -260,8 +285,19 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { int i; uint32_t selector; int n = upb_msgdef_numfields(m); - upb_fielddef **fields = malloc(n * sizeof(*fields)); - if (!fields) return false; + upb_fielddef **fields; + + if (n == 0) { + m->selector_count = UPB_STATIC_SELECTOR_COUNT; + m->submsg_field_count = 0; + return true; + } + + fields = upb_gmalloc(n * sizeof(*fields)); + if (!fields) { + upb_upberr_setoom(s); + return false; + } m->submsg_field_count = 0; for(i = 0, upb_msg_field_begin(&j, m); @@ -270,7 +306,7 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { upb_fielddef *f = upb_msg_iter_field(&j); assert(f->msg.def == m); if (!upb_validate_field(f, s)) { - free(fields); + upb_gfree(fields); return false; } if (upb_fielddef_issubmsg(f)) { @@ -330,7 +366,7 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { #undef TRY #endif - free(fields); + upb_gfree(fields); return true; } @@ -407,21 +443,26 @@ static void upb_enumdef_free(upb_refcounted *r) { upb_inttable_iter i; upb_inttable_begin(&i, &e->iton); for( ; !upb_inttable_done(&i); upb_inttable_next(&i)) { - /* To clean up the upb_strdup() from upb_enumdef_addval(). */ - free(upb_value_getcstr(upb_inttable_iter_value(&i))); + /* To clean up the upb_gstrdup() from upb_enumdef_addval(). */ + upb_gfree(upb_value_getcstr(upb_inttable_iter_value(&i))); } upb_strtable_uninit(&e->ntoi); upb_inttable_uninit(&e->iton); upb_def_uninit(upb_enumdef_upcast_mutable(e)); - free(e); + upb_gfree(e); } +const struct upb_refcounted_vtbl upb_enumdef_vtbl = {NULL, &upb_enumdef_free}; + upb_enumdef *upb_enumdef_new(const void *owner) { - static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_enumdef_free}; - upb_enumdef *e = malloc(sizeof(*e)); + upb_enumdef *e = upb_gmalloc(sizeof(*e)); if (!e) return NULL; - if (!upb_def_init(upb_enumdef_upcast_mutable(e), UPB_DEF_ENUM, &vtbl, owner)) + + if (!upb_def_init(upb_enumdef_upcast_mutable(e), UPB_DEF_ENUM, + &upb_enumdef_vtbl, owner)) { goto err2; + } + if (!upb_strtable_init(&e->ntoi, UPB_CTYPE_INT32)) goto err2; if (!upb_inttable_init(&e->iton, UPB_CTYPE_CSTR)) goto err1; return e; @@ -429,7 +470,7 @@ upb_enumdef *upb_enumdef_new(const void *owner) { err1: upb_strtable_uninit(&e->ntoi); err2: - free(e); + upb_gfree(e); return NULL; } @@ -468,27 +509,36 @@ bool upb_enumdef_setfullname(upb_enumdef *e, const char *fullname, bool upb_enumdef_addval(upb_enumdef *e, const char *name, int32_t num, upb_status *status) { + char *name2; + if (!upb_isident(name, strlen(name), false, status)) { return false; } + if (upb_enumdef_ntoiz(e, name, NULL)) { upb_status_seterrf(status, "name '%s' is already defined", name); return false; } + if (!upb_strtable_insert(&e->ntoi, name, upb_value_int32(num))) { upb_status_seterrmsg(status, "out of memory"); return false; } - if (!upb_inttable_lookup(&e->iton, num, NULL) && - !upb_inttable_insert(&e->iton, num, upb_value_cstr(upb_strdup(name)))) { - upb_status_seterrmsg(status, "out of memory"); - upb_strtable_remove(&e->ntoi, name, NULL); - return false; + + if (!upb_inttable_lookup(&e->iton, num, NULL)) { + name2 = upb_gstrdup(name); + if (!name2 || !upb_inttable_insert(&e->iton, num, upb_value_cstr(name2))) { + upb_status_seterrmsg(status, "out of memory"); + upb_strtable_remove(&e->ntoi, name, NULL); + return false; + } } + if (upb_enumdef_numvals(e) == 1) { bool ok = upb_enumdef_setdefault(e, num, NULL); UPB_ASSERT_VAR(ok, ok); } + return true; } @@ -575,9 +625,9 @@ static void freefield(upb_refcounted *r) { upb_fielddef *f = (upb_fielddef*)r; upb_fielddef_uninit_default(f); if (f->subdef_is_symbolic) - free(f->sub.name); + upb_gfree(f->sub.name); upb_def_uninit(upb_fielddef_upcast_mutable(f)); - free(f); + upb_gfree(f); } static const char *enumdefaultstr(const upb_fielddef *f) { @@ -633,12 +683,14 @@ static bool enumdefaultint32(const upb_fielddef *f, int32_t *val) { return false; } +const struct upb_refcounted_vtbl upb_fielddef_vtbl = {visitfield, freefield}; + upb_fielddef *upb_fielddef_new(const void *o) { - static const struct upb_refcounted_vtbl vtbl = {visitfield, freefield}; - upb_fielddef *f = malloc(sizeof(*f)); + upb_fielddef *f = upb_gmalloc(sizeof(*f)); if (!f) return NULL; - if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD, &vtbl, o)) { - free(f); + if (!upb_def_init(upb_fielddef_upcast_mutable(f), UPB_DEF_FIELD, + &upb_fielddef_vtbl, o)) { + upb_gfree(f); return NULL; } f->msg.def = NULL; @@ -689,7 +741,7 @@ upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { srcname = f->sub.def ? upb_def_fullname(f->sub.def) : NULL; } if (srcname) { - char *newname = malloc(strlen(f->sub.def->fullname) + 2); + char *newname = upb_gmalloc(strlen(f->sub.def->fullname) + 2); if (!newname) { upb_fielddef_unref(newf, owner); return NULL; @@ -697,7 +749,7 @@ upb_fielddef *upb_fielddef_dup(const upb_fielddef *f, const void *owner) { strcpy(newname, "."); strcat(newname, f->sub.def->fullname); upb_fielddef_setsubdefname(newf, newname, NULL); - free(newname); + upb_gfree(newname); } return newf; @@ -804,11 +856,12 @@ const char *upb_fielddef_containingtypename(upb_fielddef *f) { } static void release_containingtype(upb_fielddef *f) { - if (f->msg_is_symbolic) free(f->msg.name); + if (f->msg_is_symbolic) upb_gfree(f->msg.name); } bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, upb_status *s) { + char *name_copy; assert(!upb_fielddef_isfrozen(f)); if (upb_fielddef_containingtype(f)) { upb_status_seterrmsg(s, "field has already been added to a message."); @@ -816,8 +869,15 @@ bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, } /* TODO: validate name (upb_isident() doesn't quite work atm because this name * may have a leading "."). */ + + name_copy = upb_gstrdup(name); + if (!name_copy) { + upb_upberr_setoom(s); + return false; + } + release_containingtype(f); - f->msg.name = upb_strdup(name); + f->msg.name = name_copy; f->msg_is_symbolic = true; return true; } @@ -1218,7 +1278,7 @@ static bool upb_subdef_typecheck(upb_fielddef *f, const upb_def *subdef, static void release_subdef(upb_fielddef *f) { if (f->subdef_is_symbolic) { - free(f->sub.name); + upb_gfree(f->sub.name); } else if (f->sub.def) { upb_unref2(f->sub.def, f); } @@ -1248,15 +1308,23 @@ bool upb_fielddef_setenumsubdef(upb_fielddef *f, const upb_enumdef *subdef, bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status *s) { + char *name_copy; assert(!upb_fielddef_isfrozen(f)); if (!upb_fielddef_hassubdef(f)) { upb_status_seterrmsg(s, "field type does not accept a subdef"); return false; } + + name_copy = upb_gstrdup(name); + if (!name_copy) { + upb_upberr_setoom(s); + return false; + } + /* TODO: validate name (upb_isident() doesn't quite work atm because this name * may have a leading "."). */ release_subdef(f); - f->sub.name = upb_strdup(name); + f->sub.name = name_copy; f->subdef_is_symbolic = true; return true; } @@ -1332,32 +1400,33 @@ static void visitmsg(const upb_refcounted *r, upb_refcounted_visit *visit, static void freemsg(upb_refcounted *r) { upb_msgdef *m = (upb_msgdef*)r; - upb_strtable_uninit(&m->ntoo); upb_strtable_uninit(&m->ntof); upb_inttable_uninit(&m->itof); upb_def_uninit(upb_msgdef_upcast_mutable(m)); - free(m); + upb_gfree(m); } +const struct upb_refcounted_vtbl upb_msgdef_vtbl = {visitmsg, freemsg}; + upb_msgdef *upb_msgdef_new(const void *owner) { - static const struct upb_refcounted_vtbl vtbl = {visitmsg, freemsg}; - upb_msgdef *m = malloc(sizeof(*m)); + upb_msgdef *m = upb_gmalloc(sizeof(*m)); if (!m) return NULL; - if (!upb_def_init(upb_msgdef_upcast_mutable(m), UPB_DEF_MSG, &vtbl, owner)) + + if (!upb_def_init(upb_msgdef_upcast_mutable(m), UPB_DEF_MSG, &upb_msgdef_vtbl, + owner)) { goto err2; - if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err3; - if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err2; - if (!upb_strtable_init(&m->ntoo, UPB_CTYPE_PTR)) goto err1; + } + + if (!upb_inttable_init(&m->itof, UPB_CTYPE_PTR)) goto err2; + if (!upb_strtable_init(&m->ntof, UPB_CTYPE_PTR)) goto err1; m->map_entry = false; m->syntax = UPB_SYNTAX_PROTO2; return m; err1: - upb_strtable_uninit(&m->ntof); -err2: upb_inttable_uninit(&m->itof); -err3: - free(m); +err2: + upb_gfree(m); return NULL; } @@ -1415,6 +1484,19 @@ bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, return upb_def_setfullname(upb_msgdef_upcast_mutable(m), fullname, s); } +bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax) { + if (syntax != UPB_SYNTAX_PROTO2 && syntax != UPB_SYNTAX_PROTO3) { + return false; + } + + m->syntax = syntax; + return true; +} + +upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m) { + return m->syntax; +} + /* Helper: check that the field |f| is safe to add to msgdef |m|. Set an error * on status |s| and return false if not. */ static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f, @@ -1425,9 +1507,11 @@ static bool check_field_add(const upb_msgdef *m, const upb_fielddef *f, } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { upb_status_seterrmsg(s, "field name or number were not set"); return false; - } else if (upb_msgdef_ntofz(m, upb_fielddef_name(f)) || - upb_msgdef_itof(m, upb_fielddef_number(f))) { - upb_status_seterrmsg(s, "duplicate field name or number for field"); + } else if (upb_msgdef_itof(m, upb_fielddef_number(f))) { + upb_status_seterrmsg(s, "duplicate field number"); + return false; + } else if (upb_strtable_lookup(&m->ntof, upb_fielddef_name(f), NULL)) { + upb_status_seterrmsg(s, "name conflicts with existing field or oneof"); return false; } return true; @@ -1488,8 +1572,8 @@ bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, } else if (upb_oneofdef_name(o) == NULL) { upb_status_seterrmsg(s, "oneofdef name was not set"); return false; - } else if (upb_msgdef_ntooz(m, upb_oneofdef_name(o))) { - upb_status_seterrmsg(s, "duplicate oneof name"); + } else if (upb_strtable_lookup(&m->ntof, upb_oneofdef_name(o), NULL)) { + upb_status_seterrmsg(s, "name conflicts with existing field or oneof"); return false; } @@ -1506,7 +1590,7 @@ bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, /* Add oneof itself first. */ o->parent = m; - upb_strtable_insert(&m->ntoo, upb_oneofdef_name(o), upb_value_ptr(o)); + upb_strtable_insert(&m->ntof, upb_oneofdef_name(o), upb_value_ptr(o)); upb_ref2(o, m); upb_ref2(m, o); @@ -1530,23 +1614,47 @@ const upb_fielddef *upb_msgdef_itof(const upb_msgdef *m, uint32_t i) { const upb_fielddef *upb_msgdef_ntof(const upb_msgdef *m, const char *name, size_t len) { upb_value val; - return upb_strtable_lookup2(&m->ntof, name, len, &val) ? - upb_value_getptr(val) : NULL; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + return upb_trygetfield(upb_value_getptr(val)); } const upb_oneofdef *upb_msgdef_ntoo(const upb_msgdef *m, const char *name, size_t len) { upb_value val; - return upb_strtable_lookup2(&m->ntoo, name, len, &val) ? - upb_value_getptr(val) : NULL; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return NULL; + } + + return upb_trygetoneof(upb_value_getptr(val)); +} + +bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, + const upb_fielddef **f, const upb_oneofdef **o) { + upb_value val; + + if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { + return false; + } + + *o = upb_trygetoneof(upb_value_getptr(val)); + *f = upb_trygetfield(upb_value_getptr(val)); + assert((*o != NULL) ^ (*f != NULL)); /* Exactly one of the two should be set. */ + return true; } int upb_msgdef_numfields(const upb_msgdef *m) { - return upb_strtable_count(&m->ntof); + /* The number table contains only fields. */ + return upb_inttable_count(&m->itof); } int upb_msgdef_numoneofs(const upb_msgdef *m) { - return upb_strtable_count(&m->ntoo); + /* The name table includes oneofs, and the number table does not. */ + return upb_strtable_count(&m->ntof) - upb_inttable_count(&m->itof); } void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry) { @@ -1577,10 +1685,21 @@ void upb_msg_field_iter_setdone(upb_msg_field_iter *iter) { } void upb_msg_oneof_begin(upb_msg_oneof_iter *iter, const upb_msgdef *m) { - upb_strtable_begin(iter, &m->ntoo); + upb_strtable_begin(iter, &m->ntof); + /* We need to skip past any initial fields. */ + while (!upb_strtable_done(iter) && + !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter)))) { + upb_strtable_next(iter); + } } -void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { upb_strtable_next(iter); } +void upb_msg_oneof_next(upb_msg_oneof_iter *iter) { + /* We need to skip past fields to return only oneofs. */ + do { + upb_strtable_next(iter); + } while (!upb_strtable_done(iter) && + !upb_isoneof(upb_value_getptr(upb_strtable_iter_value(iter)))); +} bool upb_msg_oneof_done(const upb_msg_oneof_iter *iter) { return upb_strtable_done(iter); @@ -1613,26 +1732,36 @@ static void freeoneof(upb_refcounted *r) { upb_oneofdef *o = (upb_oneofdef*)r; upb_strtable_uninit(&o->ntof); upb_inttable_uninit(&o->itof); - free((void*)o->name); - free(o); + upb_gfree((void*)o->name); + upb_gfree(o); } +const struct upb_refcounted_vtbl upb_oneofdef_vtbl = {visitoneof, freeoneof}; + upb_oneofdef *upb_oneofdef_new(const void *owner) { - static const struct upb_refcounted_vtbl vtbl = {visitoneof, freeoneof}; - upb_oneofdef *o = malloc(sizeof(*o)); + upb_oneofdef *o = upb_gmalloc(sizeof(*o)); + + if (!o) { + return NULL; + } + o->parent = NULL; - if (!o) return NULL; - if (!upb_refcounted_init(upb_oneofdef_upcast_mutable(o), &vtbl, owner)) - goto err2; o->name = NULL; + + if (!upb_refcounted_init(upb_oneofdef_upcast_mutable(o), &upb_oneofdef_vtbl, + owner)) { + goto err2; + } + if (!upb_inttable_init(&o->itof, UPB_CTYPE_PTR)) goto err2; if (!upb_strtable_init(&o->ntof, UPB_CTYPE_PTR)) goto err1; + return o; err1: upb_inttable_uninit(&o->itof); err2: - free(o); + upb_gfree(o); return NULL; } @@ -1661,9 +1790,19 @@ bool upb_oneofdef_setname(upb_oneofdef *o, const char *name, upb_status *s) { upb_status_seterrmsg(s, "oneof already added to a message"); return false; } - if (!upb_isident(name, strlen(name), true, s)) return false; - free((void*)o->name); - o->name = upb_strdup(name); + + if (!upb_isident(name, strlen(name), true, s)) { + return false; + } + + name = upb_gstrdup(name); + if (!name) { + upb_status_seterrmsg(s, "One of memory"); + return false; + } + + upb_gfree((void*)o->name); + o->name = name; return true; } @@ -1805,14 +1944,15 @@ static void freefiledef(upb_refcounted *r) { upb_inttable_uninit(&f->defs); upb_inttable_uninit(&f->deps); - free((void*)f->name); - free((void*)f->package); - free(f); + upb_gfree((void*)f->name); + upb_gfree((void*)f->package); + upb_gfree(f); } +const struct upb_refcounted_vtbl upb_filedef_vtbl = {visitfiledef, freefiledef}; + upb_filedef *upb_filedef_new(const void *owner) { - static const struct upb_refcounted_vtbl vtbl = {visitfiledef, freefiledef}; - upb_filedef *f = malloc(sizeof(*f)); + upb_filedef *f = upb_gmalloc(sizeof(*f)); if (!f) { return NULL; @@ -1822,7 +1962,8 @@ upb_filedef *upb_filedef_new(const void *owner) { f->name = NULL; f->syntax = UPB_SYNTAX_PROTO2; - if (!upb_refcounted_init(upb_filedef_upcast_mutable(f), &vtbl, owner)) { + if (!upb_refcounted_init(upb_filedef_upcast_mutable(f), &upb_filedef_vtbl, + owner)) { goto err; } @@ -1841,7 +1982,7 @@ err2: upb_inttable_uninit(&f->defs); err: - free(f); + upb_gfree(f); return NULL; } @@ -1886,12 +2027,12 @@ const upb_filedef *upb_filedef_dep(const upb_filedef *f, size_t i) { } bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s) { - name = upb_strdup(name); + name = upb_gstrdup(name); if (!name) { - upb_status_seterrmsg(s, "Out of memory"); + upb_upberr_setoom(s); return false; } - free((void*)f->name); + upb_gfree((void*)f->name); f->name = name; return true; } @@ -1899,12 +2040,12 @@ bool upb_filedef_setname(upb_filedef *f, const char *name, upb_status *s) { bool upb_filedef_setpackage(upb_filedef *f, const char *package, upb_status *s) { if (!upb_isident(package, strlen(package), true, s)) return false; - package = upb_strdup(package); + package = upb_gstrdup(package); if (!package) { - upb_status_seterrmsg(s, "Out of memory"); + upb_upberr_setoom(s); return false; } - free((void*)f->package); + upb_gfree((void*)f->package); f->package = package; return true; } @@ -1953,7 +2094,7 @@ bool upb_filedef_adddef(upb_filedef *f, upb_def *def, const void *ref_donor, } return true; } else { - upb_status_seterrmsg(s, "Out of memory."); + upb_upberr_setoom(s); return false; } } @@ -1967,288 +2108,22 @@ bool upb_filedef_adddep(upb_filedef *f, const upb_filedef *dep) { return false; } } - - -#include -#include -#include - -typedef struct cleanup_ent { - upb_cleanup_func *cleanup; - void *ud; - struct cleanup_ent *next; -} cleanup_ent; - -static void *seeded_alloc(void *ud, void *ptr, size_t oldsize, size_t size); - -/* Default allocator **********************************************************/ - -/* Just use realloc, keeping all allocated blocks in a linked list to destroy at - * the end. */ - -typedef struct mem_block { - /* List is doubly-linked, because in cases where realloc() moves an existing - * block, we need to be able to remove the old pointer from the list - * efficiently. */ - struct mem_block *prev, *next; -#ifndef NDEBUG - size_t size; /* Doesn't include mem_block structure. */ -#endif -} mem_block; - -typedef struct { - mem_block *head; -} default_alloc_ud; - -static void *default_alloc(void *_ud, void *ptr, size_t oldsize, size_t size) { - default_alloc_ud *ud = _ud; - mem_block *from, *block; - void *ret; - UPB_UNUSED(oldsize); - - from = ptr ? (void*)((char*)ptr - sizeof(mem_block)) : NULL; - -#ifndef NDEBUG - if (from) { - assert(oldsize <= from->size); - } -#endif - - /* TODO(haberman): we probably need to provide even better alignment here, - * like 16-byte alignment of the returned data pointer. */ - block = realloc(from, size + sizeof(mem_block)); - if (!block) return NULL; - ret = (char*)block + sizeof(*block); - -#ifndef NDEBUG - block->size = size; -#endif - - if (from) { - if (block != from) { - /* The block was moved, so pointers in next and prev blocks must be - * updated to its new location. */ - if (block->next) block->next->prev = block; - if (block->prev) block->prev->next = block; - if (ud->head == from) ud->head = block; - } - } else { - /* Insert at head of linked list. */ - block->prev = NULL; - block->next = ud->head; - if (block->next) block->next->prev = block; - ud->head = block; - } - - return ret; -} - -static void default_alloc_cleanup(void *_ud) { - default_alloc_ud *ud = _ud; - mem_block *block = ud->head; - - while (block) { - void *to_free = block; - block = block->next; - free(to_free); - } -} - - -/* Standard error functions ***************************************************/ - -static bool default_err(void *ud, const upb_status *status) { - UPB_UNUSED(ud); - UPB_UNUSED(status); - return false; -} - -static bool write_err_to(void *ud, const upb_status *status) { - upb_status *copy_to = ud; - upb_status_copy(copy_to, status); - return false; -} - - -/* upb_env ********************************************************************/ - -void upb_env_init(upb_env *e) { - default_alloc_ud *ud = (default_alloc_ud*)&e->default_alloc_ud; - e->ok_ = true; - e->bytes_allocated = 0; - e->cleanup_head = NULL; - - ud->head = NULL; - - /* Set default functions. */ - upb_env_setallocfunc(e, default_alloc, ud); - upb_env_seterrorfunc(e, default_err, NULL); -} - -void upb_env_uninit(upb_env *e) { - cleanup_ent *ent = e->cleanup_head; - - while (ent) { - ent->cleanup(ent->ud); - ent = ent->next; - } - - /* Must do this after running cleanup functions, because this will delete - the memory we store our cleanup entries in! */ - if (e->alloc == default_alloc) { - default_alloc_cleanup(e->alloc_ud); - } -} - -UPB_FORCEINLINE void upb_env_setallocfunc(upb_env *e, upb_alloc_func *alloc, - void *ud) { - e->alloc = alloc; - e->alloc_ud = ud; -} - -UPB_FORCEINLINE void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, - void *ud) { - e->err = func; - e->err_ud = ud; -} - -void upb_env_reporterrorsto(upb_env *e, upb_status *status) { - e->err = write_err_to; - e->err_ud = status; -} - -bool upb_env_ok(const upb_env *e) { - return e->ok_; -} - -bool upb_env_reporterror(upb_env *e, const upb_status *status) { - e->ok_ = false; - return e->err(e->err_ud, status); -} - -bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud) { - cleanup_ent *ent = upb_env_malloc(e, sizeof(cleanup_ent)); - if (!ent) return false; - - ent->cleanup = func; - ent->ud = ud; - ent->next = e->cleanup_head; - e->cleanup_head = ent; - - return true; -} - -void *upb_env_malloc(upb_env *e, size_t size) { - e->bytes_allocated += size; - if (e->alloc == seeded_alloc) { - /* This is equivalent to the next branch, but allows inlining for a - * measurable perf benefit. */ - return seeded_alloc(e->alloc_ud, NULL, 0, size); - } else { - return e->alloc(e->alloc_ud, NULL, 0, size); - } -} - -void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size) { - char *ret; - assert(oldsize <= size); - ret = e->alloc(e->alloc_ud, ptr, oldsize, size); - -#ifndef NDEBUG - /* Overwrite non-preserved memory to ensure callers are passing the oldsize - * that they truly require. */ - memset(ret + oldsize, 0xff, size - oldsize); -#endif - - return ret; -} - -size_t upb_env_bytesallocated(const upb_env *e) { - return e->bytes_allocated; -} - - -/* upb_seededalloc ************************************************************/ - -/* Be conservative and choose 16 in case anyone is using SSE. */ -static const size_t maxalign = 16; - -static size_t align_up(size_t size) { - return ((size + maxalign - 1) / maxalign) * maxalign; -} - -UPB_FORCEINLINE static void *seeded_alloc(void *ud, void *ptr, size_t oldsize, - size_t size) { - upb_seededalloc *a = ud; - - size = align_up(size); - - assert(a->mem_limit >= a->mem_ptr); - - if (oldsize == 0 && size <= (size_t)(a->mem_limit - a->mem_ptr)) { - /* Fast path: we can satisfy from the initial allocation. */ - void *ret = a->mem_ptr; - a->mem_ptr += size; - return ret; - } else { - char *chptr = ptr; - /* Slow path: fallback to other allocator. */ - a->need_cleanup = true; - /* Is `ptr` part of the user-provided initial block? Don't pass it to the - * default allocator if so; otherwise, it may try to realloc() the block. */ - if (chptr >= a->mem_base && chptr < a->mem_limit) { - void *ret; - assert(chptr + oldsize <= a->mem_limit); - ret = a->alloc(a->alloc_ud, NULL, 0, size); - if (ret) memcpy(ret, ptr, oldsize); - return ret; - } else { - return a->alloc(a->alloc_ud, ptr, oldsize, size); - } - } -} - -void upb_seededalloc_init(upb_seededalloc *a, void *mem, size_t len) { - default_alloc_ud *ud = (default_alloc_ud*)&a->default_alloc_ud; - a->mem_base = mem; - a->mem_ptr = mem; - a->mem_limit = (char*)mem + len; - a->need_cleanup = false; - a->returned_allocfunc = false; - - ud->head = NULL; - - upb_seededalloc_setfallbackalloc(a, default_alloc, ud); -} - -void upb_seededalloc_uninit(upb_seededalloc *a) { - if (a->alloc == default_alloc && a->need_cleanup) { - default_alloc_cleanup(a->alloc_ud); - } -} - -UPB_FORCEINLINE void upb_seededalloc_setfallbackalloc(upb_seededalloc *a, - upb_alloc_func *alloc, - void *ud) { - assert(!a->returned_allocfunc); - a->alloc = alloc; - a->alloc_ud = ud; -} - -upb_alloc_func *upb_seededalloc_getallocfunc(upb_seededalloc *a) { - a->returned_allocfunc = true; - return seeded_alloc; -} /* ** TODO(haberman): it's unclear whether a lot of the consistency checks should ** assert() or return false. */ -#include #include +static void *upb_calloc(size_t size) { + void *mem = upb_gmalloc(size); + if (mem) { + memset(mem, 0, size); + } + return mem; +} /* Defined for the sole purpose of having a unique pointer value for * UPB_NO_CLOSURE. */ @@ -2268,8 +2143,8 @@ static void freehandlers(upb_refcounted *r) { upb_inttable_uninit(&h->cleanup_); upb_msgdef_unref(h->msg, h); - free(h->sub); - free(h); + upb_gfree(h->sub); + upb_gfree(h); } static void visithandlers(const upb_refcounted *r, upb_refcounted_visit *visit, @@ -2519,14 +2394,20 @@ upb_handlers *upb_handlers_new(const upb_msgdef *md, const void *owner) { assert(upb_msgdef_isfrozen(md)); extra = sizeof(upb_handlers_tabent) * (md->selector_count - 1); - h = calloc(sizeof(*h) + extra, 1); + h = upb_calloc(sizeof(*h) + extra); if (!h) return NULL; h->msg = md; upb_msgdef_ref(h->msg, h); upb_status_clear(&h->status_); - h->sub = calloc(md->submsg_field_count, sizeof(*h->sub)); - if (!h->sub) goto oom; + + if (md->submsg_field_count > 0) { + h->sub = upb_calloc(md->submsg_field_count * sizeof(*h->sub)); + if (!h->sub) goto oom; + } else { + h->sub = 0; + } + if (!upb_refcounted_init(upb_handlers_upcast_mutable(h), &vtbl, owner)) goto oom; if (!upb_inttable_init(&h->cleanup_, UPB_CTYPE_FPTR)) goto oom; @@ -2941,7 +2822,6 @@ bool upb_byteshandler_setendstr(upb_byteshandler *h, #include -#include static void freeobj(upb_refcounted *o); @@ -3017,8 +2897,31 @@ void upb_unlock(); /* UPB_DEBUG_REFS mode counts on being able to malloc() memory in some * code-paths that can normally never fail, like upb_refcounted_ref(). Since * we have no way to propagage out-of-memory errors back to the user, and since - * these errors can only occur in UPB_DEBUG_REFS mode, we immediately fail. */ -#define CHECK_OOM(predicate) if (!(predicate)) { assert(predicate); exit(1); } + * these errors can only occur in UPB_DEBUG_REFS mode, we use an allocator that + * immediately aborts on failure (avoiding the global allocator, which might + * inject failures). */ + +#include + +static void *upb_debugrefs_allocfunc(upb_alloc *alloc, void *ptr, + size_t oldsize, size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; + } else { + void *ret = realloc(ptr, size); + + if (!ret) { + abort(); + } + + return ret; + } +} + +upb_alloc upb_alloc_debugrefs = {&upb_debugrefs_allocfunc}; typedef struct { int count; /* How many refs there are (duplicates only allowed for ref2). */ @@ -3026,8 +2929,7 @@ typedef struct { } trackedref; static trackedref *trackedref_new(bool is_ref2) { - trackedref *ret = malloc(sizeof(*ret)); - CHECK_OOM(ret); + trackedref *ret = upb_malloc(&upb_alloc_debugrefs, sizeof(*ret)); ret->count = 1; ret->is_ref2 = is_ref2; return ret; @@ -3052,15 +2954,15 @@ static void track(const upb_refcounted *r, const void *owner, bool ref2) { ref->count++; } else { trackedref *ref = trackedref_new(ref2); - bool ok = upb_inttable_insertptr(r->refs, owner, upb_value_ptr(ref)); - CHECK_OOM(ok); + upb_inttable_insertptr2(r->refs, owner, upb_value_ptr(ref), + &upb_alloc_debugrefs); if (ref2) { /* We know this cast is safe when it is a ref2, because it's coming from * another refcounted object. */ const upb_refcounted *from = owner; assert(!upb_inttable_lookupptr(from->ref2s, r, NULL)); - ok = upb_inttable_insertptr(from->ref2s, r, upb_value_ptr(NULL)); - CHECK_OOM(ok); + upb_inttable_insertptr2(from->ref2s, r, upb_value_ptr(NULL), + &upb_alloc_debugrefs); } } upb_unlock(); @@ -3118,7 +3020,6 @@ static void getref2s(const upb_refcounted *owner, upb_inttable *tab) { upb_value v; upb_value count; trackedref *ref; - bool ok; bool found; upb_refcounted *to = (upb_refcounted*)upb_inttable_iter_key(&i); @@ -3129,8 +3030,7 @@ static void getref2s(const upb_refcounted *owner, upb_inttable *tab) { ref = upb_value_getptr(v); count = upb_value_int32(ref->count); - ok = upb_inttable_insertptr(tab, to, count); - CHECK_OOM(ok); + upb_inttable_insertptr2(tab, to, count, &upb_alloc_debugrefs); } upb_unlock(); } @@ -3156,21 +3056,19 @@ static void visit_check(const upb_refcounted *obj, const upb_refcounted *subobj, assert(removed); newcount = upb_value_getint32(v) - 1; if (newcount > 0) { - upb_inttable_insert(ref2, (uintptr_t)subobj, upb_value_int32(newcount)); + upb_inttable_insert2(ref2, (uintptr_t)subobj, upb_value_int32(newcount), + &upb_alloc_debugrefs); } } static void visit(const upb_refcounted *r, upb_refcounted_visit *v, void *closure) { - bool ok; - /* In DEBUG_REFS mode we know what existing ref2 refs there are, so we know * exactly the set of nodes that visit() should visit. So we verify visit()'s * correctness here. */ check_state state; state.obj = r; - ok = upb_inttable_init(&state.ref2, UPB_CTYPE_INT32); - CHECK_OOM(ok); + upb_inttable_init2(&state.ref2, UPB_CTYPE_INT32, &upb_alloc_debugrefs); getref2s(r, &state.ref2); /* This should visit any children in the ref2 table. */ @@ -3178,32 +3076,22 @@ static void visit(const upb_refcounted *r, upb_refcounted_visit *v, /* This assertion will fail if the visit() function missed any children. */ assert(upb_inttable_count(&state.ref2) == 0); - upb_inttable_uninit(&state.ref2); + upb_inttable_uninit2(&state.ref2, &upb_alloc_debugrefs); if (r->vtbl->visit) r->vtbl->visit(r, v, closure); } -static bool trackinit(upb_refcounted *r) { - r->refs = malloc(sizeof(*r->refs)); - r->ref2s = malloc(sizeof(*r->ref2s)); - if (!r->refs || !r->ref2s) goto err1; - - if (!upb_inttable_init(r->refs, UPB_CTYPE_PTR)) goto err1; - if (!upb_inttable_init(r->ref2s, UPB_CTYPE_PTR)) goto err2; - return true; - -err2: - upb_inttable_uninit(r->refs); -err1: - free(r->refs); - free(r->ref2s); - return false; +static void trackinit(upb_refcounted *r) { + r->refs = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->refs)); + r->ref2s = upb_malloc(&upb_alloc_debugrefs, sizeof(*r->ref2s)); + upb_inttable_init2(r->refs, UPB_CTYPE_PTR, &upb_alloc_debugrefs); + upb_inttable_init2(r->ref2s, UPB_CTYPE_PTR, &upb_alloc_debugrefs); } static void trackfree(const upb_refcounted *r) { - upb_inttable_uninit(r->refs); - upb_inttable_uninit(r->ref2s); - free(r->refs); - free(r->ref2s); + upb_inttable_uninit2(r->refs, &upb_alloc_debugrefs); + upb_inttable_uninit2(r->ref2s, &upb_alloc_debugrefs); + upb_free(&upb_alloc_debugrefs, r->refs); + upb_free(&upb_alloc_debugrefs, r->ref2s); } #else @@ -3226,9 +3114,8 @@ static void checkref(const upb_refcounted *r, const void *owner, bool ref2) { UPB_UNUSED(ref2); } -static bool trackinit(upb_refcounted *r) { +static void trackinit(upb_refcounted *r) { UPB_UNUSED(r); - return true; } static void trackfree(const upb_refcounted *r) { @@ -3338,12 +3225,12 @@ static upb_refcounted *pop(tarjan *t) { } static void tarjan_newgroup(tarjan *t) { - uint32_t *group = malloc(sizeof(*group)); + uint32_t *group = upb_gmalloc(sizeof(*group)); if (!group) oom(t); /* Push group and empty group leader (we'll fill in leader later). */ if (!upb_inttable_push(&t->groups, upb_value_ptr(group)) || !upb_inttable_push(&t->groups, upb_value_ptr(NULL))) { - free(group); + upb_gfree(group); oom(t); } *group = 0; @@ -3518,7 +3405,7 @@ static bool freeze(upb_refcounted *const*roots, int n, upb_status *s, if (obj == move) { /* Removing the last object from a group. */ assert(*obj->group == obj->individual_count); - free(obj->group); + upb_gfree(obj->group); } else { obj->next = move->next; /* This may decrease to zero; we'll collect GRAY objects (if any) that @@ -3574,7 +3461,7 @@ static bool freeze(upb_refcounted *const*roots, int n, upb_status *s, /* We eagerly free() the group's count (since we can't easily determine * the group's remaining size it's the easiest way to ensure it gets * done). */ - free(obj->group); + upb_gfree(obj->group); /* Visit to release ref2's (done in a separate pass since release_ref2 * depends on o->group being unmodified so it can test merged()). */ @@ -3594,7 +3481,7 @@ err4: if (!ret) { upb_inttable_begin(&iter, &t.groups); for(; !upb_inttable_done(&iter); upb_inttable_next(&iter)) - free(upb_value_getptr(upb_inttable_iter_value(&iter))); + upb_gfree(upb_value_getptr(upb_inttable_iter_value(&iter))); } upb_inttable_uninit(&t.groups); err3: @@ -3618,7 +3505,7 @@ static void merge(upb_refcounted *r, upb_refcounted *from) { if (merged(r, from)) return; *r->group += *from->group; - free(from->group); + upb_gfree(from->group); base = from; /* Set all refcount pointers in the "from" chain to the merged refcount. @@ -3652,7 +3539,7 @@ static void unref(const upb_refcounted *r) { if (unrefgroup(r->group)) { const upb_refcounted *o; - free(r->group); + upb_gfree(r->group); /* In two passes, since release_ref2 needs a guarantee that any subobjs * are alive. */ @@ -3696,13 +3583,10 @@ bool upb_refcounted_init(upb_refcounted *r, r->vtbl = vtbl; r->individual_count = 0; r->is_frozen = false; - r->group = malloc(sizeof(*r->group)); + r->group = upb_gmalloc(sizeof(*r->group)); if (!r->group) return false; *r->group = 0; - if (!trackinit(r)) { - free(r->group); - return false; - } + trackinit(r); upb_refcounted_ref(r, owner); return true; } @@ -3771,8 +3655,6 @@ bool upb_refcounted_freeze(upb_refcounted *const*roots, int n, upb_status *s, } -#include - /* Fallback implementation if the shim is not specialized by the JIT. */ #define SHIM_WRITER(type, ctype) \ bool upb_shim_set ## type (void *c, const void *hd, ctype val) { \ @@ -3798,14 +3680,14 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; bool ok; - upb_shim_data *d = malloc(sizeof(*d)); + upb_shim_data *d = upb_gmalloc(sizeof(*d)); if (!d) return false; d->offset = offset; d->hasbit = hasbit; upb_handlerattr_sethandlerdata(&attr, d); upb_handlerattr_setalwaysok(&attr, true); - upb_handlers_addcleanup(h, d, free); + upb_handlers_addcleanup(h, d, upb_gfree); #define TYPE(u, l) \ case UPB_TYPE_##u: \ @@ -3856,7 +3738,6 @@ const upb_shim_data *upb_shim_getdata(const upb_handlers *h, upb_selector_t s, } -#include #include static void upb_symtab_free(upb_refcounted *r) { @@ -3868,13 +3749,17 @@ static void upb_symtab_free(upb_refcounted *r) { upb_def_unref(def, s); } upb_strtable_uninit(&s->symtab); - free(s); + upb_gfree(s); } - upb_symtab *upb_symtab_new(const void *owner) { static const struct upb_refcounted_vtbl vtbl = {NULL, &upb_symtab_free}; - upb_symtab *s = malloc(sizeof(*s)); + + upb_symtab *s = upb_gmalloc(sizeof(*s)); + if (!s) { + return NULL; + } + upb_refcounted_init(upb_symtab_upcast_mutable(s), &vtbl, owner); upb_strtable_init(&s->symtab, UPB_CTYPE_PTR); return s; @@ -4061,6 +3946,10 @@ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, upb_strtable addtab; upb_inttable seen; + if (n == 0 && !freeze_also) { + return true; + } + assert(!upb_symtab_isfrozen(s)); if (!upb_strtable_init(&addtab, UPB_CTYPE_PTR)) { upb_status_seterrmsg(status, "out of memory"); @@ -4209,7 +4098,7 @@ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, add_objs_size++; } - add_defs = malloc(sizeof(void*) * add_objs_size); + add_defs = upb_gmalloc(sizeof(void*) * add_objs_size); if (add_defs == NULL) goto oom_err; upb_strtable_begin(&iter, &addtab); for (add_n = 0; !upb_strtable_done(&iter); upb_strtable_next(&iter)) { @@ -4254,7 +4143,7 @@ static bool symtab_add(upb_symtab *s, upb_def *const*defs, size_t n, success = upb_strtable_insert(&s->symtab, name, upb_value_ptr(def)); UPB_ASSERT_VAR(success, success == true); } - free(add_objs); + upb_gfree(add_defs); return true; oom_err: @@ -4275,7 +4164,7 @@ err: { } } upb_strtable_uninit(&addtab); - free(add_objs); + upb_gfree(add_defs); assert(!upb_ok(status)); return false; } @@ -4292,7 +4181,7 @@ bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status *status) { bool ret; n = upb_filedef_defcount(file); - defs = malloc(sizeof(*defs) * n); + defs = upb_gmalloc(sizeof(*defs) * n); if (defs == NULL) { upb_status_seterrmsg(status, "Out of memory"); @@ -4305,7 +4194,7 @@ bool upb_symtab_addfile(upb_symtab *s, upb_filedef *file, upb_status *status) { ret = symtab_add(s, defs, n, NULL, upb_filedef_upcast_mutable(file), status); - free(defs); + upb_gfree(defs); return ret; } @@ -4347,7 +4236,6 @@ const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) { */ -#include #include #define UPB_MAXARRSIZE 16 /* 64k. */ @@ -4356,6 +4244,17 @@ const upb_def *upb_symtab_iter_def(const upb_symtab_iter *iter) { #define ARRAY_SIZE(x) \ ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) +#ifdef NDEBUG +static void upb_check_alloc(upb_table *t, upb_alloc *a) { + UPB_UNUSED(t); + UPB_UNUSED(a); +} +#else +static void upb_check_alloc(upb_table *t, upb_alloc *a) { + assert(t->alloc == a); +} +#endif + static const double MAX_LOAD = 0.85; /* The minimum utilization of the array part of a mixed hash/array table. This @@ -4373,11 +4272,11 @@ int log2ceil(uint64_t v) { return UPB_MIN(UPB_MAXARRSIZE, ret); } -char *upb_strdup(const char *s) { - return upb_strdup2(s, strlen(s)); +char *upb_strdup(const char *s, upb_alloc *a) { + return upb_strdup2(s, strlen(s), a); } -char *upb_strdup2(const char *s, size_t len) { +char *upb_strdup2(const char *s, size_t len, upb_alloc *a) { size_t n; char *p; @@ -4386,7 +4285,7 @@ char *upb_strdup2(const char *s, size_t len) { /* Always null-terminate, even if binary data; but don't rely on the input to * have a null-terminating byte since it may be a raw binary buffer. */ n = len + 1; - p = malloc(n); + p = upb_malloc(a, n); if (p) { memcpy(p, s, len); p[len] = 0; @@ -4434,16 +4333,20 @@ static bool isfull(upb_table *t) { } } -static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2) { +static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2, + upb_alloc *a) { size_t bytes; t->count = 0; t->ctype = ctype; t->size_lg2 = size_lg2; t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0; +#ifndef NDEBUG + t->alloc = a; +#endif bytes = upb_table_size(t) * sizeof(upb_tabent); if (bytes > 0) { - t->entries = malloc(bytes); + t->entries = upb_malloc(a, bytes); if (!t->entries) return false; memset(mutable_entries(t), 0, bytes); } else { @@ -4452,7 +4355,10 @@ static bool init(upb_table *t, upb_ctype_t ctype, uint8_t size_lg2) { return true; } -static void uninit(upb_table *t) { free(mutable_entries(t)); } +static void uninit(upb_table *t, upb_alloc *a) { + upb_check_alloc(t, a); + upb_free(a, mutable_entries(t)); +} static upb_tabent *emptyent(upb_table *t) { upb_tabent *e = mutable_entries(t) + upb_table_size(t); @@ -4605,8 +4511,8 @@ static size_t begin(const upb_table *t) { /* A simple "subclass" of upb_table that only adds a hash function for strings. */ -static upb_tabkey strcopy(lookupkey_t k2) { - char *str = malloc(k2.str.len + sizeof(uint32_t) + 1); +static upb_tabkey strcopy(lookupkey_t k2, upb_alloc *a) { + char *str = upb_malloc(a, k2.str.len + sizeof(uint32_t) + 1); if (str == NULL) return 0; memcpy(str, &k2.str.len, sizeof(uint32_t)); memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len + 1); @@ -4625,51 +4531,56 @@ static bool streql(upb_tabkey k1, lookupkey_t k2) { return len == k2.str.len && memcmp(str, k2.str.str, len) == 0; } -bool upb_strtable_init(upb_strtable *t, upb_ctype_t ctype) { - return init(&t->t, ctype, 2); +bool upb_strtable_init2(upb_strtable *t, upb_ctype_t ctype, upb_alloc *a) { + return init(&t->t, ctype, 2, a); } -void upb_strtable_uninit(upb_strtable *t) { +void upb_strtable_uninit2(upb_strtable *t, upb_alloc *a) { size_t i; for (i = 0; i < upb_table_size(&t->t); i++) - free((void*)t->t.entries[i].key); - uninit(&t->t); + upb_free(a, (void*)t->t.entries[i].key); + uninit(&t->t, a); } -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2) { +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a) { upb_strtable new_table; upb_strtable_iter i; - if (!init(&new_table.t, t->t.ctype, size_lg2)) + upb_check_alloc(&t->t, a); + + if (!init(&new_table.t, t->t.ctype, size_lg2, a)) return false; upb_strtable_begin(&i, t); for ( ; !upb_strtable_done(&i); upb_strtable_next(&i)) { - upb_strtable_insert2( + upb_strtable_insert3( &new_table, upb_strtable_iter_key(&i), upb_strtable_iter_keylength(&i), - upb_strtable_iter_value(&i)); + upb_strtable_iter_value(&i), + a); } - upb_strtable_uninit(t); + upb_strtable_uninit2(t, a); *t = new_table; return true; } -bool upb_strtable_insert2(upb_strtable *t, const char *k, size_t len, - upb_value v) { +bool upb_strtable_insert3(upb_strtable *t, const char *k, size_t len, + upb_value v, upb_alloc *a) { lookupkey_t key; upb_tabkey tabkey; uint32_t hash; + upb_check_alloc(&t->t, a); + if (isfull(&t->t)) { /* Need to resize. New table of double the size, add old elements to it. */ - if (!upb_strtable_resize(t, t->t.size_lg2 + 1)) { + if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) { return false; } } key = strkey2(k, len); - tabkey = strcopy(key); + tabkey = strcopy(key, a); if (tabkey == 0) return false; hash = MurmurHash2(key.str.str, key.str.len, 0); @@ -4683,12 +4594,12 @@ bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, return lookup(&t->t, strkey2(key, len), v, hash, &streql); } -bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len, - upb_value *val) { +bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, + upb_value *val, upb_alloc *alloc) { uint32_t hash = MurmurHash2(key, strlen(key), 0); upb_tabkey tabkey; if (rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql)) { - free((void*)tabkey); + upb_free(alloc, (void*)tabkey); return true; } else { return false; @@ -4715,12 +4626,12 @@ bool upb_strtable_done(const upb_strtable_iter *i) { upb_tabent_isempty(str_tabent(i)); } -const char *upb_strtable_iter_key(upb_strtable_iter *i) { +const char *upb_strtable_iter_key(const upb_strtable_iter *i) { assert(!upb_strtable_done(i)); return upb_tabstr(str_tabent(i)->key, NULL); } -size_t upb_strtable_iter_keylength(upb_strtable_iter *i) { +size_t upb_strtable_iter_keylength(const upb_strtable_iter *i) { uint32_t len; assert(!upb_strtable_done(i)); upb_tabstr(str_tabent(i)->key, &len); @@ -4795,18 +4706,18 @@ static void check(upb_inttable *t) { } bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype, - size_t asize, int hsize_lg2) { + size_t asize, int hsize_lg2, upb_alloc *a) { size_t array_bytes; - if (!init(&t->t, ctype, hsize_lg2)) return false; + if (!init(&t->t, ctype, hsize_lg2, a)) return false; /* Always make the array part at least 1 long, so that we know key 0 * won't be in the hash part, which simplifies things. */ t->array_size = UPB_MAX(1, asize); t->array_count = 0; array_bytes = t->array_size * sizeof(upb_value); - t->array = malloc(array_bytes); + t->array = upb_malloc(a, array_bytes); if (!t->array) { - uninit(&t->t); + uninit(&t->t, a); return false; } memset(mutable_array(t), 0xff, array_bytes); @@ -4814,22 +4725,23 @@ bool upb_inttable_sizedinit(upb_inttable *t, upb_ctype_t ctype, return true; } -bool upb_inttable_init(upb_inttable *t, upb_ctype_t ctype) { - return upb_inttable_sizedinit(t, ctype, 0, 4); +bool upb_inttable_init2(upb_inttable *t, upb_ctype_t ctype, upb_alloc *a) { + return upb_inttable_sizedinit(t, ctype, 0, 4, a); } -void upb_inttable_uninit(upb_inttable *t) { - uninit(&t->t); - free(mutable_array(t)); +void upb_inttable_uninit2(upb_inttable *t, upb_alloc *a) { + uninit(&t->t, a); + upb_free(a, mutable_array(t)); } -bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { - /* XXX: Table can't store value (uint64_t)-1. Need to somehow statically - * guarantee that this is not necessary, or fix the limitation. */ +bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, + upb_alloc *a) { upb_tabval tabval; tabval.val = val.val; UPB_UNUSED(tabval); - assert(upb_arrhas(tabval)); + assert(upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */ + + upb_check_alloc(&t->t, a); if (key < t->array_size) { assert(!upb_arrhas(t->array[key])); @@ -4840,8 +4752,11 @@ bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { /* Need to resize the hash part, but we re-use the array part. */ size_t i; upb_table new_table; - if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1)) + + if (!init(&new_table, t->t.ctype, t->t.size_lg2 + 1, a)) { return false; + } + for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { const upb_tabent *e = &t->t.entries[i]; uint32_t hash; @@ -4854,7 +4769,7 @@ bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val) { assert(t->t.count == new_table.count); - uninit(&t->t); + uninit(&t->t, a); t->t = new_table; } insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql); @@ -4900,8 +4815,9 @@ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val) { return success; } -bool upb_inttable_push(upb_inttable *t, upb_value val) { - return upb_inttable_insert(t, upb_inttable_count(t), val); +bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a) { + upb_check_alloc(&t->t, a); + return upb_inttable_insert2(t, upb_inttable_count(t), val, a); } upb_value upb_inttable_pop(upb_inttable *t) { @@ -4911,8 +4827,10 @@ upb_value upb_inttable_pop(upb_inttable *t) { return val; } -bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val) { - return upb_inttable_insert(t, (uintptr_t)key, val); +bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, + upb_alloc *a) { + upb_check_alloc(&t->t, a); + return upb_inttable_insert2(t, (uintptr_t)key, val, a); } bool upb_inttable_lookupptr(const upb_inttable *t, const void *key, @@ -4924,7 +4842,7 @@ bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val) { return upb_inttable_remove(t, (uintptr_t)key, val); } -void upb_inttable_compact(upb_inttable *t) { +void upb_inttable_compact2(upb_inttable *t, upb_alloc *a) { /* A power-of-two histogram of the table keys. */ size_t counts[UPB_MAXARRSIZE + 1] = {0}; @@ -4936,6 +4854,8 @@ void upb_inttable_compact(upb_inttable *t) { int size_lg2; upb_inttable new_t; + upb_check_alloc(&t->t, a); + upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t key = upb_inttable_iter_key(&i); @@ -4968,16 +4888,16 @@ void upb_inttable_compact(upb_inttable *t) { size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0; size_t hashsize_lg2 = log2ceil(hash_size); - upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2); + upb_inttable_sizedinit(&new_t, t->t.ctype, arr_size, hashsize_lg2, a); upb_inttable_begin(&i, t); for (; !upb_inttable_done(&i); upb_inttable_next(&i)) { uintptr_t k = upb_inttable_iter_key(&i); - upb_inttable_insert(&new_t, k, upb_inttable_iter_value(&i)); + upb_inttable_insert2(&new_t, k, upb_inttable_iter_value(&i), a); } assert(new_t.array_size == arr_size); assert(new_t.t.size_lg2 == hashsize_lg2); } - upb_inttable_uninit(t); + upb_inttable_uninit2(t, a); *t = new_t; } @@ -5253,6 +5173,19 @@ static void nullz(upb_status *status) { memcpy(status->msg + sizeof(status->msg) - len, ellipsis, len); } + +/* upb_upberr *****************************************************************/ + +upb_errorspace upb_upberr = {"upb error"}; + +void upb_upberr_setoom(upb_status *status) { + status->error_space_ = &upb_upberr; + upb_status_seterrmsg(status, "Out of memory"); +} + + +/* upb_status *****************************************************************/ + void upb_status_clear(upb_status *status) { if (!status) return; status->ok_ = true; @@ -5291,20 +5224,258 @@ void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args) { nullz(status); } -void upb_status_seterrcode(upb_status *status, upb_errorspace *space, - int code) { - if (!status) return; - status->ok_ = false; - status->error_space_ = space; - status->code_ = code; - space->set_message(status, code); -} - void upb_status_copy(upb_status *to, const upb_status *from) { if (!to) return; *to = *from; } -/* This file was generated by upbc (the upb compiler). + + +/* upb_alloc ******************************************************************/ + +static void *upb_global_allocfunc(upb_alloc *alloc, void *ptr, size_t oldsize, + size_t size) { + UPB_UNUSED(alloc); + UPB_UNUSED(oldsize); + if (size == 0) { + free(ptr); + return NULL; + } else { + return realloc(ptr, size); + } +} + +upb_alloc upb_alloc_global = {&upb_global_allocfunc}; + + +/* upb_arena ******************************************************************/ + +/* Be conservative and choose 16 in case anyone is using SSE. */ +static const size_t maxalign = 16; + +static size_t align_up(size_t size) { + return ((size + maxalign - 1) / maxalign) * maxalign; +} + +typedef struct mem_block { + struct mem_block *next; + size_t size; + size_t used; + bool owned; + /* Data follows. */ +} mem_block; + +typedef struct cleanup_ent { + struct cleanup_ent *next; + upb_cleanup_func *cleanup; + void *ud; +} cleanup_ent; + +static void upb_arena_addblock(upb_arena *a, void *ptr, size_t size, + bool owned) { + mem_block *block = ptr; + + block->next = a->block_head; + block->size = size; + block->used = align_up(sizeof(mem_block)); + block->owned = owned; + + a->block_head = block; + + /* TODO(haberman): ASAN poison. */ +} + + +static mem_block *upb_arena_allocblock(upb_arena *a, size_t size) { + size_t block_size = UPB_MAX(size, a->next_block_size) + sizeof(mem_block); + mem_block *block = upb_malloc(a->block_alloc, block_size); + + if (!block) { + return NULL; + } + + upb_arena_addblock(a, block, block_size, true); + a->next_block_size = UPB_MIN(block_size * 2, a->max_block_size); + + return block; +} + +static void *upb_arena_doalloc(upb_alloc *alloc, void *ptr, size_t oldsize, + size_t size) { + upb_arena *a = (upb_arena*)alloc; /* upb_alloc is initial member. */ + mem_block *block = a->block_head; + void *ret; + + if (size == 0) { + return NULL; /* We are an arena, don't need individual frees. */ + } + + size = align_up(size); + + /* TODO(haberman): special-case if this is a realloc of the last alloc? */ + + if (!block || block->size - block->used < size) { + /* Slow path: have to allocate a new block. */ + block = upb_arena_allocblock(a, size); + + if (!block) { + return NULL; /* Out of memory. */ + } + } + + ret = (char*)block + block->used; + block->used += size; + + if (oldsize > 0) { + memcpy(ret, ptr, oldsize); /* Preserve existing data. */ + } + + /* TODO(haberman): ASAN unpoison. */ + + a->bytes_allocated += size; + return ret; +} + +/* Public Arena API ***********************************************************/ + +void upb_arena_init(upb_arena *a) { + a->alloc.func = &upb_arena_doalloc; + a->block_alloc = &upb_alloc_global; + a->bytes_allocated = 0; + a->next_block_size = 256; + a->max_block_size = 16384; + a->cleanup_head = NULL; + a->block_head = NULL; +} + +void upb_arena_init2(upb_arena *a, void *mem, size_t size, upb_alloc *alloc) { + upb_arena_init(a); + + if (size > sizeof(mem_block)) { + upb_arena_addblock(a, mem, size, false); + } + + if (alloc) { + a->block_alloc = alloc; + } +} + +void upb_arena_uninit(upb_arena *a) { + cleanup_ent *ent = a->cleanup_head; + mem_block *block = a->block_head; + + while (ent) { + ent->cleanup(ent->ud); + ent = ent->next; + } + + /* Must do this after running cleanup functions, because this will delete + * the memory we store our cleanup entries in! */ + while (block) { + mem_block *next = block->next; + + if (block->owned) { + upb_free(a->block_alloc, block); + } + + block = next; + } +} + +bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud) { + cleanup_ent *ent = upb_malloc(&a->alloc, sizeof(cleanup_ent)); + if (!ent) { + return false; /* Out of memory. */ + } + + ent->cleanup = func; + ent->ud = ud; + ent->next = a->cleanup_head; + a->cleanup_head = ent; + + return true; +} + +size_t upb_arena_bytesallocated(const upb_arena *a) { + return a->bytes_allocated; +} + + +/* Standard error functions ***************************************************/ + +static bool default_err(void *ud, const upb_status *status) { + UPB_UNUSED(ud); + UPB_UNUSED(status); + return false; +} + +static bool write_err_to(void *ud, const upb_status *status) { + upb_status *copy_to = ud; + upb_status_copy(copy_to, status); + return false; +} + + +/* upb_env ********************************************************************/ + +void upb_env_initonly(upb_env *e) { + e->ok_ = true; + e->error_func_ = &default_err; + e->error_ud_ = NULL; +} + +void upb_env_init(upb_env *e) { + upb_arena_init(&e->arena_); + upb_env_initonly(e); +} + +void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc) { + upb_arena_init2(&e->arena_, mem, n, alloc); + upb_env_initonly(e); +} + +void upb_env_uninit(upb_env *e) { + upb_arena_uninit(&e->arena_); +} + +void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud) { + e->error_func_ = func; + e->error_ud_ = ud; +} + +void upb_env_reporterrorsto(upb_env *e, upb_status *s) { + e->error_func_ = &write_err_to; + e->error_ud_ = s; +} + +bool upb_env_reporterror(upb_env *e, const upb_status *status) { + e->ok_ = false; + return e->error_func_(e->error_ud_, status); +} + +void *upb_env_malloc(upb_env *e, size_t size) { + return upb_malloc(&e->arena_.alloc, size); +} + +void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size) { + return upb_realloc(&e->arena_.alloc, ptr, oldsize, size); +} + +void upb_env_free(upb_env *e, void *ptr) { + upb_free(&e->arena_.alloc, ptr); +} + +bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud) { + return upb_arena_addcleanup(&e->arena_, func, ud); +} + +size_t upb_env_bytesallocated(const upb_env *e) { + return upb_arena_bytesallocated(&e->arena_); +} +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * upb/descriptor/descriptor.proto + * * Do not edit -- your changes will be discarded when the file is * regenerated. */ @@ -5323,28 +5494,28 @@ static upb_inttable reftables[264]; #endif static const upb_msgdef msgs[22] = { - UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 40, 8, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[0]),&reftables[0], &reftables[1]), - UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]),&reftables[2], &reftables[3]), - UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ReservedRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[14], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[20]),&reftables[4], &reftables[5]), - UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[17], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[24]),&reftables[6], &reftables[7]), - UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[21], 4, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]),&reftables[8], &reftables[9]), - UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[25], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[32]),&reftables[10], &reftables[11]), - UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 7, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[29], 2, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[36]),&reftables[12], &reftables[13]), - UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 23, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[40]),&reftables[14], &reftables[15]), - UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 12, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[42], 11, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[56]),&reftables[16], &reftables[17]), - UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 42, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[53], 13, 12), UPB_STRTABLE_INIT(12, 15, UPB_CTYPE_PTR, 4, &strentries[72]),&reftables[18], &reftables[19]), - UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[66], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[88]),&reftables[20], &reftables[21]), - UPB_MSGDEF_INIT("google.protobuf.FileOptions", 31, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[68], 39, 15), UPB_STRTABLE_INIT(16, 31, UPB_CTYPE_PTR, 5, &strentries[92]),&reftables[22], &reftables[23]), - UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 10, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[107], 8, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[124]),&reftables[24], &reftables[25]), - UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 15, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[115], 7, 6), UPB_STRTABLE_INIT(6, 7, UPB_CTYPE_PTR, 3, &strentries[132]),&reftables[26], &reftables[27]), - UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[10], &arrays[122], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[140]),&reftables[28], &reftables[29]), - UPB_MSGDEF_INIT("google.protobuf.OneofDescriptorProto", 5, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[123], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[144]),&reftables[30], &reftables[31]), - UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[125], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[148]),&reftables[32], &reftables[33]), - UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[14], &arrays[129], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[152]),&reftables[34], &reftables[35]), - UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[130], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[156]),&reftables[36], &reftables[37]), - UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 19, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[132], 7, 5), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[160]),&reftables[38], &reftables[39]), - UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[139], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[168]),&reftables[40], &reftables[41]), - UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[148], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[184]),&reftables[42], &reftables[43]), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto", 40, 8, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[0], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[0]), false, UPB_SYNTAX_PROTO2, &reftables[0], &reftables[1]), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ExtensionRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[11], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[16]), false, UPB_SYNTAX_PROTO2, &reftables[2], &reftables[3]), + UPB_MSGDEF_INIT("google.protobuf.DescriptorProto.ReservedRange", 4, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[14], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[20]), false, UPB_SYNTAX_PROTO2, &reftables[4], &reftables[5]), + UPB_MSGDEF_INIT("google.protobuf.EnumDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[17], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[24]), false, UPB_SYNTAX_PROTO2, &reftables[6], &reftables[7]), + UPB_MSGDEF_INIT("google.protobuf.EnumOptions", 8, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[0], &arrays[21], 4, 2), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[28]), false, UPB_SYNTAX_PROTO2, &reftables[8], &reftables[9]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueDescriptorProto", 8, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[25], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[32]), false, UPB_SYNTAX_PROTO2, &reftables[10], &reftables[11]), + UPB_MSGDEF_INIT("google.protobuf.EnumValueOptions", 7, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[2], &arrays[29], 2, 1), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[36]), false, UPB_SYNTAX_PROTO2, &reftables[12], &reftables[13]), + UPB_MSGDEF_INIT("google.protobuf.FieldDescriptorProto", 23, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[31], 11, 10), UPB_STRTABLE_INIT(10, 15, UPB_CTYPE_PTR, 4, &strentries[40]), false, UPB_SYNTAX_PROTO2, &reftables[14], &reftables[15]), + UPB_MSGDEF_INIT("google.protobuf.FieldOptions", 12, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[4], &arrays[42], 11, 6), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[56]), false, UPB_SYNTAX_PROTO2, &reftables[16], &reftables[17]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorProto", 42, 6, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[53], 13, 12), UPB_STRTABLE_INIT(12, 15, UPB_CTYPE_PTR, 4, &strentries[72]), false, UPB_SYNTAX_PROTO2, &reftables[18], &reftables[19]), + UPB_MSGDEF_INIT("google.protobuf.FileDescriptorSet", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[66], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[88]), false, UPB_SYNTAX_PROTO2, &reftables[20], &reftables[21]), + UPB_MSGDEF_INIT("google.protobuf.FileOptions", 31, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[6], &arrays[68], 39, 15), UPB_STRTABLE_INIT(16, 31, UPB_CTYPE_PTR, 5, &strentries[92]), false, UPB_SYNTAX_PROTO2, &reftables[22], &reftables[23]), + UPB_MSGDEF_INIT("google.protobuf.MessageOptions", 10, 1, UPB_INTTABLE_INIT(1, 1, UPB_CTYPE_PTR, 1, &intentries[8], &arrays[107], 8, 4), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[124]), false, UPB_SYNTAX_PROTO2, &reftables[24], &reftables[25]), + UPB_MSGDEF_INIT("google.protobuf.MethodDescriptorProto", 15, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[115], 7, 6), UPB_STRTABLE_INIT(6, 7, UPB_CTYPE_PTR, 3, &strentries[132]), false, UPB_SYNTAX_PROTO2, &reftables[26], &reftables[27]), + UPB_MSGDEF_INIT("google.protobuf.MethodOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[10], &arrays[122], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[140]), false, UPB_SYNTAX_PROTO2, &reftables[28], &reftables[29]), + UPB_MSGDEF_INIT("google.protobuf.OneofDescriptorProto", 5, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[123], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[144]), false, UPB_SYNTAX_PROTO2, &reftables[30], &reftables[31]), + UPB_MSGDEF_INIT("google.protobuf.ServiceDescriptorProto", 11, 2, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[125], 4, 3), UPB_STRTABLE_INIT(3, 3, UPB_CTYPE_PTR, 2, &strentries[148]), false, UPB_SYNTAX_PROTO2, &reftables[32], &reftables[33]), + UPB_MSGDEF_INIT("google.protobuf.ServiceOptions", 7, 1, UPB_INTTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &intentries[14], &arrays[129], 1, 0), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[152]), false, UPB_SYNTAX_PROTO2, &reftables[34], &reftables[35]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo", 6, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[130], 2, 1), UPB_STRTABLE_INIT(1, 3, UPB_CTYPE_PTR, 2, &strentries[156]), false, UPB_SYNTAX_PROTO2, &reftables[36], &reftables[37]), + UPB_MSGDEF_INIT("google.protobuf.SourceCodeInfo.Location", 19, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[132], 7, 5), UPB_STRTABLE_INIT(5, 7, UPB_CTYPE_PTR, 3, &strentries[160]), false, UPB_SYNTAX_PROTO2, &reftables[38], &reftables[39]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption", 18, 1, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[139], 9, 7), UPB_STRTABLE_INIT(7, 15, UPB_CTYPE_PTR, 4, &strentries[168]), false, UPB_SYNTAX_PROTO2, &reftables[40], &reftables[41]), + UPB_MSGDEF_INIT("google.protobuf.UninterpretedOption.NamePart", 6, 0, UPB_INTTABLE_INIT(0, 0, UPB_CTYPE_PTR, 0, NULL, &arrays[148], 3, 2), UPB_STRTABLE_INIT(2, 3, UPB_CTYPE_PTR, 2, &strentries[184]), false, UPB_SYNTAX_PROTO2, &reftables[42], &reftables[43]), }; static const upb_fielddef fields[105] = { @@ -6277,7 +6448,7 @@ struct upb_descreader { }; static char *upb_strndup(const char *buf, size_t n) { - char *ret = malloc(n + 1); + char *ret = upb_gmalloc(n + 1); if (!ret) return NULL; memcpy(ret, buf, n); ret[n] = '\0'; @@ -6291,9 +6462,12 @@ static char *upb_strndup(const char *buf, size_t n) { * Caller owns a ref on the returned string. */ static char *upb_join(const char *base, const char *name) { if (!base || strlen(base) == 0) { - return upb_strdup(name); + return upb_gstrdup(name); } else { - char *ret = malloc(strlen(base) + strlen(name) + 2); + char *ret = upb_gmalloc(strlen(base) + strlen(name) + 2); + if (!ret) { + return NULL; + } ret[0] = '\0'; strcat(ret, base); strcat(ret, "."); @@ -6303,14 +6477,20 @@ static char *upb_join(const char *base, const char *name) { } /* Qualify the defname for all defs starting with offset "start" with "str". */ -static void upb_descreader_qualify(upb_filedef *f, char *str, int32_t start) { +static bool upb_descreader_qualify(upb_filedef *f, char *str, int32_t start) { size_t i; for (i = start; i < upb_filedef_defcount(f); i++) { upb_def *def = upb_filedef_mutabledef(f, i); char *name = upb_join(str, upb_def_fullname(def)); + if (!name) { + /* Need better logic here; at this point we've qualified some names but + * not others. */ + return false; + } upb_def_setfullname(def, name, NULL); - free(name); + upb_gfree(name); } + return true; } @@ -6336,16 +6516,19 @@ void upb_descreader_startcontainer(upb_descreader *r) { f->name = NULL; } -void upb_descreader_endcontainer(upb_descreader *r) { +bool upb_descreader_endcontainer(upb_descreader *r) { upb_descreader_frame *f = &r->stack[--r->stack_len]; - upb_descreader_qualify(r->file, f->name, f->start); - free(f->name); + if (!upb_descreader_qualify(r->file, f->name, f->start)) { + return false; + } + upb_gfree(f->name); f->name = NULL; + return true; } void upb_descreader_setscopename(upb_descreader *r, char *str) { upb_descreader_frame *f = &r->stack[r->stack_len-1]; - free(f->name); + upb_gfree(f->name); f->name = str; } @@ -6372,8 +6555,7 @@ static bool file_end(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(status); - upb_descreader_endcontainer(r); - return true; + return upb_descreader_endcontainer(r); } static size_t file_onname(void *closure, const void *hd, const char *buf, @@ -6387,6 +6569,7 @@ static size_t file_onname(void *closure, const void *hd, const char *buf, name = upb_strndup(buf, n); /* XXX: see comment at the top of the file. */ ok = upb_filedef_setname(r->file, name, NULL); + upb_gfree(name); UPB_ASSERT_VAR(ok, ok); return n; } @@ -6470,7 +6653,7 @@ static size_t enumval_onname(void *closure, const void *hd, const char *buf, UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ - free(r->name); + upb_gfree(r->name); r->name = upb_strndup(buf, n); r->saw_name = true; return n; @@ -6495,7 +6678,7 @@ static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) { } e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); upb_enumdef_addval(e, r->name, r->number, status); - free(r->name); + upb_gfree(r->name); r->name = NULL; return true; } @@ -6527,7 +6710,7 @@ static size_t enum_onname(void *closure, const void *hd, const char *buf, UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_def_setfullname(upb_descreader_last(r), fullname, NULL); - free(fullname); + upb_gfree(fullname); return n; } @@ -6537,7 +6720,7 @@ static bool field_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); assert(r->f); - free(r->default_string); + upb_gfree(r->default_string); r->default_string = NULL; /* fielddefs default to packed, but descriptors default to non-packed. */ @@ -6696,7 +6879,7 @@ static size_t field_onname(void *closure, const void *hd, const char *buf, /* XXX: see comment at the top of the file. */ upb_fielddef_setname(r->f, name, NULL); - free(name); + upb_gfree(name); return n; } @@ -6709,7 +6892,7 @@ static size_t field_ontypename(void *closure, const void *hd, const char *buf, /* XXX: see comment at the top of the file. */ upb_fielddef_setsubdefname(r->f, name, NULL); - free(name); + upb_gfree(name); return n; } @@ -6722,7 +6905,7 @@ static size_t field_onextendee(void *closure, const void *hd, const char *buf, /* XXX: see comment at the top of the file. */ upb_fielddef_setcontainingtypename(r->f, name, NULL); - free(name); + upb_gfree(name); return n; } @@ -6735,7 +6918,7 @@ static size_t field_ondefaultval(void *closure, const void *hd, const char *buf, /* Have to convert from string to the correct type, but we might not know the * type yet, so we save it as a string until the end of the field. * XXX: see comment at the top of the file. */ - free(r->default_string); + upb_gfree(r->default_string); r->default_string = upb_strndup(buf, n); return n; } @@ -6759,8 +6942,7 @@ static bool msg_end(void *closure, const void *hd, upb_status *status) { upb_status_seterrmsg(status, "Encountered message with no name."); return false; } - upb_descreader_endcontainer(r); - return true; + return upb_descreader_endcontainer(r); } static size_t msg_name(void *closure, const void *hd, const char *buf, @@ -6814,6 +6996,17 @@ static bool msg_endfield(void *closure, const void *hd) { return true; } +static bool msg_onmapentry(void *closure, const void *hd, bool mapentry) { + upb_descreader *r = closure; + upb_msgdef *m = upb_descreader_top(r); + UPB_UNUSED(hd); + + upb_msgdef_setmapentry(m, mapentry); + r->f = NULL; + return true; +} + + /** Code to register handlers *************************************************/ @@ -6884,6 +7077,8 @@ static void reghandlers(const void *closure, upb_handlers *h) { } else if (upbdefs_google_protobuf_FieldOptions_is(m)) { upb_handlers_setbool(h, F(FieldOptions, lazy), &field_onlazy, NULL); upb_handlers_setbool(h, F(FieldOptions, packed), &field_onpacked, NULL); + } else if (upbdefs_google_protobuf_MessageOptions_is(m)) { + upb_handlers_setbool(h, F(MessageOptions, map_entry), &msg_onmapentry, NULL); } assert(upb_ok(upb_handlers_status(h))); @@ -6899,12 +7094,12 @@ void descreader_cleanup(void *_r) { upb_filedef_unref(upb_descreader_file(r, i), &r->files); } - free(r->name); + upb_gfree(r->name); upb_inttable_uninit(&r->files); - free(r->default_string); + upb_gfree(r->default_string); while (r->stack_len > 0) { upb_descreader_frame *f = &r->stack[--r->stack_len]; - free(f->name); + upb_gfree(f->name); } } @@ -6980,8 +7175,8 @@ static void freegroup(upb_refcounted *r) { #ifdef UPB_USE_JIT_X64 upb_pbdecoder_freejit(g); #endif - free(g->bytecode); - free(g); + upb_gfree(g->bytecode); + upb_gfree(g); } static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit, @@ -6996,7 +7191,7 @@ static void visitgroup(const upb_refcounted *r, upb_refcounted_visit *visit, } mgroup *newgroup(const void *owner) { - mgroup *g = malloc(sizeof(*g)); + mgroup *g = upb_gmalloc(sizeof(*g)); static const struct upb_refcounted_vtbl vtbl = {visitgroup, freegroup}; upb_refcounted_init(mgroup_upcast_mutable(g), &vtbl, owner); upb_inttable_init(&g->methods, UPB_CTYPE_PTR); @@ -7016,7 +7211,7 @@ static void freemethod(upb_refcounted *r) { } upb_inttable_uninit(&method->dispatch); - free(method); + upb_gfree(method); } static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit, @@ -7028,7 +7223,7 @@ static void visitmethod(const upb_refcounted *r, upb_refcounted_visit *visit, static upb_pbdecodermethod *newmethod(const upb_handlers *dest_handlers, mgroup *group) { static const struct upb_refcounted_vtbl vtbl = {visitmethod, freemethod}; - upb_pbdecodermethod *ret = malloc(sizeof(*ret)); + upb_pbdecodermethod *ret = upb_gmalloc(sizeof(*ret)); upb_refcounted_init(upb_pbdecodermethod_upcast_mutable(ret), &vtbl, &ret); upb_byteshandler_init(&ret->input_handler_); @@ -7091,7 +7286,7 @@ typedef struct { } compiler; static compiler *newcompiler(mgroup *group, bool lazy) { - compiler *ret = malloc(sizeof(*ret)); + compiler *ret = upb_gmalloc(sizeof(*ret)); int i; ret->group = group; @@ -7104,7 +7299,7 @@ static compiler *newcompiler(mgroup *group, bool lazy) { } static void freecompiler(compiler *c) { - free(c); + upb_gfree(c); } const size_t ptr_words = sizeof(void*) / sizeof(uint32_t); @@ -7208,7 +7403,8 @@ static void put32(compiler *c, uint32_t v) { size_t oldsize = g->bytecode_end - g->bytecode; size_t newsize = UPB_MAX(oldsize * 2, 64); /* TODO(haberman): handle OOM. */ - g->bytecode = realloc(g->bytecode, newsize * sizeof(uint32_t)); + g->bytecode = upb_grealloc(g->bytecode, oldsize * sizeof(uint32_t), + newsize * sizeof(uint32_t)); g->bytecode_end = g->bytecode + newsize; c->pc = g->bytecode + ofs; } @@ -9073,7 +9269,6 @@ bool upb_pbdecoder_setmaxnesting(upb_pbdecoder *d, size_t max) { */ -#include /* The output buffer is divided into segments; a segment is a string of data * that is "ready to go" -- it does not need any varint lengths inserted into @@ -9318,12 +9513,12 @@ static void new_tag(upb_handlers *h, const upb_fielddef *f, upb_wiretype_t wt, upb_handlerattr *attr) { uint32_t n = upb_fielddef_number(f); - tag_t *tag = malloc(sizeof(tag_t)); + tag_t *tag = upb_gmalloc(sizeof(tag_t)); tag->bytes = upb_vencode64((n << 3) | wt, tag->tag); upb_handlerattr_init(attr); upb_handlerattr_sethandlerdata(attr, tag); - upb_handlers_addcleanup(h, tag, free); + upb_handlers_addcleanup(h, tag, upb_gfree); } static bool encode_tag(upb_pb_encoder *e, const tag_t *tag) { @@ -9582,9 +9777,6 @@ upb_pb_encoder *upb_pb_encoder_create(upb_env *env, const upb_handlers *h, upb_sink *upb_pb_encoder_input(upb_pb_encoder *e) { return &e->input_; } -#include -#include -#include upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner, upb_status *status) { @@ -9615,7 +9807,7 @@ upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner, goto cleanup; } - ret = malloc(sizeof (*ret) * (upb_descreader_filecount(reader) + 1)); + ret = upb_gmalloc(sizeof (*ret) * (upb_descreader_filecount(reader) + 1)); if (!ret) { goto cleanup; @@ -9647,7 +9839,6 @@ cleanup: #include #include #include -#include #include @@ -9743,14 +9934,14 @@ bool putf(upb_textprinter *p, const char *fmt, ...) { va_end(args_copy); /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */ - str = malloc(len + 1); + str = upb_gmalloc(len + 1); if (!str) return false; written = vsprintf(str, fmt, args); va_end(args); UPB_ASSERT_VAR(written, written == len); ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL); - free(str); + upb_gfree(str); return ok; } @@ -10119,12 +10310,11 @@ upb_decoderet upb_vdecode_max8_wright(upb_decoderet r) { ** - handling of keys/escape-sequences/etc that span input buffers. */ -#include -#include #include -#include -#include #include +#include +#include +#include #define UPB_JSON_MAX_DEPTH 64 @@ -11247,11 +11437,11 @@ static void end_object(upb_json_parser *p) { * final state once, when the closing '"' is seen. */ -#line 1246 "upb/json/parser.rl" +#line 1245 "upb/json/parser.rl" -#line 1158 "upb/json/parser.c" +#line 1157 "upb/json/parser.c" static const char _json_actions[] = { 0, 1, 0, 1, 2, 1, 3, 1, 5, 1, 6, 1, 7, 1, 8, 1, @@ -11400,7 +11590,7 @@ static const int json_en_value_machine = 27; static const int json_en_main = 1; -#line 1249 "upb/json/parser.rl" +#line 1248 "upb/json/parser.rl" size_t parse(void *closure, const void *hd, const char *buf, size_t size, const upb_bufhandle *handle) { @@ -11422,7 +11612,7 @@ size_t parse(void *closure, const void *hd, const char *buf, size_t size, capture_resume(parser, buf); -#line 1329 "upb/json/parser.c" +#line 1328 "upb/json/parser.c" { int _klen; unsigned int _trans; @@ -11497,118 +11687,118 @@ _match: switch ( *_acts++ ) { case 0: -#line 1161 "upb/json/parser.rl" +#line 1160 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 1: -#line 1162 "upb/json/parser.rl" +#line 1161 "upb/json/parser.rl" { p--; {stack[top++] = cs; cs = 10; goto _again;} } break; case 2: -#line 1166 "upb/json/parser.rl" +#line 1165 "upb/json/parser.rl" { start_text(parser, p); } break; case 3: -#line 1167 "upb/json/parser.rl" +#line 1166 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_text(parser, p)); } break; case 4: -#line 1173 "upb/json/parser.rl" +#line 1172 "upb/json/parser.rl" { start_hex(parser); } break; case 5: -#line 1174 "upb/json/parser.rl" +#line 1173 "upb/json/parser.rl" { hexdigit(parser, p); } break; case 6: -#line 1175 "upb/json/parser.rl" +#line 1174 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_hex(parser)); } break; case 7: -#line 1181 "upb/json/parser.rl" +#line 1180 "upb/json/parser.rl" { CHECK_RETURN_TOP(escape(parser, p)); } break; case 8: -#line 1187 "upb/json/parser.rl" +#line 1186 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; case 9: -#line 1190 "upb/json/parser.rl" +#line 1189 "upb/json/parser.rl" { {stack[top++] = cs; cs = 19; goto _again;} } break; case 10: -#line 1192 "upb/json/parser.rl" +#line 1191 "upb/json/parser.rl" { p--; {stack[top++] = cs; cs = 27; goto _again;} } break; case 11: -#line 1197 "upb/json/parser.rl" +#line 1196 "upb/json/parser.rl" { start_member(parser); } break; case 12: -#line 1198 "upb/json/parser.rl" +#line 1197 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_membername(parser)); } break; case 13: -#line 1201 "upb/json/parser.rl" +#line 1200 "upb/json/parser.rl" { end_member(parser); } break; case 14: -#line 1207 "upb/json/parser.rl" +#line 1206 "upb/json/parser.rl" { start_object(parser); } break; case 15: -#line 1210 "upb/json/parser.rl" +#line 1209 "upb/json/parser.rl" { end_object(parser); } break; case 16: -#line 1216 "upb/json/parser.rl" +#line 1215 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_array(parser)); } break; case 17: -#line 1220 "upb/json/parser.rl" +#line 1219 "upb/json/parser.rl" { end_array(parser); } break; case 18: -#line 1225 "upb/json/parser.rl" +#line 1224 "upb/json/parser.rl" { start_number(parser, p); } break; case 19: -#line 1226 "upb/json/parser.rl" +#line 1225 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_number(parser, p)); } break; case 20: -#line 1228 "upb/json/parser.rl" +#line 1227 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_stringval(parser)); } break; case 21: -#line 1229 "upb/json/parser.rl" +#line 1228 "upb/json/parser.rl" { CHECK_RETURN_TOP(end_stringval(parser)); } break; case 22: -#line 1231 "upb/json/parser.rl" +#line 1230 "upb/json/parser.rl" { CHECK_RETURN_TOP(parser_putbool(parser, true)); } break; case 23: -#line 1233 "upb/json/parser.rl" +#line 1232 "upb/json/parser.rl" { CHECK_RETURN_TOP(parser_putbool(parser, false)); } break; case 24: -#line 1235 "upb/json/parser.rl" +#line 1234 "upb/json/parser.rl" { /* null value */ } break; case 25: -#line 1237 "upb/json/parser.rl" +#line 1236 "upb/json/parser.rl" { CHECK_RETURN_TOP(start_subobject(parser)); } break; case 26: -#line 1238 "upb/json/parser.rl" +#line 1237 "upb/json/parser.rl" { end_subobject(parser); } break; case 27: -#line 1243 "upb/json/parser.rl" +#line 1242 "upb/json/parser.rl" { p--; {cs = stack[--top]; goto _again;} } break; -#line 1515 "upb/json/parser.c" +#line 1514 "upb/json/parser.c" } } @@ -11621,7 +11811,7 @@ _again: _out: {} } -#line 1270 "upb/json/parser.rl" +#line 1269 "upb/json/parser.rl" if (p != pe) { upb_status_seterrf(&parser->status, "Parse error at '%.*s'\n", pe - p, p); @@ -11662,13 +11852,13 @@ static void json_parser_reset(upb_json_parser *p) { /* Emit Ragel initialization of the parser. */ -#line 1569 "upb/json/parser.c" +#line 1568 "upb/json/parser.c" { cs = json_start; top = 0; } -#line 1310 "upb/json/parser.rl" +#line 1309 "upb/json/parser.rl" p->current_state = cs; p->parser_top = top; accumulate_clear(p); @@ -11694,12 +11884,12 @@ static void free_json_parsermethod(upb_refcounted *r) { upb_value val = upb_inttable_iter_value(&i); upb_strtable *t = upb_value_getptr(val); upb_strtable_uninit(t); - free(t); + upb_gfree(t); } upb_inttable_uninit(&method->name_tables); - free(r); + upb_gfree(r); } static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { @@ -11716,7 +11906,7 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { } /* TODO(haberman): handle malloc failure. */ - t = malloc(sizeof(*t)); + t = upb_gmalloc(sizeof(*t)); upb_strtable_init(t, UPB_CTYPE_CONSTPTR); upb_inttable_insertptr(&m->name_tables, md, upb_value_ptr(t)); @@ -11729,7 +11919,7 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { size_t field_len = upb_fielddef_getjsonname(f, buf, len); if (field_len > len) { size_t len2; - buf = realloc(buf, field_len); + buf = upb_grealloc(buf, 0, field_len); len = field_len; len2 = upb_fielddef_getjsonname(f, buf, len); UPB_ASSERT_VAR(len2, len == len2); @@ -11748,7 +11938,7 @@ static void add_jsonname_table(upb_json_parsermethod *m, const upb_msgdef* md) { } } - free(buf); + upb_gfree(buf); } /* Public API *****************************************************************/ @@ -11788,7 +11978,7 @@ upb_json_parsermethod *upb_json_parsermethod_new(const upb_msgdef* md, const void* owner) { static const struct upb_refcounted_vtbl vtbl = {visit_json_parsermethod, free_json_parsermethod}; - upb_json_parsermethod *ret = malloc(sizeof(*ret)); + upb_json_parsermethod *ret = upb_gmalloc(sizeof(*ret)); upb_refcounted_init(upb_json_parsermethod_upcast_mutable(ret), &vtbl, owner); ret->msg = md; @@ -11815,8 +12005,6 @@ const upb_byteshandler *upb_json_parsermethod_inputhandler( */ -#include -#include #include #include @@ -11849,22 +12037,22 @@ typedef struct { void freestrpc(void *ptr) { strpc *pc = ptr; - free(pc->ptr); - free(pc); + upb_gfree(pc->ptr); + upb_gfree(pc); } /* Convert fielddef name to JSON name and return as a string piece. */ strpc *newstrpc(upb_handlers *h, const upb_fielddef *f, bool preserve_fieldnames) { /* TODO(haberman): handle malloc failure. */ - strpc *ret = malloc(sizeof(*ret)); + strpc *ret = upb_gmalloc(sizeof(*ret)); if (preserve_fieldnames) { - ret->ptr = upb_strdup(upb_fielddef_name(f)); + ret->ptr = upb_gstrdup(upb_fielddef_name(f)); ret->len = strlen(ret->ptr); } else { size_t len; ret->len = upb_fielddef_getjsonname(f, NULL, 0); - ret->ptr = malloc(ret->len); + ret->ptr = upb_gmalloc(ret->len); len = upb_fielddef_getjsonname(f, ret->ptr, ret->len); UPB_ASSERT_VAR(len, len == ret->len); ret->len--; /* NULL */ @@ -12376,10 +12564,10 @@ static void set_enum_hd(upb_handlers *h, const upb_fielddef *f, bool preserve_fieldnames, upb_handlerattr *attr) { - EnumHandlerData *hd = malloc(sizeof(EnumHandlerData)); + EnumHandlerData *hd = upb_gmalloc(sizeof(EnumHandlerData)); hd->enumdef = (const upb_enumdef *)upb_fielddef_subdef(f); hd->keyname = newstrpc(h, f, preserve_fieldnames); - upb_handlers_addcleanup(h, hd, free); + upb_handlers_addcleanup(h, hd, upb_gfree); upb_handlerattr_sethandlerdata(attr, hd); } diff --git a/ruby/ext/google/protobuf_c/upb.h b/ruby/ext/google/protobuf_c/upb.h index b0058161..2faf74e5 100644 --- a/ruby/ext/google/protobuf_c/upb.h +++ b/ruby/ext/google/protobuf_c/upb.h @@ -80,6 +80,18 @@ #include #include +#ifdef __cplusplus +namespace upb { +class Allocator; +class Arena; +class Environment; +class ErrorSpace; +class Status; +template class InlinedArena; +template class InlinedEnvironment; +} +#endif + /* UPB_INLINE: inline if possible, emit standalone code if required. */ #ifdef __cplusplus #define UPB_INLINE inline @@ -147,6 +159,7 @@ #define UPB_ASSERT_STDLAYOUT(type) \ static_assert(std::is_standard_layout::value, \ #type " must be standard layout"); +#define UPB_FINAL final #else /* !defined(UPB_CXX11) */ #define UPB_DISALLOW_COPY_AND_ASSIGN(class_name) \ class_name(const class_name&); \ @@ -156,6 +169,7 @@ ~class_name(); \ UPB_DISALLOW_COPY_AND_ASSIGN(class_name) #define UPB_ASSERT_STDLAYOUT(type) +#define UPB_FINAL #endif /* UPB_DECLARE_TYPE() @@ -257,6 +271,7 @@ /* Generic function type. */ typedef void upb_func(); + /* C++ Casts ******************************************************************/ #ifdef __cplusplus @@ -334,134 +349,18 @@ class PointerBase2 : public PointerBase { #endif -/* upb::reffed_ptr ************************************************************/ +/* upb::ErrorSpace ************************************************************/ -#ifdef __cplusplus - -#include /* For std::swap(). */ - -namespace upb { - -/* Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a - * ref on whatever object it points to (if any). */ -template class reffed_ptr { - public: - reffed_ptr() : ptr_(NULL) {} - - /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ - template - reffed_ptr(U* val, const void* ref_donor = NULL) - : ptr_(upb::upcast(val)) { - if (ref_donor) { - assert(ptr_); - ptr_->DonateRef(ref_donor, this); - } else if (ptr_) { - ptr_->Ref(this); - } - } - - template - reffed_ptr(const reffed_ptr& other) - : ptr_(upb::upcast(other.get())) { - if (ptr_) ptr_->Ref(this); - } - - reffed_ptr(const reffed_ptr& other) - : ptr_(upb::upcast(other.get())) { - if (ptr_) ptr_->Ref(this); - } - - ~reffed_ptr() { if (ptr_) ptr_->Unref(this); } - - template - reffed_ptr& operator=(const reffed_ptr& other) { - reset(other.get()); - return *this; - } - - reffed_ptr& operator=(const reffed_ptr& other) { - reset(other.get()); - return *this; - } - - /* TODO(haberman): add C++11 move construction/assignment for greater - * efficiency. */ - - void swap(reffed_ptr& other) { - if (ptr_ == other.ptr_) { - return; - } - - if (ptr_) ptr_->DonateRef(this, &other); - if (other.ptr_) other.ptr_->DonateRef(&other, this); - std::swap(ptr_, other.ptr_); - } - - T& operator*() const { - assert(ptr_); - return *ptr_; - } - - T* operator->() const { - assert(ptr_); - return ptr_; - } - - T* get() const { return ptr_; } - - /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ - template - void reset(U* ptr = NULL, const void* ref_donor = NULL) { - reffed_ptr(ptr, ref_donor).swap(*this); - } - - template - reffed_ptr down_cast() { - return reffed_ptr(upb::down_cast(get())); - } - - template - reffed_ptr dyn_cast() { - return reffed_ptr(upb::dyn_cast(get())); - } - - /* Plain release() is unsafe; if we were the only owner, it would leak the - * object. Instead we provide this: */ - T* ReleaseTo(const void* new_owner) { - T* ret = NULL; - ptr_->DonateRef(this, new_owner); - std::swap(ret, ptr_); - return ret; - } - - private: - T* ptr_; -}; - -} /* namespace upb */ - -#endif /* __cplusplus */ - - -/* upb::Status ****************************************************************/ - -#ifdef __cplusplus -namespace upb { -class ErrorSpace; -class Status; -} -#endif +/* A upb::ErrorSpace represents some domain of possible error values. This lets + * upb::Status attach specific error codes to operations, like POSIX/C errno, + * Win32 error codes, etc. Clients who want to know the very specific error + * code can check the error space and then know the type of the integer code. + * + * NOTE: upb::ErrorSpace is currently not used and should be considered + * experimental. It is important primarily in cases where upb is performing + * I/O, but upb doesn't currently have any components that do this. */ UPB_DECLARE_TYPE(upb::ErrorSpace, upb_errorspace) -UPB_DECLARE_TYPE(upb::Status, upb_status) - -/* The maximum length of an error message before it will get truncated. */ -#define UPB_STATUS_MAX_MESSAGE 128 - -/* An error callback function is used to report errors from some component. - * The function can return "true" to indicate that the component should try - * to recover and proceed, but this is not always possible. */ -typedef bool upb_errcb_t(void *closure, const upb_status* status); #ifdef __cplusplus class upb::ErrorSpace { @@ -469,67 +368,21 @@ class upb::ErrorSpace { struct upb_errorspace { #endif const char *name; - /* Should the error message in the status object according to this code. */ - void (*set_message)(upb_status* status, int code); }; -#ifdef __cplusplus -/* Object representing a success or failure status. +/* upb::Status ****************************************************************/ + +/* upb::Status represents a success or failure status and error message. * It owns no resources and allocates no memory, so it should work * even in OOM situations. */ +UPB_DECLARE_TYPE(upb::Status, upb_status) -class upb::Status { - public: - Status(); +/* The maximum length of an error message before it will get truncated. */ +#define UPB_STATUS_MAX_MESSAGE 128 - /* Returns true if there is no error. */ - bool ok() const; +UPB_BEGIN_EXTERN_C - /* Optional error space and code, useful if the caller wants to - * programmatically check the specific kind of error. */ - ErrorSpace* error_space(); - int code() const; - - const char *error_message() const; - - /* The error message will be truncated if it is longer than - * UPB_STATUS_MAX_MESSAGE-4. */ - void SetErrorMessage(const char* msg); - void SetFormattedErrorMessage(const char* fmt, ...); - - /* If there is no error message already, this will use the ErrorSpace to - * populate the error message for this code. The caller can still call - * SetErrorMessage() to give a more specific message. */ - void SetErrorCode(ErrorSpace* space, int code); - - /* Resets the status to a successful state with no message. */ - void Clear(); - - void CopyFrom(const Status& other); - - private: - UPB_DISALLOW_COPY_AND_ASSIGN(Status) -#else -struct upb_status { -#endif - bool ok_; - - /* Specific status code defined by some error space (optional). */ - int code_; - upb_errorspace *error_space_; - - /* Error message; NULL-terminated. */ - char msg[UPB_STATUS_MAX_MESSAGE]; -}; - -#define UPB_STATUS_INIT {true, 0, NULL, {0}} - -#ifdef __cplusplus -extern "C" { -#endif - -/* The returned string is invalidated by any other call into the status. */ const char *upb_status_errmsg(const upb_status *status); bool upb_ok(const upb_status *status); upb_errorspace *upb_status_errspace(const upb_status *status); @@ -542,40 +395,384 @@ void upb_status_clear(upb_status *status); void upb_status_seterrmsg(upb_status *status, const char *msg); void upb_status_seterrf(upb_status *status, const char *fmt, ...); void upb_status_vseterrf(upb_status *status, const char *fmt, va_list args); -void upb_status_seterrcode(upb_status *status, upb_errorspace *space, int code); void upb_status_copy(upb_status *to, const upb_status *from); +UPB_END_EXTERN_C + #ifdef __cplusplus -} /* extern "C" */ -namespace upb { +class upb::Status { + public: + Status() { upb_status_clear(this); } -/* C++ Wrappers */ -inline Status::Status() { Clear(); } -inline bool Status::ok() const { return upb_ok(this); } -inline const char* Status::error_message() const { - return upb_status_errmsg(this); -} -inline void Status::SetErrorMessage(const char* msg) { - upb_status_seterrmsg(this, msg); -} -inline void Status::SetFormattedErrorMessage(const char* fmt, ...) { - va_list args; - va_start(args, fmt); - upb_status_vseterrf(this, fmt, args); - va_end(args); -} -inline void Status::SetErrorCode(ErrorSpace* space, int code) { - upb_status_seterrcode(this, space, code); -} -inline void Status::Clear() { upb_status_clear(this); } -inline void Status::CopyFrom(const Status& other) { - upb_status_copy(this, &other); -} + /* Returns true if there is no error. */ + bool ok() const { return upb_ok(this); } -} /* namespace upb */ + /* Optional error space and code, useful if the caller wants to + * programmatically check the specific kind of error. */ + ErrorSpace* error_space() { return upb_status_errspace(this); } + int error_code() const { return upb_status_errcode(this); } + /* The returned string is invalidated by any other call into the status. */ + const char *error_message() const { return upb_status_errmsg(this); } + + /* The error message will be truncated if it is longer than + * UPB_STATUS_MAX_MESSAGE-4. */ + void SetErrorMessage(const char* msg) { upb_status_seterrmsg(this, msg); } + void SetFormattedErrorMessage(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + upb_status_vseterrf(this, fmt, args); + va_end(args); + } + + /* Resets the status to a successful state with no message. */ + void Clear() { upb_status_clear(this); } + + void CopyFrom(const Status& other) { upb_status_copy(this, &other); } + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Status) +#else +struct upb_status { #endif + bool ok_; + + /* Specific status code defined by some error space (optional). */ + int code_; + upb_errorspace *error_space_; + + /* TODO(haberman): add file/line of error? */ + + /* Error message; NULL-terminated. */ + char msg[UPB_STATUS_MAX_MESSAGE]; +}; + +#define UPB_STATUS_INIT {true, 0, NULL, {0}} + + +/** Built-in error spaces. ****************************************************/ + +/* Errors raised by upb that we want to be able to detect programmatically. */ +typedef enum { + UPB_NOMEM /* Can't reuse ENOMEM because it is POSIX, not ISO C. */ +} upb_errcode_t; + +extern upb_errorspace upb_upberr; + +void upb_upberr_setoom(upb_status *s); + +/* Since errno is defined by standard C, we define an error space for it in + * core upb. Other error spaces should be defined in other, platform-specific + * modules. */ + +extern upb_errorspace upb_errnoerr; + + +/** upb::Allocator ************************************************************/ + +/* A upb::Allocator is a possibly-stateful allocator object. + * + * It could either be an arena allocator (which doesn't require individual + * free() calls) or a regular malloc() (which does). The client must therefore + * free memory unless it knows that the allocator is an arena allocator. */ +UPB_DECLARE_TYPE(upb::Allocator, upb_alloc) + +/* A malloc()/free() function. + * If "size" is 0 then the function acts like free(), otherwise it acts like + * realloc(). Only "oldsize" bytes from a previous allocation are preserved. */ +typedef void *upb_alloc_func(upb_alloc *alloc, void *ptr, size_t oldsize, + size_t size); + +#ifdef __cplusplus + +class upb::Allocator UPB_FINAL { + public: + Allocator() {} + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Allocator) + + public: +#else +struct upb_alloc { +#endif /* __cplusplus */ + upb_alloc_func *func; +}; + +UPB_INLINE void *upb_malloc(upb_alloc *alloc, size_t size) { + assert(size > 0); + return alloc->func(alloc, NULL, 0, size); +} + +UPB_INLINE void *upb_realloc(upb_alloc *alloc, void *ptr, size_t oldsize, + size_t size) { + assert(size > 0); + return alloc->func(alloc, ptr, oldsize, size); +} + +UPB_INLINE void upb_free(upb_alloc *alloc, void *ptr) { + alloc->func(alloc, ptr, 0, 0); +} + +/* The global allocator used by upb. Uses the standard malloc()/free(). */ + +extern upb_alloc upb_alloc_global; + +/* Functions that hard-code the global malloc. + * + * We still get benefit because we can put custom logic into our global + * allocator, like injecting out-of-memory faults in debug/testing builds. */ + +UPB_INLINE void *upb_gmalloc(size_t size) { + return upb_malloc(&upb_alloc_global, size); +} + +UPB_INLINE void *upb_grealloc(void *ptr, size_t oldsize, size_t size) { + return upb_realloc(&upb_alloc_global, ptr, oldsize, size); +} + +UPB_INLINE void upb_gfree(void *ptr) { + upb_free(&upb_alloc_global, ptr); +} + +/* upb::Arena *****************************************************************/ + +/* upb::Arena is a specific allocator implementation that uses arena allocation. + * The user provides an allocator that will be used to allocate the underlying + * arena blocks. Arenas by nature do not require the individual allocations + * to be freed. However the Arena does allow users to register cleanup + * functions that will run when the arena is destroyed. + * + * A upb::Arena is *not* thread-safe. + * + * You could write a thread-safe arena allocator that satisfies the + * upb::Allocator interface, but it would not be as efficient for the + * single-threaded case. */ +UPB_DECLARE_TYPE(upb::Arena, upb_arena) + +typedef void upb_cleanup_func(void *ud); + +#define UPB_ARENA_BLOCK_OVERHEAD (sizeof(size_t)*4) + +UPB_BEGIN_EXTERN_C + +void upb_arena_init(upb_arena *a); +void upb_arena_init2(upb_arena *a, void *mem, size_t n, upb_alloc *alloc); +void upb_arena_uninit(upb_arena *a); +upb_alloc *upb_arena_alloc(upb_arena *a); +bool upb_arena_addcleanup(upb_arena *a, upb_cleanup_func *func, void *ud); +size_t upb_arena_bytesallocated(const upb_arena *a); +void upb_arena_setnextblocksize(upb_arena *a, size_t size); +void upb_arena_setmaxblocksize(upb_arena *a, size_t size); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +class upb::Arena { + public: + /* A simple arena with no initial memory block and the default allocator. */ + Arena() { upb_arena_init(this); } + + /* Constructs an arena with the given initial block which allocates blocks + * with the given allocator. The given allocator must outlive the Arena. + * + * If you pass NULL for the allocator it will default to the global allocator + * upb_alloc_global, and NULL/0 for the initial block will cause there to be + * no initial block. */ + Arena(void *mem, size_t len, Allocator* a) { + upb_arena_init2(this, mem, len, a); + } + + ~Arena() { upb_arena_uninit(this); } + + /* Sets the size of the next block the Arena will request (unless the + * requested allocation is larger). Each block will double in size until the + * max limit is reached. */ + void SetNextBlockSize(size_t size) { upb_arena_setnextblocksize(this, size); } + + /* Sets the maximum block size. No blocks larger than this will be requested + * from the underlying allocator unless individual arena allocations are + * larger. */ + void SetMaxBlockSize(size_t size) { upb_arena_setmaxblocksize(this, size); } + + /* Allows this arena to be used as a generic allocator. + * + * The arena does not need free() calls so when using Arena as an allocator + * it is safe to skip them. However they are no-ops so there is no harm in + * calling free() either. */ + Allocator* allocator() { return upb_arena_alloc(this); } + + /* Add a cleanup function to run when the arena is destroyed. + * Returns false on out-of-memory. */ + bool AddCleanup(upb_cleanup_func* func, void* ud) { + return upb_arena_addcleanup(this, func, ud); + } + + /* Total number of bytes that have been allocated. It is undefined what + * Realloc() does to this counter. */ + size_t BytesAllocated() const { + return upb_arena_bytesallocated(this); + } + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Arena) + +#else +struct upb_arena { +#endif /* __cplusplus */ + /* We implement the allocator interface. + * This must be the first member of upb_arena! */ + upb_alloc alloc; + + /* Allocator to allocate arena blocks. We are responsible for freeing these + * when we are destroyed. */ + upb_alloc *block_alloc; + + size_t bytes_allocated; + size_t next_block_size; + size_t max_block_size; + + /* Linked list of blocks. Points to an arena_block, defined in env.c */ + void *block_head; + + /* Cleanup entries. Pointer to a cleanup_ent, defined in env.c */ + void *cleanup_head; + + /* For future expansion, since the size of this struct is exposed to users. */ + void *future1; + void *future2; +}; + + +/* upb::Environment ***********************************************************/ + +/* A upb::Environment provides a means for injecting malloc and an + * error-reporting callback into encoders/decoders. This allows them to be + * independent of nearly all assumptions about their actual environment. + * + * It is also a container for allocating the encoders/decoders themselves that + * insulates clients from knowing their actual size. This provides ABI + * compatibility even if the size of the objects change. And this allows the + * structure definitions to be in the .c files instead of the .h files, making + * the .h files smaller and more readable. + * + * We might want to consider renaming this to "Pipeline" if/when the concept of + * a pipeline element becomes more formalized. */ +UPB_DECLARE_TYPE(upb::Environment, upb_env) + +/* A function that receives an error report from an encoder or decoder. The + * callback can return true to request that the error should be recovered, but + * if the error is not recoverable this has no effect. */ +typedef bool upb_error_func(void *ud, const upb_status *status); + +UPB_BEGIN_EXTERN_C + +void upb_env_init(upb_env *e); +void upb_env_init2(upb_env *e, void *mem, size_t n, upb_alloc *alloc); +void upb_env_uninit(upb_env *e); + +void upb_env_initonly(upb_env *e); + +upb_arena *upb_env_arena(upb_env *e); +bool upb_env_ok(const upb_env *e); +void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud); + +/* Convenience wrappers around the methods of the contained arena. */ +void upb_env_reporterrorsto(upb_env *e, upb_status *s); +bool upb_env_reporterror(upb_env *e, const upb_status *s); +void *upb_env_malloc(upb_env *e, size_t size); +void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size); +void upb_env_free(upb_env *e, void *ptr); +bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud); +size_t upb_env_bytesallocated(const upb_env *e); + +UPB_END_EXTERN_C + +#ifdef __cplusplus + +class upb::Environment { + public: + /* The given Arena must outlive this environment. */ + Environment() { upb_env_initonly(this); } + + Environment(void *mem, size_t len, Allocator *a) : arena_(mem, len, a) { + upb_env_initonly(this); + } + + Arena* arena() { return upb_env_arena(this); } + + /* Set a custom error reporting function. */ + void SetErrorFunction(upb_error_func* func, void* ud) { + upb_env_seterrorfunc(this, func, ud); + } + + /* Set the error reporting function to simply copy the status to the given + * status and abort. */ + void ReportErrorsTo(Status* status) { upb_env_reporterrorsto(this, status); } + + /* Returns true if all allocations and AddCleanup() calls have succeeded, + * and no errors were reported with ReportError() (except ones that recovered + * successfully). */ + bool ok() const { return upb_env_ok(this); } + + /* Reports an error to this environment's callback, returning true if + * the caller should try to recover. */ + bool ReportError(const Status* status) { + return upb_env_reporterror(this, status); + } + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(Environment) + +#else +struct upb_env { +#endif /* __cplusplus */ + upb_arena arena_; + upb_error_func *error_func_; + void *error_ud_; + bool ok_; +}; + + +/* upb::InlinedArena **********************************************************/ +/* upb::InlinedEnvironment ****************************************************/ + +/* upb::InlinedArena and upb::InlinedEnvironment seed their arenas with a + * predefined amount of memory. No heap memory will be allocated until the + * initial block is exceeded. + * + * These types only exist in C++ */ + +#ifdef __cplusplus + +template class upb::InlinedArena : public upb::Arena { + public: + InlinedArena() : Arena(initial_block_, N, NULL) {} + explicit InlinedArena(Allocator* a) : Arena(initial_block_, N, a) {} + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(InlinedArena) + + char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD]; +}; + +template class upb::InlinedEnvironment : public upb::Environment { + public: + InlinedEnvironment() : Environment(initial_block_, N, NULL) {} + explicit InlinedEnvironment(Allocator *a) + : Environment(initial_block_, N, a) {} + + private: + UPB_DISALLOW_COPY_AND_ASSIGN(InlinedEnvironment) + + char initial_block_[N + UPB_ARENA_BLOCK_OVERHEAD]; +}; + +#endif /* __cplusplus */ + + #endif /* UPB_H_ */ @@ -617,10 +814,14 @@ typedef struct { #endif /* Like strdup(), which isn't always available since it's not ANSI C. */ -char *upb_strdup(const char *s); +char *upb_strdup(const char *s, upb_alloc *a); /* Variant that works with a length-delimited rather than NULL-delimited string, * as supported by strtable. */ -char *upb_strdup2(const char *s, size_t len); +char *upb_strdup2(const char *s, size_t len, upb_alloc *a); + +UPB_INLINE char *upb_gstrdup(const char *s) { + return upb_strdup(s, &upb_alloc_global); +} UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val, upb_ctype_t ctype) { @@ -797,14 +998,40 @@ typedef struct { * initialize const hash tables. Then we cast away const when we have to. */ const upb_tabent *entries; + +#ifndef NDEBUG + /* This table's allocator. We make the user pass it in to every relevant + * function and only use this to check it in debug mode. We do this solely + * to keep upb_table as small as possible. This might seem slightly paranoid + * but the plan is to use upb_table for all map fields and extension sets in + * a forthcoming message representation, so there could be a lot of these. + * If this turns out to be too annoying later, we can change it (since this + * is an internal-only header file). */ + upb_alloc *alloc; +#endif } upb_table; +#ifdef NDEBUG +# define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \ + {count, mask, ctype, size_lg2, entries} +#else +# ifdef UPB_DEBUG_REFS +/* At the moment the only mutable tables we statically initialize are debug + * ref tables. */ +# define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \ + {count, mask, ctype, size_lg2, entries, &upb_alloc_debugrefs} +# else +# define UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries) \ + {count, mask, ctype, size_lg2, entries, NULL} +# endif +#endif + typedef struct { upb_table t; } upb_strtable; #define UPB_STRTABLE_INIT(count, mask, ctype, size_lg2, entries) \ - {{count, mask, ctype, size_lg2, entries}} + {UPB_TABLE_INIT(count, mask, ctype, size_lg2, entries)} #define UPB_EMPTY_STRTABLE_INIT(ctype) \ UPB_STRTABLE_INIT(0, 0, ctype, 0, NULL) @@ -817,7 +1044,7 @@ typedef struct { } upb_inttable; #define UPB_INTTABLE_INIT(count, mask, ctype, size_lg2, ent, a, asize, acount) \ - {{count, mask, ctype, size_lg2, ent}, a, asize, acount} + {UPB_TABLE_INIT(count, mask, ctype, size_lg2, ent), a, asize, acount} #define UPB_EMPTY_INTTABLE_INIT(ctype) \ UPB_INTTABLE_INIT(0, 0, ctype, 0, NULL, NULL, 0, 0) @@ -857,10 +1084,26 @@ UPB_INLINE bool upb_arrhas(upb_tabval key) { /* Initialize and uninitialize a table, respectively. If memory allocation * failed, false is returned that the table is uninitialized. */ -bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype); -bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype); -void upb_inttable_uninit(upb_inttable *table); -void upb_strtable_uninit(upb_strtable *table); +bool upb_inttable_init2(upb_inttable *table, upb_ctype_t ctype, upb_alloc *a); +bool upb_strtable_init2(upb_strtable *table, upb_ctype_t ctype, upb_alloc *a); +void upb_inttable_uninit2(upb_inttable *table, upb_alloc *a); +void upb_strtable_uninit2(upb_strtable *table, upb_alloc *a); + +UPB_INLINE bool upb_inttable_init(upb_inttable *table, upb_ctype_t ctype) { + return upb_inttable_init2(table, ctype, &upb_alloc_global); +} + +UPB_INLINE bool upb_strtable_init(upb_strtable *table, upb_ctype_t ctype) { + return upb_strtable_init2(table, ctype, &upb_alloc_global); +} + +UPB_INLINE void upb_inttable_uninit(upb_inttable *table) { + upb_inttable_uninit2(table, &upb_alloc_global); +} + +UPB_INLINE void upb_strtable_uninit(upb_strtable *table) { + upb_strtable_uninit2(table, &upb_alloc_global); +} /* Returns the number of values in the table. */ size_t upb_inttable_count(const upb_inttable *t); @@ -875,9 +1118,20 @@ UPB_INLINE size_t upb_strtable_count(const upb_strtable *t) { * * If a table resize was required but memory allocation failed, false is * returned and the table is unchanged. */ -bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val); -bool upb_strtable_insert2(upb_strtable *t, const char *key, size_t len, - upb_value val); +bool upb_inttable_insert2(upb_inttable *t, uintptr_t key, upb_value val, + upb_alloc *a); +bool upb_strtable_insert3(upb_strtable *t, const char *key, size_t len, + upb_value val, upb_alloc *a); + +UPB_INLINE bool upb_inttable_insert(upb_inttable *t, uintptr_t key, + upb_value val) { + return upb_inttable_insert2(t, key, val, &upb_alloc_global); +} + +UPB_INLINE bool upb_strtable_insert2(upb_strtable *t, const char *key, + size_t len, upb_value val) { + return upb_strtable_insert3(t, key, len, val, &upb_alloc_global); +} /* For NULL-terminated strings. */ UPB_INLINE bool upb_strtable_insert(upb_strtable *t, const char *key, @@ -900,8 +1154,13 @@ UPB_INLINE bool upb_strtable_lookup(const upb_strtable *t, const char *key, /* Removes an item from the table. Returns true if the remove was successful, * and stores the removed item in *val if non-NULL. */ bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val); -bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len, - upb_value *val); +bool upb_strtable_remove3(upb_strtable *t, const char *key, size_t len, + upb_value *val, upb_alloc *alloc); + +UPB_INLINE bool upb_strtable_remove2(upb_strtable *t, const char *key, + size_t len, upb_value *val) { + return upb_strtable_remove3(t, key, len, val, &upb_alloc_global); +} /* For NULL-terminated strings. */ UPB_INLINE bool upb_strtable_remove(upb_strtable *t, const char *key, @@ -916,19 +1175,33 @@ bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val); /* Handy routines for treating an inttable like a stack. May not be mixed with * other insert/remove calls. */ -bool upb_inttable_push(upb_inttable *t, upb_value val); +bool upb_inttable_push2(upb_inttable *t, upb_value val, upb_alloc *a); upb_value upb_inttable_pop(upb_inttable *t); +UPB_INLINE bool upb_inttable_push(upb_inttable *t, upb_value val) { + return upb_inttable_push2(t, val, &upb_alloc_global); +} + /* Convenience routines for inttables with pointer keys. */ -bool upb_inttable_insertptr(upb_inttable *t, const void *key, upb_value val); +bool upb_inttable_insertptr2(upb_inttable *t, const void *key, upb_value val, + upb_alloc *a); bool upb_inttable_removeptr(upb_inttable *t, const void *key, upb_value *val); bool upb_inttable_lookupptr( const upb_inttable *t, const void *key, upb_value *val); +UPB_INLINE bool upb_inttable_insertptr(upb_inttable *t, const void *key, + upb_value val) { + return upb_inttable_insertptr2(t, key, val, &upb_alloc_global); +} + /* Optimizes the table for the current set of entries, for both memory use and * lookup time. Client should call this after all entries have been inserted; * inserting more entries is legal, but will likely require a table resize. */ -void upb_inttable_compact(upb_inttable *t); +void upb_inttable_compact2(upb_inttable *t, upb_alloc *a); + +UPB_INLINE void upb_inttable_compact(upb_inttable *t) { + upb_inttable_compact2(t, &upb_alloc_global); +} /* A special-case inlinable version of the lookup routine for 32-bit * integers. */ @@ -957,7 +1230,7 @@ UPB_INLINE bool upb_inttable_lookup32(const upb_inttable *t, uint32_t key, } /* Exposed for testing only. */ -bool upb_strtable_resize(upb_strtable *t, size_t size_lg2); +bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_alloc *a); /* Iterators ******************************************************************/ @@ -1002,8 +1275,8 @@ typedef struct { void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t); void upb_strtable_next(upb_strtable_iter *i); bool upb_strtable_done(const upb_strtable_iter *i); -const char *upb_strtable_iter_key(upb_strtable_iter *i); -size_t upb_strtable_iter_keylength(upb_strtable_iter *i); +const char *upb_strtable_iter_key(const upb_strtable_iter *i); +size_t upb_strtable_iter_keylength(const upb_strtable_iter *i); upb_value upb_strtable_iter_value(const upb_strtable_iter *i); void upb_strtable_iter_setdone(upb_strtable_iter *i); bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, @@ -1056,7 +1329,10 @@ bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, /* #define UPB_DEBUG_REFS */ #ifdef __cplusplus -namespace upb { class RefCounted; } +namespace upb { +class RefCounted; +template class reffed_ptr; +} #endif UPB_DECLARE_TYPE(upb::RefCounted, upb_refcounted) @@ -1124,10 +1400,12 @@ struct upb_refcounted { }; #ifdef UPB_DEBUG_REFS -#define UPB_REFCOUNT_INIT(refs, ref2s) \ - {&static_refcount, NULL, NULL, 0, true, refs, ref2s} +extern upb_alloc upb_alloc_debugrefs; +#define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \ + {&static_refcount, NULL, vtbl, 0, true, refs, ref2s} #else -#define UPB_REFCOUNT_INIT(refs, ref2s) {&static_refcount, NULL, NULL, 0, true} +#define UPB_REFCOUNT_INIT(vtbl, refs, ref2s) \ + {&static_refcount, NULL, vtbl, 0, true} #endif UPB_BEGIN_EXTERN_C @@ -1260,6 +1538,111 @@ inline void RefCounted::CheckRef(const void *owner) const { } /* namespace upb */ #endif + +/* upb::reffed_ptr ************************************************************/ + +#ifdef __cplusplus + +#include /* For std::swap(). */ + +/* Provides RAII semantics for upb refcounted objects. Each reffed_ptr owns a + * ref on whatever object it points to (if any). */ +template class upb::reffed_ptr { + public: + reffed_ptr() : ptr_(NULL) {} + + /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ + template + reffed_ptr(U* val, const void* ref_donor = NULL) + : ptr_(upb::upcast(val)) { + if (ref_donor) { + assert(ptr_); + ptr_->DonateRef(ref_donor, this); + } else if (ptr_) { + ptr_->Ref(this); + } + } + + template + reffed_ptr(const reffed_ptr& other) + : ptr_(upb::upcast(other.get())) { + if (ptr_) ptr_->Ref(this); + } + + reffed_ptr(const reffed_ptr& other) + : ptr_(upb::upcast(other.get())) { + if (ptr_) ptr_->Ref(this); + } + + ~reffed_ptr() { if (ptr_) ptr_->Unref(this); } + + template + reffed_ptr& operator=(const reffed_ptr& other) { + reset(other.get()); + return *this; + } + + reffed_ptr& operator=(const reffed_ptr& other) { + reset(other.get()); + return *this; + } + + /* TODO(haberman): add C++11 move construction/assignment for greater + * efficiency. */ + + void swap(reffed_ptr& other) { + if (ptr_ == other.ptr_) { + return; + } + + if (ptr_) ptr_->DonateRef(this, &other); + if (other.ptr_) other.ptr_->DonateRef(&other, this); + std::swap(ptr_, other.ptr_); + } + + T& operator*() const { + assert(ptr_); + return *ptr_; + } + + T* operator->() const { + assert(ptr_); + return ptr_; + } + + T* get() const { return ptr_; } + + /* If ref_donor is NULL, takes a new ref, otherwise adopts from ref_donor. */ + template + void reset(U* ptr = NULL, const void* ref_donor = NULL) { + reffed_ptr(ptr, ref_donor).swap(*this); + } + + template + reffed_ptr down_cast() { + return reffed_ptr(upb::down_cast(get())); + } + + template + reffed_ptr dyn_cast() { + return reffed_ptr(upb::dyn_cast(get())); + } + + /* Plain release() is unsafe; if we were the only owner, it would leak the + * object. Instead we provide this: */ + T* ReleaseTo(const void* new_owner) { + T* ret = NULL; + ptr_->DonateRef(this, new_owner); + std::swap(ret, ptr_); + return ret; + } + + private: + T* ptr_; +}; + +#endif /* __cplusplus */ + #endif /* UPB_REFCOUNT_H_ */ #ifdef __cplusplus @@ -1511,6 +1894,11 @@ typedef enum { UPB_DESCRIPTOR_TYPE_SINT64 = 18 } upb_descriptortype_t; +typedef enum { + UPB_SYNTAX_PROTO2 = 2, + UPB_SYNTAX_PROTO3 = 3 +} upb_syntax_t; + /* Maximum field number allowed for FieldDefs. This is an inherent limit of the * protobuf wire format. */ #define UPB_MAX_FIELDNUMBER ((1 << 29) - 1) @@ -1902,6 +2290,10 @@ UPB_END_EXTERN_C typedef upb_inttable_iter upb_msg_field_iter; typedef upb_strtable_iter upb_msg_oneof_iter; +/* Well-known field tag numbers for map-entry messages. */ +#define UPB_MAPENTRY_KEY 1 +#define UPB_MAPENTRY_VALUE 2 + #ifdef __cplusplus /* Structure that describes a single .proto message type. @@ -1960,6 +2352,11 @@ class upb::MessageDef { bool AddOneof(OneofDef* o, Status* s); bool AddOneof(const reffed_ptr& o, Status* s); + upb_syntax_t syntax() const; + + /* Returns false if we don't support this syntax value. */ + bool set_syntax(upb_syntax_t syntax); + /* Set this to false to indicate that primitive fields should not have * explicit presence information associated with them. This will affect all * fields added to this message. Defaults to true. */ @@ -2150,15 +2547,20 @@ UPB_REFCOUNTED_CMETHODS(upb_msgdef, upb_msgdef_upcast2) bool upb_msgdef_freeze(upb_msgdef *m, upb_status *status); +upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner); const char *upb_msgdef_fullname(const upb_msgdef *m); const char *upb_msgdef_name(const upb_msgdef *m); -bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s); +int upb_msgdef_numoneofs(const upb_msgdef *m); +upb_syntax_t upb_msgdef_syntax(const upb_msgdef *m); -upb_msgdef *upb_msgdef_dup(const upb_msgdef *m, const void *owner); bool upb_msgdef_addfield(upb_msgdef *m, upb_fielddef *f, const void *ref_donor, upb_status *s); bool upb_msgdef_addoneof(upb_msgdef *m, upb_oneofdef *o, const void *ref_donor, upb_status *s); +bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, upb_status *s); +void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry); +bool upb_msgdef_mapentry(const upb_msgdef *m); +bool upb_msgdef_setsyntax(upb_msgdef *m, upb_syntax_t syntax); /* Field lookup in a couple of different variations: * - itof = int to field @@ -2200,18 +2602,21 @@ UPB_INLINE upb_oneofdef *upb_msgdef_ntoo_mutable(upb_msgdef *m, return (upb_oneofdef *)upb_msgdef_ntoo(m, name, len); } -void upb_msgdef_setmapentry(upb_msgdef *m, bool map_entry); -bool upb_msgdef_mapentry(const upb_msgdef *m); +/* Lookup of either field or oneof by name. Returns whether either was found. + * If the return is true, then the found def will be set, and the non-found + * one set to NULL. */ +bool upb_msgdef_lookupname(const upb_msgdef *m, const char *name, size_t len, + const upb_fielddef **f, const upb_oneofdef **o); -/* Well-known field tag numbers for map-entry messages. */ -#define UPB_MAPENTRY_KEY 1 -#define UPB_MAPENTRY_VALUE 2 +UPB_INLINE bool upb_msgdef_lookupnamez(const upb_msgdef *m, const char *name, + const upb_fielddef **f, + const upb_oneofdef **o) { + return upb_msgdef_lookupname(m, name, strlen(name), f, o); +} -const upb_oneofdef *upb_msgdef_findoneof(const upb_msgdef *m, - const char *name); -int upb_msgdef_numoneofs(const upb_msgdef *m); - -/* upb_msg_field_iter i; +/* Iteration over fields and oneofs. For example: + * + * upb_msg_field_iter i; * for(upb_msg_field_begin(&i, m); * !upb_msg_field_done(&i); * upb_msg_field_next(&i)) { @@ -2523,11 +2928,6 @@ UPB_END_EXTERN_C /* upb::FileDef ***************************************************************/ -typedef enum { - UPB_SYNTAX_PROTO2 = 2, - UPB_SYNTAX_PROTO3 = 3 -} upb_syntax_t; - #ifdef __cplusplus /* Class that represents a .proto file with some things defined in it. @@ -2890,12 +3290,18 @@ inline const char *MessageDef::full_name() const { inline const char *MessageDef::name() const { return upb_msgdef_name(this); } +inline upb_syntax_t MessageDef::syntax() const { + return upb_msgdef_syntax(this); +} inline bool MessageDef::set_full_name(const char* fullname, Status* s) { return upb_msgdef_setfullname(this, fullname, s); } inline bool MessageDef::set_full_name(const std::string& fullname, Status* s) { return upb_msgdef_setfullname(this, upb_safecstr(fullname), s); } +inline bool MessageDef::set_syntax(upb_syntax_t syntax) { + return upb_msgdef_setsyntax(this, syntax); +} inline bool MessageDef::Freeze(Status* status) { return upb_msgdef_freeze(this, status); } @@ -3309,8 +3715,8 @@ struct upb_def { bool came_from_user; }; -#define UPB_DEF_INIT(name, type, refs, ref2s) \ - { UPB_REFCOUNT_INIT(refs, ref2s), name, NULL, type, false } +#define UPB_DEF_INIT(name, type, vtbl, refs, ref2s) \ + { UPB_REFCOUNT_INIT(vtbl, refs, ref2s), name, NULL, type, false } /* upb_fielddef ***************************************************************/ @@ -3350,12 +3756,14 @@ struct upb_fielddef { uint32_t index_; }; +extern const struct upb_refcounted_vtbl upb_fielddef_vtbl; + #define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, lazy, \ packed, name, num, msgdef, subdef, selector_base, \ index, defaultval, refs, ref2s) \ { \ - UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, {msgdef}, \ - {subdef}, NULL, false, false, \ + UPB_DEF_INIT(name, UPB_DEF_FIELD, &upb_fielddef_vtbl, refs, ref2s), \ + defaultval, {msgdef}, {subdef}, NULL, false, false, \ type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \ lazy, packed, intfmt, tagdelim, type, label, num, selector_base, index \ } @@ -3371,32 +3779,26 @@ struct upb_msgdef { /* Tables for looking up fields by number and name. */ upb_inttable itof; /* int to field */ - upb_strtable ntof; /* name to field */ + upb_strtable ntof; /* name to field/oneof */ - /* Tables for looking up oneofs by name. */ - upb_strtable ntoo; /* name to oneof */ - - /* Is this a map-entry message? - * TODO: set this flag properly for static descriptors; regenerate - * descriptor.upb.c. */ + /* Is this a map-entry message? */ bool map_entry; - /* Whether this message has proto2 or proto3 semantics. - * TODO: set this flag properly for static descriptors; regenerate - * descriptor.upb.c. */ + /* Whether this message has proto2 or proto3 semantics. */ upb_syntax_t syntax; /* TODO(haberman): proper extension ranges (there can be multiple). */ }; +extern const struct upb_refcounted_vtbl upb_msgdef_vtbl; + /* TODO: also support static initialization of the oneofs table. This will be * needed if we compile in descriptors that contain oneofs. */ #define UPB_MSGDEF_INIT(name, selector_count, submsg_field_count, itof, ntof, \ - refs, ref2s) \ + map_entry, syntax, refs, ref2s) \ { \ - UPB_DEF_INIT(name, UPB_DEF_MSG, refs, ref2s), selector_count, \ - submsg_field_count, itof, ntof, \ - UPB_EMPTY_STRTABLE_INIT(UPB_CTYPE_PTR), false, true \ + UPB_DEF_INIT(name, UPB_DEF_MSG, &upb_fielddef_vtbl, refs, ref2s), \ + selector_count, submsg_field_count, itof, ntof, map_entry, syntax \ } @@ -3410,8 +3812,11 @@ struct upb_enumdef { int32_t defaultval; }; +extern const struct upb_refcounted_vtbl upb_enumdef_vtbl; + #define UPB_ENUMDEF_INIT(name, ntoi, iton, defaultval, refs, ref2s) \ - { UPB_DEF_INIT(name, UPB_DEF_ENUM, refs, ref2s), ntoi, iton, defaultval } + { UPB_DEF_INIT(name, UPB_DEF_ENUM, &upb_enumdef_vtbl, refs, ref2s), ntoi, \ + iton, defaultval } /* upb_oneofdef ***************************************************************/ @@ -3425,8 +3830,10 @@ struct upb_oneofdef { const upb_msgdef *parent; }; +extern const struct upb_refcounted_vtbl upb_oneofdef_vtbl; + #define UPB_ONEOFDEF_INIT(name, ntof, itof, refs, ref2s) \ - { UPB_REFCOUNT_INIT(refs, ref2s), name, ntof, itof } + { UPB_REFCOUNT_INIT(&upb_oneofdef_vtbl, refs, ref2s), name, ntof, itof } /* upb_symtab *****************************************************************/ @@ -3437,9 +3844,6 @@ struct upb_symtab { upb_strtable symtab; }; -#define UPB_SYMTAB_INIT(symtab, refs, ref2s) \ - { UPB_REFCOUNT_INIT(refs, ref2s), symtab } - struct upb_filedef { upb_refcounted base; @@ -3451,6 +3855,8 @@ struct upb_filedef { upb_inttable deps; }; +extern const struct upb_refcounted_vtbl upb_filedef_vtbl; + #endif /* UPB_STATICINIT_H_ */ /* ** upb::Handlers (upb_handlers) @@ -5392,267 +5798,6 @@ inline BytesHandler::~BytesHandler() {} #endif /* UPB_HANDLERS_H */ /* -** upb::Environment (upb_env) -** -** A upb::Environment provides a means for injecting malloc and an -** error-reporting callback into encoders/decoders. This allows them to be -** independent of nearly all assumptions about their actual environment. -** -** It is also a container for allocating the encoders/decoders themselves that -** insulates clients from knowing their actual size. This provides ABI -** compatibility even if the size of the objects change. And this allows the -** structure definitions to be in the .c files instead of the .h files, making -** the .h files smaller and more readable. -*/ - - -#ifndef UPB_ENV_H_ -#define UPB_ENV_H_ - -#ifdef __cplusplus -namespace upb { -class Environment; -class SeededAllocator; -} -#endif - -UPB_DECLARE_TYPE(upb::Environment, upb_env) -UPB_DECLARE_TYPE(upb::SeededAllocator, upb_seededalloc) - -typedef void *upb_alloc_func(void *ud, void *ptr, size_t oldsize, size_t size); -typedef void upb_cleanup_func(void *ud); -typedef bool upb_error_func(void *ud, const upb_status *status); - -#ifdef __cplusplus - -/* An environment is *not* thread-safe. */ -class upb::Environment { - public: - Environment(); - ~Environment(); - - /* Set a custom memory allocation function for the environment. May ONLY - * be called before any calls to Malloc()/Realloc()/AddCleanup() below. - * If this is not called, the system realloc() function will be used. - * The given user pointer "ud" will be passed to the allocation function. - * - * The allocation function will not receive corresponding "free" calls. it - * must ensure that the memory is valid for the lifetime of the Environment, - * but it may be reclaimed any time thereafter. The likely usage is that - * "ud" points to a stateful allocator, and that the allocator frees all - * memory, arena-style, when it is destroyed. In this case the allocator must - * outlive the Environment. Another possibility is that the allocation - * function returns GC-able memory that is guaranteed to be GC-rooted for the - * life of the Environment. */ - void SetAllocationFunction(upb_alloc_func* alloc, void* ud); - - template - void SetAllocator(T* allocator) { - SetAllocationFunction(allocator->GetAllocationFunction(), allocator); - } - - /* Set a custom error reporting function. */ - void SetErrorFunction(upb_error_func* func, void* ud); - - /* Set the error reporting function to simply copy the status to the given - * status and abort. */ - void ReportErrorsTo(Status* status); - - /* Returns true if all allocations and AddCleanup() calls have succeeded, - * and no errors were reported with ReportError() (except ones that recovered - * successfully). */ - bool ok() const; - - /* Functions for use by encoders/decoders. **********************************/ - - /* Reports an error to this environment's callback, returning true if - * the caller should try to recover. */ - bool ReportError(const Status* status); - - /* Allocate memory. Uses the environment's allocation function. - * - * There is no need to free(). All memory will be freed automatically, but is - * guaranteed to outlive the Environment. */ - void* Malloc(size_t size); - - /* Reallocate memory. Preserves "oldsize" bytes from the existing buffer - * Requires: oldsize <= existing_size. - * - * TODO(haberman): should we also enforce that oldsize <= size? */ - void* Realloc(void* ptr, size_t oldsize, size_t size); - - /* Add a cleanup function to run when the environment is destroyed. - * Returns false on out-of-memory. - * - * The first call to AddCleanup() after SetAllocationFunction() is guaranteed - * to return true -- this makes it possible to robustly set a cleanup handler - * for a custom allocation function. */ - bool AddCleanup(upb_cleanup_func* func, void* ud); - - /* Total number of bytes that have been allocated. It is undefined what - * Realloc() does to this counter. */ - size_t BytesAllocated() const; - - private: - UPB_DISALLOW_COPY_AND_ASSIGN(Environment) - -#else -struct upb_env { -#endif /* __cplusplus */ - - bool ok_; - size_t bytes_allocated; - - /* Alloc function. */ - upb_alloc_func *alloc; - void *alloc_ud; - - /* Error-reporting function. */ - upb_error_func *err; - void *err_ud; - - /* Userdata for default alloc func. */ - void *default_alloc_ud; - - /* Cleanup entries. Pointer to a cleanup_ent, defined in env.c */ - void *cleanup_head; - - /* For future expansion, since the size of this struct is exposed to users. */ - void *future1; - void *future2; -}; - -UPB_BEGIN_EXTERN_C - -void upb_env_init(upb_env *e); -void upb_env_uninit(upb_env *e); -void upb_env_setallocfunc(upb_env *e, upb_alloc_func *func, void *ud); -void upb_env_seterrorfunc(upb_env *e, upb_error_func *func, void *ud); -void upb_env_reporterrorsto(upb_env *e, upb_status *status); -bool upb_env_ok(const upb_env *e); -bool upb_env_reporterror(upb_env *e, const upb_status *status); -void *upb_env_malloc(upb_env *e, size_t size); -void *upb_env_realloc(upb_env *e, void *ptr, size_t oldsize, size_t size); -bool upb_env_addcleanup(upb_env *e, upb_cleanup_func *func, void *ud); -size_t upb_env_bytesallocated(const upb_env *e); - -UPB_END_EXTERN_C - -#ifdef __cplusplus - -/* An allocator that allocates from an initial memory region (likely the stack) - * before falling back to another allocator. */ -class upb::SeededAllocator { - public: - SeededAllocator(void *mem, size_t len); - ~SeededAllocator(); - - /* Set a custom fallback memory allocation function for the allocator, to use - * once the initial region runs out. - * - * May ONLY be called before GetAllocationFunction(). If this is not - * called, the system realloc() will be the fallback allocator. */ - void SetFallbackAllocator(upb_alloc_func *alloc, void *ud); - - /* Gets the allocation function for this allocator. */ - upb_alloc_func* GetAllocationFunction(); - - private: - UPB_DISALLOW_COPY_AND_ASSIGN(SeededAllocator) - -#else -struct upb_seededalloc { -#endif /* __cplusplus */ - - /* Fallback alloc function. */ - upb_alloc_func *alloc; - upb_cleanup_func *alloc_cleanup; - void *alloc_ud; - bool need_cleanup; - bool returned_allocfunc; - - /* Userdata for default alloc func. */ - void *default_alloc_ud; - - /* Pointers for the initial memory region. */ - char *mem_base; - char *mem_ptr; - char *mem_limit; - - /* For future expansion, since the size of this struct is exposed to users. */ - void *future1; - void *future2; -}; - -UPB_BEGIN_EXTERN_C - -void upb_seededalloc_init(upb_seededalloc *a, void *mem, size_t len); -void upb_seededalloc_uninit(upb_seededalloc *a); -void upb_seededalloc_setfallbackalloc(upb_seededalloc *a, upb_alloc_func *func, - void *ud); -upb_alloc_func *upb_seededalloc_getallocfunc(upb_seededalloc *a); - -UPB_END_EXTERN_C - -#ifdef __cplusplus - -namespace upb { - -inline Environment::Environment() { - upb_env_init(this); -} -inline Environment::~Environment() { - upb_env_uninit(this); -} -inline void Environment::SetAllocationFunction(upb_alloc_func *alloc, - void *ud) { - upb_env_setallocfunc(this, alloc, ud); -} -inline void Environment::SetErrorFunction(upb_error_func *func, void *ud) { - upb_env_seterrorfunc(this, func, ud); -} -inline void Environment::ReportErrorsTo(Status* status) { - upb_env_reporterrorsto(this, status); -} -inline bool Environment::ok() const { - return upb_env_ok(this); -} -inline bool Environment::ReportError(const Status* status) { - return upb_env_reporterror(this, status); -} -inline void *Environment::Malloc(size_t size) { - return upb_env_malloc(this, size); -} -inline void *Environment::Realloc(void *ptr, size_t oldsize, size_t size) { - return upb_env_realloc(this, ptr, oldsize, size); -} -inline bool Environment::AddCleanup(upb_cleanup_func *func, void *ud) { - return upb_env_addcleanup(this, func, ud); -} -inline size_t Environment::BytesAllocated() const { - return upb_env_bytesallocated(this); -} - -inline SeededAllocator::SeededAllocator(void *mem, size_t len) { - upb_seededalloc_init(this, mem, len); -} -inline SeededAllocator::~SeededAllocator() { - upb_seededalloc_uninit(this); -} -inline void SeededAllocator::SetFallbackAllocator(upb_alloc_func *alloc, - void *ud) { - upb_seededalloc_setfallbackalloc(this, alloc, ud); -} -inline upb_alloc_func *SeededAllocator::GetAllocationFunction() { - return upb_seededalloc_getallocfunc(this); -} - -} /* namespace upb */ - -#endif /* __cplusplus */ - -#endif /* UPB_ENV_H_ */ -/* ** upb::Sink (upb_sink) ** upb::BytesSink (upb_bytessink) ** @@ -6529,7 +6674,11 @@ inline FileDef* Reader::file(size_t i) const { * actually storing protobufs. It only contains *defs* which * let you reflect over a protobuf *schema*. */ -/* This file was generated by upbc (the upb compiler). +/* This file was generated by upbc (the upb compiler) from the input + * file: + * + * upb/descriptor/descriptor.proto + * * Do not edit -- your changes will be discarded when the file is * regenerated. */ @@ -6818,347 +6967,347 @@ namespace upbdefs { namespace google { namespace protobuf { -class DescriptorProto : public upb::reffed_ptr { +class DescriptorProto : public ::upb::reffed_ptr { public: - DescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + DescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_DescriptorProto_is(m)); } static DescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_get(&m); return DescriptorProto(m, &m); } - class ExtensionRange : public upb::reffed_ptr { + class ExtensionRange : public ::upb::reffed_ptr { public: - ExtensionRange(const upb::MessageDef* m, const void *ref_donor = NULL) + ExtensionRange(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_DescriptorProto_ExtensionRange_is(m)); } static ExtensionRange get() { - const upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ExtensionRange_get(&m); return ExtensionRange(m, &m); } }; - class ReservedRange : public upb::reffed_ptr { + class ReservedRange : public ::upb::reffed_ptr { public: - ReservedRange(const upb::MessageDef* m, const void *ref_donor = NULL) + ReservedRange(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_DescriptorProto_ReservedRange_is(m)); } static ReservedRange get() { - const upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_DescriptorProto_ReservedRange_get(&m); return ReservedRange(m, &m); } }; }; -class EnumDescriptorProto : public upb::reffed_ptr { +class EnumDescriptorProto : public ::upb::reffed_ptr { public: - EnumDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + EnumDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_EnumDescriptorProto_is(m)); } static EnumDescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_EnumDescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumDescriptorProto_get(&m); return EnumDescriptorProto(m, &m); } }; -class EnumOptions : public upb::reffed_ptr { +class EnumOptions : public ::upb::reffed_ptr { public: - EnumOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + EnumOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_EnumOptions_is(m)); } static EnumOptions get() { - const upb::MessageDef* m = upbdefs_google_protobuf_EnumOptions_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumOptions_get(&m); return EnumOptions(m, &m); } }; -class EnumValueDescriptorProto : public upb::reffed_ptr { +class EnumValueDescriptorProto : public ::upb::reffed_ptr { public: - EnumValueDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + EnumValueDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)); } static EnumValueDescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_EnumValueDescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueDescriptorProto_get(&m); return EnumValueDescriptorProto(m, &m); } }; -class EnumValueOptions : public upb::reffed_ptr { +class EnumValueOptions : public ::upb::reffed_ptr { public: - EnumValueOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + EnumValueOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_EnumValueOptions_is(m)); } static EnumValueOptions get() { - const upb::MessageDef* m = upbdefs_google_protobuf_EnumValueOptions_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_EnumValueOptions_get(&m); return EnumValueOptions(m, &m); } }; -class FieldDescriptorProto : public upb::reffed_ptr { +class FieldDescriptorProto : public ::upb::reffed_ptr { public: - FieldDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + FieldDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_FieldDescriptorProto_is(m)); } static FieldDescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_FieldDescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldDescriptorProto_get(&m); return FieldDescriptorProto(m, &m); } - class Label : public upb::reffed_ptr { + class Label : public ::upb::reffed_ptr { public: - Label(const upb::EnumDef* e, const void *ref_donor = NULL) + Label(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { assert(upbdefs_google_protobuf_FieldDescriptorProto_Label_is(e)); } static Label get() { - const upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Label_get(&e); + const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Label_get(&e); return Label(e, &e); } }; - class Type : public upb::reffed_ptr { + class Type : public ::upb::reffed_ptr { public: - Type(const upb::EnumDef* e, const void *ref_donor = NULL) + Type(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { assert(upbdefs_google_protobuf_FieldDescriptorProto_Type_is(e)); } static Type get() { - const upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Type_get(&e); + const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldDescriptorProto_Type_get(&e); return Type(e, &e); } }; }; -class FieldOptions : public upb::reffed_ptr { +class FieldOptions : public ::upb::reffed_ptr { public: - FieldOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + FieldOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_FieldOptions_is(m)); } static FieldOptions get() { - const upb::MessageDef* m = upbdefs_google_protobuf_FieldOptions_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_FieldOptions_get(&m); return FieldOptions(m, &m); } - class CType : public upb::reffed_ptr { + class CType : public ::upb::reffed_ptr { public: - CType(const upb::EnumDef* e, const void *ref_donor = NULL) + CType(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { assert(upbdefs_google_protobuf_FieldOptions_CType_is(e)); } static CType get() { - const upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_CType_get(&e); + const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_CType_get(&e); return CType(e, &e); } }; - class JSType : public upb::reffed_ptr { + class JSType : public ::upb::reffed_ptr { public: - JSType(const upb::EnumDef* e, const void *ref_donor = NULL) + JSType(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { assert(upbdefs_google_protobuf_FieldOptions_JSType_is(e)); } static JSType get() { - const upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_JSType_get(&e); + const ::upb::EnumDef* e = upbdefs_google_protobuf_FieldOptions_JSType_get(&e); return JSType(e, &e); } }; }; -class FileDescriptorProto : public upb::reffed_ptr { +class FileDescriptorProto : public ::upb::reffed_ptr { public: - FileDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + FileDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_FileDescriptorProto_is(m)); } static FileDescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorProto_get(&m); return FileDescriptorProto(m, &m); } }; -class FileDescriptorSet : public upb::reffed_ptr { +class FileDescriptorSet : public ::upb::reffed_ptr { public: - FileDescriptorSet(const upb::MessageDef* m, const void *ref_donor = NULL) + FileDescriptorSet(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_FileDescriptorSet_is(m)); } static FileDescriptorSet get() { - const upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorSet_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_FileDescriptorSet_get(&m); return FileDescriptorSet(m, &m); } }; -class FileOptions : public upb::reffed_ptr { +class FileOptions : public ::upb::reffed_ptr { public: - FileOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + FileOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_FileOptions_is(m)); } static FileOptions get() { - const upb::MessageDef* m = upbdefs_google_protobuf_FileOptions_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_FileOptions_get(&m); return FileOptions(m, &m); } - class OptimizeMode : public upb::reffed_ptr { + class OptimizeMode : public ::upb::reffed_ptr { public: - OptimizeMode(const upb::EnumDef* e, const void *ref_donor = NULL) + OptimizeMode(const ::upb::EnumDef* e, const void *ref_donor = NULL) : reffed_ptr(e, ref_donor) { assert(upbdefs_google_protobuf_FileOptions_OptimizeMode_is(e)); } static OptimizeMode get() { - const upb::EnumDef* e = upbdefs_google_protobuf_FileOptions_OptimizeMode_get(&e); + const ::upb::EnumDef* e = upbdefs_google_protobuf_FileOptions_OptimizeMode_get(&e); return OptimizeMode(e, &e); } }; }; -class MessageOptions : public upb::reffed_ptr { +class MessageOptions : public ::upb::reffed_ptr { public: - MessageOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + MessageOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_MessageOptions_is(m)); } static MessageOptions get() { - const upb::MessageDef* m = upbdefs_google_protobuf_MessageOptions_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_MessageOptions_get(&m); return MessageOptions(m, &m); } }; -class MethodDescriptorProto : public upb::reffed_ptr { +class MethodDescriptorProto : public ::upb::reffed_ptr { public: - MethodDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + MethodDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_MethodDescriptorProto_is(m)); } static MethodDescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_MethodDescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodDescriptorProto_get(&m); return MethodDescriptorProto(m, &m); } }; -class MethodOptions : public upb::reffed_ptr { +class MethodOptions : public ::upb::reffed_ptr { public: - MethodOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + MethodOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_MethodOptions_is(m)); } static MethodOptions get() { - const upb::MessageDef* m = upbdefs_google_protobuf_MethodOptions_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_MethodOptions_get(&m); return MethodOptions(m, &m); } }; -class OneofDescriptorProto : public upb::reffed_ptr { +class OneofDescriptorProto : public ::upb::reffed_ptr { public: - OneofDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + OneofDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_OneofDescriptorProto_is(m)); } static OneofDescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_OneofDescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_OneofDescriptorProto_get(&m); return OneofDescriptorProto(m, &m); } }; -class ServiceDescriptorProto : public upb::reffed_ptr { +class ServiceDescriptorProto : public ::upb::reffed_ptr { public: - ServiceDescriptorProto(const upb::MessageDef* m, const void *ref_donor = NULL) + ServiceDescriptorProto(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_ServiceDescriptorProto_is(m)); } static ServiceDescriptorProto get() { - const upb::MessageDef* m = upbdefs_google_protobuf_ServiceDescriptorProto_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceDescriptorProto_get(&m); return ServiceDescriptorProto(m, &m); } }; -class ServiceOptions : public upb::reffed_ptr { +class ServiceOptions : public ::upb::reffed_ptr { public: - ServiceOptions(const upb::MessageDef* m, const void *ref_donor = NULL) + ServiceOptions(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_ServiceOptions_is(m)); } static ServiceOptions get() { - const upb::MessageDef* m = upbdefs_google_protobuf_ServiceOptions_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_ServiceOptions_get(&m); return ServiceOptions(m, &m); } }; -class SourceCodeInfo : public upb::reffed_ptr { +class SourceCodeInfo : public ::upb::reffed_ptr { public: - SourceCodeInfo(const upb::MessageDef* m, const void *ref_donor = NULL) + SourceCodeInfo(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_SourceCodeInfo_is(m)); } static SourceCodeInfo get() { - const upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_get(&m); return SourceCodeInfo(m, &m); } - class Location : public upb::reffed_ptr { + class Location : public ::upb::reffed_ptr { public: - Location(const upb::MessageDef* m, const void *ref_donor = NULL) + Location(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_SourceCodeInfo_Location_is(m)); } static Location get() { - const upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_Location_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_SourceCodeInfo_Location_get(&m); return Location(m, &m); } }; }; -class UninterpretedOption : public upb::reffed_ptr { +class UninterpretedOption : public ::upb::reffed_ptr { public: - UninterpretedOption(const upb::MessageDef* m, const void *ref_donor = NULL) + UninterpretedOption(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_UninterpretedOption_is(m)); } static UninterpretedOption get() { - const upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_get(&m); return UninterpretedOption(m, &m); } - class NamePart : public upb::reffed_ptr { + class NamePart : public ::upb::reffed_ptr { public: - NamePart(const upb::MessageDef* m, const void *ref_donor = NULL) + NamePart(const ::upb::MessageDef* m, const void *ref_donor = NULL) : reffed_ptr(m, ref_donor) { assert(upbdefs_google_protobuf_UninterpretedOption_NamePart_is(m)); } static NamePart get() { - const upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_NamePart_get(&m); + const ::upb::MessageDef* m = upbdefs_google_protobuf_UninterpretedOption_NamePart_get(&m); return NamePart(m, &m); } }; @@ -7178,7 +7327,6 @@ class UninterpretedOption : public upb::reffed_ptr { #ifndef UPB_DECODER_INT_H_ #define UPB_DECODER_INT_H_ -#include /* ** upb::pb::Decoder ** @@ -7278,7 +7426,7 @@ class upb::pb::DecoderMethod { * constructed. This hint may be an overestimate for some build configurations. * But if the decoder library is upgraded without recompiling the application, * it may be an underestimate. */ -#define UPB_PB_DECODER_SIZE 4408 +#define UPB_PB_DECODER_SIZE 4416 #ifdef __cplusplus @@ -8097,7 +8245,8 @@ extern "C" { #endif /* Loads a binary descriptor and returns a NULL-terminated array of unfrozen - * filedefs. The caller owns the returned array. */ + * filedefs. The caller owns the returned array, which must be freed with + * upb_gfree(). */ upb_filedef **upb_loaddescriptor(const char *buf, size_t n, const void *owner, upb_status *status); @@ -8244,7 +8393,7 @@ UPB_DECLARE_DERIVED_TYPE(upb::json::ParserMethod, upb::RefCounted, * constructed. This hint may be an overestimate for some build configurations. * But if the parser library is upgraded without recompiling the application, * it may be an underestimate. */ -#define UPB_JSON_PARSER_SIZE 4104 +#define UPB_JSON_PARSER_SIZE 4112 #ifdef __cplusplus @@ -8357,7 +8506,7 @@ UPB_DECLARE_TYPE(upb::json::Printer, upb_json_printer) /* upb::json::Printer *********************************************************/ -#define UPB_JSON_PRINTER_SIZE 168 +#define UPB_JSON_PRINTER_SIZE 176 #ifdef __cplusplus From 18b6a321b5fd8f53e1029c436c2ad5dd2d3122df Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 26 Apr 2016 14:40:11 -0400 Subject: [PATCH 096/123] Proper checking of enum with non zero default proto2 syntax allows the first enum to have a non zero value. This means any field using that default has a non zero default without having an explicit default being set. So when deciding what runtime info is needed, don't rely on an explicit default, always check that the values aren't zero. Fixes https://github.com/google/protobuf/issues/1453 --- objectivec/Tests/GPBMessageTests.m | 7 +++++++ objectivec/Tests/unittest_objc.proto | 10 ++++++++++ .../protobuf/compiler/objectivec/objectivec_helpers.cc | 9 +++++---- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m index 43546156..0779c5ae 100644 --- a/objectivec/Tests/GPBMessageTests.m +++ b/objectivec/Tests/GPBMessageTests.m @@ -1947,4 +1947,11 @@ EnumTestMsg_MyEnum_NegTwo); } +- (void)testOneBasedEnumHolder { + // Test case for https://github.com/google/protobuf/issues/1453 + // Message with no explicit defaults, but a non zero default for an enum. + MessageWithOneBasedEnum *enumMsg = [MessageWithOneBasedEnum message]; + XCTAssertEqual(enumMsg.enumField, MessageWithOneBasedEnum_OneBasedEnum_One); +} + @end diff --git a/objectivec/Tests/unittest_objc.proto b/objectivec/Tests/unittest_objc.proto index 9483cb1d..6bcfbf70 100644 --- a/objectivec/Tests/unittest_objc.proto +++ b/objectivec/Tests/unittest_objc.proto @@ -401,3 +401,13 @@ message EnumTestMsg { repeated MyEnum mumble = 4; } + +// Test case for https://github.com/google/protobuf/issues/1453 +// Message with no explicit defaults, but a non zero default for an enum. +message MessageWithOneBasedEnum { + enum OneBasedEnum { + ONE = 1; + TWO = 2; + } + optional OneBasedEnum enum_field = 1; +} diff --git a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc index fda51807..196b39dd 100644 --- a/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc +++ b/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc @@ -757,10 +757,11 @@ bool HasNonZeroDefaultValue(const FieldDescriptor* field) { return false; } - if (!field->has_default_value()) { - // No custom default set in the proto file. - return false; - } + // As much as checking field->has_default_value() seems useful, it isn't + // because of enums. proto2 syntax allows the first item in an enum (the + // default) to be non zero. So checking field->has_default_value() would + // result in missing this non zero default. See MessageWithOneBasedEnum in + // objectivec/Tests/unittest_objc.proto for a test Message to confirm this. // Some proto file set the default to the zero value, so make sure the value // isn't the zero case. From bbb68fe63d0c77d19cb7ecccbfb77c8bdccf751c Mon Sep 17 00:00:00 2001 From: Adam Cozzette Date: Wed, 27 Apr 2016 10:40:54 -0700 Subject: [PATCH 097/123] Added dig and bsearch_index to RepeatedField methods forwarded to array This fixes the test_acts_likes_an_array test in RepeatedFieldTest, which checks that repeated fields respond to the same methods as regular Ruby arrays. The bsearch_index and dig array methods seem to be new in Ruby 2.3 and so we should support those. --- ruby/lib/google/protobuf/repeated_field.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruby/lib/google/protobuf/repeated_field.rb b/ruby/lib/google/protobuf/repeated_field.rb index 16c843c0..0ad2060d 100644 --- a/ruby/lib/google/protobuf/repeated_field.rb +++ b/ruby/lib/google/protobuf/repeated_field.rb @@ -69,8 +69,8 @@ module Google # relationship explicit instead of implicit def_delegators :to_ary, :&, :*, :-, :'<=>', - :assoc, :bsearch, :combination, :compact, :count, :cycle, - :drop, :drop_while, :eql?, :fetch, :find_index, :flatten, + :assoc, :bsearch, :bsearch_index, :combination, :compact, :count, + :cycle, :dig, :drop, :drop_while, :eql?, :fetch, :find_index, :flatten, :include?, :index, :inspect, :join, :pack, :permutation, :product, :pretty_print, :pretty_print_cycle, :rassoc, :repeated_combination, :repeated_permutation, :reverse, From 30646288ad60fff7a3ce9c864a9bf481e6c4045a Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Wed, 27 Apr 2016 13:11:16 -0400 Subject: [PATCH 098/123] Fix up -hash/-isEqual: for bool storage. Both methods weren't checking the has_bits (where the bools are stored), so it resulted in invalid results. Add a test that should shake out something like this in the future also. --- objectivec/GPBMessage.m | 18 +++++--- objectivec/Tests/GPBMessageTests.m | 65 ++++++++++++++++++++++++++++ objectivec/Tests/unittest_objc.proto | 36 +++++++++++++++ 3 files changed, 114 insertions(+), 5 deletions(-) diff --git a/objectivec/GPBMessage.m b/objectivec/GPBMessage.m index 0e1599dc..8134e259 100644 --- a/objectivec/GPBMessage.m +++ b/objectivec/GPBMessage.m @@ -2603,9 +2603,13 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( size_t fieldOffset = field->description_->offset; switch (fieldDataType) { case GPBDataTypeBool: { - BOOL *selfValPtr = (BOOL *)&selfStorage[fieldOffset]; - BOOL *otherValPtr = (BOOL *)&otherStorage[fieldOffset]; - if (*selfValPtr != *otherValPtr) { + // Bools are stored in has_bits to avoid needing explicit space in + // the storage structure. + // (the field number passed to the HasIvar helper doesn't really + // matter since the offset is never negative) + BOOL selfValue = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0); + BOOL otherValue = GPBGetHasIvar(other, (int32_t)(fieldOffset), 0); + if (selfValue != otherValue) { return NO; } break; @@ -2714,8 +2718,12 @@ static void MergeRepeatedNotPackedFieldFromCodedInputStream( size_t fieldOffset = field->description_->offset; switch (fieldDataType) { case GPBDataTypeBool: { - BOOL *valPtr = (BOOL *)&storage[fieldOffset]; - result = prime * result + *valPtr; + // Bools are stored in has_bits to avoid needing explicit space in + // the storage structure. + // (the field number passed to the HasIvar helper doesn't really + // matter since the offset is never negative) + BOOL value = GPBGetHasIvar(self, (int32_t)(fieldOffset), 0); + result = prime * result + value; break; } case GPBDataTypeSFixed32: diff --git a/objectivec/Tests/GPBMessageTests.m b/objectivec/Tests/GPBMessageTests.m index 0779c5ae..89d1fce2 100644 --- a/objectivec/Tests/GPBMessageTests.m +++ b/objectivec/Tests/GPBMessageTests.m @@ -1954,4 +1954,69 @@ XCTAssertEqual(enumMsg.enumField, MessageWithOneBasedEnum_OneBasedEnum_One); } +- (void)testBoolOffsetUsage { + // Bools use storage within has_bits; this test ensures that this is honored + // in all places where things should crash or fail based on reading out of + // field storage instead. + BoolOnlyMessage *msg1 = [BoolOnlyMessage message]; + BoolOnlyMessage *msg2 = [BoolOnlyMessage message]; + + msg1.boolField1 = YES; + msg2.boolField1 = YES; + msg1.boolField3 = YES; + msg2.boolField3 = YES; + msg1.boolField5 = YES; + msg2.boolField5 = YES; + msg1.boolField7 = YES; + msg2.boolField7 = YES; + msg1.boolField9 = YES; + msg2.boolField9 = YES; + msg1.boolField11 = YES; + msg2.boolField11 = YES; + msg1.boolField13 = YES; + msg2.boolField13 = YES; + msg1.boolField15 = YES; + msg2.boolField15 = YES; + msg1.boolField17 = YES; + msg2.boolField17 = YES; + msg1.boolField19 = YES; + msg2.boolField19 = YES; + msg1.boolField21 = YES; + msg2.boolField21 = YES; + msg1.boolField23 = YES; + msg2.boolField23 = YES; + msg1.boolField25 = YES; + msg2.boolField25 = YES; + msg1.boolField27 = YES; + msg2.boolField27 = YES; + msg1.boolField29 = YES; + msg2.boolField29 = YES; + msg1.boolField31 = YES; + msg2.boolField31 = YES; + + msg1.boolField32 = YES; + msg2.boolField32 = YES; + + XCTAssertTrue(msg1 != msg2); // Different pointers. + XCTAssertEqual([msg1 hash], [msg2 hash]); + XCTAssertEqualObjects(msg1, msg2); + + BoolOnlyMessage *msg1Prime = [[msg1 copy] autorelease]; + XCTAssertTrue(msg1Prime != msg1); // Different pointers. + XCTAssertEqual([msg1 hash], [msg1Prime hash]); + XCTAssertEqualObjects(msg1, msg1Prime); + + // Field set in one, but not the other means they don't match (even if + // set to default value). + msg1Prime.boolField2 = NO; + XCTAssertNotEqualObjects(msg1Prime, msg1); + // And when set to different values. + msg1.boolField2 = YES; + XCTAssertNotEqualObjects(msg1Prime, msg1); + // And then they match again. + msg1.boolField2 = NO; + XCTAssertEqualObjects(msg1Prime, msg1); + XCTAssertEqual([msg1 hash], [msg1Prime hash]); +} + @end diff --git a/objectivec/Tests/unittest_objc.proto b/objectivec/Tests/unittest_objc.proto index 6bcfbf70..f6ab6a24 100644 --- a/objectivec/Tests/unittest_objc.proto +++ b/objectivec/Tests/unittest_objc.proto @@ -411,3 +411,39 @@ message MessageWithOneBasedEnum { } optional OneBasedEnum enum_field = 1; } + +// Message with all bools for testing things related to bool storage. +message BoolOnlyMessage { + optional bool bool_field_1 = 1; + optional bool bool_field_2 = 2; + optional bool bool_field_3 = 3; + optional bool bool_field_4 = 4; + optional bool bool_field_5 = 5; + optional bool bool_field_6 = 6; + optional bool bool_field_7 = 7; + optional bool bool_field_8 = 8; + optional bool bool_field_9 = 9; + optional bool bool_field_10 = 10; + optional bool bool_field_11 = 11; + optional bool bool_field_12 = 12; + optional bool bool_field_13 = 13; + optional bool bool_field_14 = 14; + optional bool bool_field_15 = 15; + optional bool bool_field_16 = 16; + optional bool bool_field_17 = 17; + optional bool bool_field_18 = 18; + optional bool bool_field_19 = 19; + optional bool bool_field_20 = 20; + optional bool bool_field_21 = 21; + optional bool bool_field_22 = 22; + optional bool bool_field_23 = 23; + optional bool bool_field_24 = 24; + optional bool bool_field_25 = 25; + optional bool bool_field_26 = 26; + optional bool bool_field_27 = 27; + optional bool bool_field_28 = 28; + optional bool bool_field_29 = 29; + optional bool bool_field_30 = 30; + optional bool bool_field_31 = 31; + optional bool bool_field_32 = 32; +} From 2e83110230b7e91b07835e9c718a1d6fbcb8b617 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Wed, 27 Apr 2016 18:22:22 -0700 Subject: [PATCH 099/123] Added framework for generating/consuming benchmarking data sets. This takes the code that was sitting in benchmarks/ already and makes it easier for language-specific benchmarks to consume. Future PRs will enhance this so that the language-specific benchmarks can report metrics back that will be tracked over time in PerfKit. --- Makefile.am | 6 +- benchmarks/Makefile.am | 75 ++++++++++++ ....proto => benchmark_messages_proto2.proto} | 19 +-- benchmarks/benchmark_messages_proto3.proto | 76 ++++++++++++ benchmarks/benchmarks.proto | 102 ++++++++++++++++ benchmarks/generate_datasets.cc | 114 ++++++++++++++++++ configure.ac | 2 +- 7 files changed, 384 insertions(+), 10 deletions(-) create mode 100644 benchmarks/Makefile.am rename benchmarks/{google_speed.proto => benchmark_messages_proto2.proto} (91%) create mode 100644 benchmarks/benchmark_messages_proto3.proto create mode 100644 benchmarks/benchmarks.proto create mode 100644 benchmarks/generate_datasets.cc diff --git a/Makefile.am b/Makefile.am index a7a1f413..3e988816 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,7 +9,7 @@ AUTOMAKE_OPTIONS = foreign SUBDIRS = . src # Always include gmock in distributions. -DIST_SUBDIRS = $(subdirs) src conformance +DIST_SUBDIRS = $(subdirs) src conformance benchmarks # Build gmock before we build protobuf tests. We don't add gmock to SUBDIRS # because then "make check" would also build and run all of gmock's own tests, @@ -36,6 +36,10 @@ clean-local: echo "Making clean in conformance"; \ cd conformance && $(MAKE) $(AM_MAKEFLAGS) clean; \ fi; \ + if test -e benchmarks/Makefile; then \ + echo "Making clean in benchmarks"; \ + cd benchmarks && $(MAKE) $(AM_MAKEFLAGS) clean; \ + fi; \ if test -e objectivec/DevTools; then \ echo "Cleaning any ObjC pyc files"; \ rm -f objectivec/DevTools/*.pyc; \ diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am new file mode 100644 index 00000000..79581ee9 --- /dev/null +++ b/benchmarks/Makefile.am @@ -0,0 +1,75 @@ + +benchmarks_protoc_inputs = \ + benchmarks.proto \ + benchmark_messages_proto3.proto + +benchmarks_protoc_inputs_proto2 = \ + benchmark_messages_proto2.proto + +benchmarks_protoc_outputs = \ + benchmarks.pb.cc \ + benchmarks.pb.h \ + benchmark_messages_proto3.pb.cc \ + benchmark_messages_proto3.pb.h + +benchmarks_protoc_outputs_proto2 = \ + benchmark_messages_proto2.pb.cc \ + benchmark_messages_proto2.pb.h + +bin_PROGRAMS = generate-datasets + +generate_datasets_LDADD = $(top_srcdir)/src/libprotobuf.la +generate_datasets_SOURCES = generate_datasets.cc +generate_datasets_CPPFLAGS = -I$(top_srcdir)/src -I$(srcdir) +nodist_generate_datasets_SOURCES = \ + google_message1.h \ + google_message2.h \ + $(benchmarks_protoc_outputs) \ + $(benchmarks_protoc_outputs_proto2) + +# Explicit deps beacuse BUILT_SOURCES are only done before a "make all/check" +# so a direct "make test_cpp" could fail if parallel enough. +generate_datasets-generate_datasets.$(OBJEXT): benchmarks.pb.h google_message1.h google_message2.h + +$(benchmarks_protoc_outputs): protoc_middleman +$(benchmarks_protoc_outputs_proto2): protoc_middleman2 + +google_message1.h: google_message1.dat + xxd -i $< $@ + +google_message2.h: google_message2.dat + xxd -i $< $@ + +CLEANFILES = \ + $(benchmarks_protoc_outputs) \ + $(benchmarks_protoc_outputs_proto2) \ + google_message1.h \ + google_message2.h \ + protoc_middleman \ + protoc_middleman2 \ + dataset.* + +if USE_EXTERNAL_PROTOC + +protoc_middleman: $(benchmarks_protoc_inputs) + $(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. $(benchmarks_protoc_inputs) + touch protoc_middleman + +protoc_middleman2: $(benchmarks_protoc_inputs_proto2) + $(PROTOC) -I$(srcdir) -I$(top_srcdir) --cpp_out=. $(benchmarks_protoc_inputs_proto2) + touch protoc_middleman2 + +else + +# We have to cd to $(srcdir) before executing protoc because $(protoc_inputs) is +# relative to srcdir, which may not be the same as the current directory when +# building out-of-tree. +protoc_middleman: $(top_srcdir)/src/protoc$(EXEEXT) $(benchmarks_protoc_inputs) $(well_known_type_protoc_inputs) + oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd $(benchmarks_protoc_inputs) ) + touch protoc_middleman + +protoc_middleman2: $(top_srcdir)/src/protoc$(EXEEXT) $(benchmarks_protoc_inputs_proto2) $(well_known_type_protoc_inputs) + oldpwd=`pwd` && ( cd $(srcdir) && $$oldpwd/../src/protoc$(EXEEXT) -I. -I$(top_srcdir)/src --cpp_out=$$oldpwd $(benchmarks_protoc_inputs_proto2) ) + touch protoc_middleman + +endif diff --git a/benchmarks/google_speed.proto b/benchmarks/benchmark_messages_proto2.proto similarity index 91% rename from benchmarks/google_speed.proto rename to benchmarks/benchmark_messages_proto2.proto index 16f6d678..c7103be5 100644 --- a/benchmarks/google_speed.proto +++ b/benchmarks/benchmark_messages_proto2.proto @@ -1,11 +1,14 @@ +// Benchmark messages for proto2. + syntax = "proto2"; -package benchmarks; +package benchmarks.p2; +option java_package = "com.google.protobuf.benchmarks"; -option java_outer_classname = "GoogleSpeed"; +// This is the default, but we specify it here explicitly. option optimize_for = SPEED; -message SpeedMessage1 { +message GoogleMessage1 { required string field1 = 1; optional string field9 = 9; optional string field18 = 18; @@ -40,7 +43,7 @@ message SpeedMessage1 { optional int32 field23 = 23 [default=0]; optional bool field24 = 24 [default=false]; optional int32 field25 = 25 [default=0]; - optional SpeedMessage1SubMessage field15 = 15; + optional GoogleMessage1SubMessage field15 = 15; optional bool field78 = 78; optional int32 field67 = 67 [default=0]; optional int32 field68 = 68; @@ -49,7 +52,7 @@ message SpeedMessage1 { optional int32 field131 = 131 [default=0]; } -message SpeedMessage1SubMessage { +message GoogleMessage1SubMessage { optional int32 field1 = 1 [default=0]; optional int32 field2 = 2 [default=0]; optional int32 field3 = 3 [default=0]; @@ -72,7 +75,7 @@ message SpeedMessage1SubMessage { optional uint64 field300 = 300; } -message SpeedMessage2 { +message GoogleMessage2 { optional string field1 = 1; optional int64 field3 = 3; optional int64 field4 = 4; @@ -112,7 +115,7 @@ message SpeedMessage2 { repeated int32 field73 = 73; optional int32 field20 = 20 [default=0]; optional string field24 = 24; - optional SpeedMessage2GroupedMessage field31 = 31; + optional GoogleMessage2GroupedMessage field31 = 31; } repeated string field128 = 128; optional int64 field131 = 131; @@ -123,7 +126,7 @@ message SpeedMessage2 { optional bool field206 = 206 [default=false]; } -message SpeedMessage2GroupedMessage { +message GoogleMessage2GroupedMessage { optional float field1 = 1; optional float field2 = 2; optional float field3 = 3 [default=0.0]; diff --git a/benchmarks/benchmark_messages_proto3.proto b/benchmarks/benchmark_messages_proto3.proto new file mode 100644 index 00000000..4ea39c22 --- /dev/null +++ b/benchmarks/benchmark_messages_proto3.proto @@ -0,0 +1,76 @@ +// Benchmark messages for proto3. + +syntax = "proto3"; + +package benchmarks.p3; +option java_package = "com.google.protobuf.benchmarks"; + +// This is the default, but we specify it here explicitly. +option optimize_for = SPEED; + +message GoogleMessage1 { + string field1 = 1; + string field9 = 9; + string field18 = 18; + bool field80 = 80; + bool field81 = 81; + int32 field2 = 2; + int32 field3 = 3; + int32 field280 = 280; + int32 field6 = 6; + int64 field22 = 22; + string field4 = 4; + repeated fixed64 field5 = 5; + bool field59 = 59; + string field7 = 7; + int32 field16 = 16; + int32 field130 = 130; + bool field12 = 12; + bool field17 = 17; + bool field13 = 13; + bool field14 = 14; + int32 field104 = 104; + int32 field100 = 100; + int32 field101 = 101; + string field102 = 102; + string field103 = 103; + int32 field29 = 29; + bool field30 = 30; + int32 field60 = 60; + int32 field271 = 271; + int32 field272 = 272; + int32 field150 = 150; + int32 field23 = 23; + bool field24 = 24; + int32 field25 = 25; + GoogleMessage1SubMessage field15 = 15; + bool field78 = 78; + int32 field67 = 67; + int32 field68 = 68; + int32 field128 = 128; + string field129 = 129; + int32 field131 = 131; +} + +message GoogleMessage1SubMessage { + int32 field1 = 1; + int32 field2 = 2; + int32 field3 = 3; + string field15 = 15; + bool field12 = 12; + int64 field13 = 13; + int64 field14 = 14; + int32 field16 = 16; + int32 field19 = 19; + bool field20 = 20; + bool field28 = 28; + fixed64 field21 = 21; + int32 field22 = 22; + bool field23 = 23; + bool field206 = 206; + fixed32 field203 = 203; + int32 field204 = 204; + string field205 = 205; + uint64 field207 = 207; + uint64 field300 = 300; +} diff --git a/benchmarks/benchmarks.proto b/benchmarks/benchmarks.proto new file mode 100644 index 00000000..a891eb9e --- /dev/null +++ b/benchmarks/benchmarks.proto @@ -0,0 +1,102 @@ +// 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"; +package benchmarks; +option java_package = "com.google.protobuf.benchmarks"; + +message BenchmarkDataset { + // Name of the benchmark dataset. This should be unique across all datasets. + // Should only contain word characters: [a-zA-Z0-9_] + string name = 1; + + // Fully-qualified name of the protobuf message for this dataset. + // It will be one of the messages defined benchmark_messages.proto. + // Implementations that do not support reflection can implement this with + // an explicit "if/else" chain that lists every possible message defined + // in this file. + string message_name = 2; + + // The payload(s) for this dataset. They should be parsed or serialized + // in sequence, in a loop, ie. + // + // while (!benchmarkDone) { // Benchmark runner decides when to exit. + // for (i = 0; i < benchmark.payload.length; i++) { + // parse(benchmark.payload[i]) + // } + // } + // + // This is intended to let datasets include a variety of data to provide + // potentially more realistic results than just parsing the same message + // over and over. A single message parsed repeatedly could yield unusually + // good branch prediction performance. + repeated bytes payload = 3; +} + +// A benchmark can write out metrics that we will then upload to our metrics +// database for tracking over time. +message Metric { + // A unique ID for these results. Used for de-duping. + string guid = 1; + + // The tags specify exactly what benchmark was run against the dataset. + // The specific benchmark suite can decide what these mean, but here are + // some common tags that have a predefined meaning: + // + // - "dataset": for tests that pertain to a specific dataset. + // + // For example: + // + // # Tests parsing from binary proto string using arenas. + // tags={ + // dataset: "testalltypes", + // op: "parse", + // format: "binaryproto", + // input: "string" + // arena: "true" + // } + // + // # Tests serializing to JSON string. + // tags={ + // dataset: "testalltypes", + // op: "serialize", + // format: "json", + // input: "string" + // } + map labels = 2; + + // Unit of measurement for the metric: + // - a speed test might be "mb_per_second" or "ops_per_second" + // - a size test might be "kb". + string unit = 3; + + // Metric value. + double value = 4; +} diff --git a/benchmarks/generate_datasets.cc b/benchmarks/generate_datasets.cc new file mode 100644 index 00000000..f6f30cd8 --- /dev/null +++ b/benchmarks/generate_datasets.cc @@ -0,0 +1,114 @@ +// 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. + +const char *file_prefix = "dataset."; +const char *file_suffix = ".pb"; + +#include +#include +#include "benchmarks.pb.h" +#include "google_message1.h" +#include "google_message2.h" + +using benchmarks::BenchmarkDataset; +using google::protobuf::Descriptor; +using google::protobuf::DescriptorPool; +using google::protobuf::Message; +using google::protobuf::MessageFactory; + +#define ARRAY_TO_STRING(arr) std::string(arr, arr + sizeof(arr)) + +std::set names; + +void WriteFileWithPayloads(const std::string& name, + const std::string& message_name, + const std::vector& payload) { + if (!names.insert(name).second) { + std::cerr << "Duplicate test name: " << name << "\n"; + abort(); + } + + // First verify that this message name exists in our set of benchmark messages + // and that these payloads are valid for the given message. + const Descriptor* d = + DescriptorPool::generated_pool()->FindMessageTypeByName(message_name); + + if (!d) { + std::cerr << "For dataset " << name << ", no such message: " + << message_name << "\n"; + abort(); + } + + Message* m = MessageFactory::generated_factory()->GetPrototype(d)->New(); + + for (size_t i = 0; i < payload.size(); i++) { + if (!m->ParseFromString(payload[i])) { + std::cerr << "For dataset " << name << ", payload[" << i << "] fails " + << "to parse\n"; + abort(); + } + } + + BenchmarkDataset dataset; + dataset.set_name(name); + dataset.set_message_name(message_name); + for (size_t i = 0; i < payload.size(); i++) { + dataset.add_payload()->assign(payload[i]); + } + + std::string serialized; + dataset.SerializeToString(&serialized); + + std::ofstream writer; + std::string fname = file_prefix + name + file_suffix; + writer.open(fname); + writer << serialized; + writer.close(); + + std::cerr << "Wrote dataset: " << fname << "\n"; +} + +void WriteFile(const std::string& name, const std::string& message_name, + const std::string& payload) { + std::vector payloads; + payloads.push_back(payload); + WriteFileWithPayloads(name, message_name, payloads); +} + +int main() { + WriteFile("google_message1_proto3", "benchmarks.p3.GoogleMessage1", + ARRAY_TO_STRING(google_message1_dat)); + WriteFile("google_message1_proto2", "benchmarks.p2.GoogleMessage1", + ARRAY_TO_STRING(google_message1_dat)); + + // Not in proto3 because it has a group, which is not supported. + WriteFile("google_message2", "benchmarks.p2.GoogleMessage2", + ARRAY_TO_STRING(google_message2_dat)); +} diff --git a/configure.ac b/configure.ac index 33a6c64d..d56a7047 100644 --- a/configure.ac +++ b/configure.ac @@ -180,5 +180,5 @@ export CFLAGS export CXXFLAGS AC_CONFIG_SUBDIRS([gmock]) -AC_CONFIG_FILES([Makefile src/Makefile conformance/Makefile protobuf.pc protobuf-lite.pc]) +AC_CONFIG_FILES([Makefile src/Makefile benchmarks/Makefile conformance/Makefile protobuf.pc protobuf-lite.pc]) AC_OUTPUT From 30a2f70eb33a216c53c56f765f09aea63c0cf53b Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Wed, 27 Apr 2016 18:34:33 -0700 Subject: [PATCH 100/123] Added README describing the directory. --- benchmarks/README.md | 28 ++++++++++++++++++++++++++++ benchmarks/benchmarks.proto | 8 +++++--- 2 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 benchmarks/README.md diff --git a/benchmarks/README.md b/benchmarks/README.md new file mode 100644 index 00000000..c9027805 --- /dev/null +++ b/benchmarks/README.md @@ -0,0 +1,28 @@ + +# Protocol Buffers Benchmarks + +This directory contains benchmarking schemas and data sets that you +can use to test a variety of performance scenarios against your +protobuf language runtime. + +The schema for the datasets is described in `benchmarks.proto`. + +Generate the data sets like so: + +``` +$ make +$ ./generate-datasets +Wrote dataset: dataset.google_message1_proto3.pb +Wrote dataset: dataset.google_message1_proto2.pb +Wrote dataset: dataset.google_message2.pb +$ +``` + +Each data set will be written to its own file. Benchmarks will +likely want to run several benchmarks against each data set (parse, +serialize, possibly JSON, possibly using different APIs, etc). + +We would like to add more data sets. In general we will favor data sets +that make the overall suite diverse without being too large or having +too many similar tests. Ideally everyone can run through the entire +suite without the test run getting too long. diff --git a/benchmarks/benchmarks.proto b/benchmarks/benchmarks.proto index a891eb9e..5c2706df 100644 --- a/benchmarks/benchmarks.proto +++ b/benchmarks/benchmarks.proto @@ -38,10 +38,12 @@ message BenchmarkDataset { string name = 1; // Fully-qualified name of the protobuf message for this dataset. - // It will be one of the messages defined benchmark_messages.proto. + // It will be one of the messages defined benchmark_messages_proto2.proto + // or benchmark_messages_proto3.proto. + // // Implementations that do not support reflection can implement this with - // an explicit "if/else" chain that lists every possible message defined - // in this file. + // an explicit "if/else" chain that lists every known message defined + // in those files. string message_name = 2; // The payload(s) for this dataset. They should be parsed or serialized From cf14183bcd5485b4a71541599ddce0b35eb71352 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 28 Apr 2016 14:34:59 -0700 Subject: [PATCH 101/123] Down integrate from Google internal. --- .../com/google/protobuf/AbstractMessage.java | 48 +- .../google/protobuf/AbstractMessageLite.java | 79 +- .../com/google/protobuf/AbstractParser.java | 85 +- .../google/protobuf/AbstractProtobufList.java | 48 +- .../com/google/protobuf/BooleanArrayList.java | 73 +- .../google/protobuf/CodedOutputStream.java | 2368 +++++++++++++---- .../java/com/google/protobuf/Descriptors.java | 181 +- .../com/google/protobuf/DoubleArrayList.java | 65 +- .../com/google/protobuf/DynamicMessage.java | 40 +- .../java/com/google/protobuf/Extension.java | 1 + .../java/com/google/protobuf/FieldSet.java | 19 + .../com/google/protobuf/FloatArrayList.java | 64 +- .../com/google/protobuf/GeneratedMessage.java | 255 +- .../google/protobuf/GeneratedMessageLite.java | 1067 +++++++- .../com/google/protobuf/IntArrayList.java | 64 +- .../java/com/google/protobuf/Internal.java | 63 +- .../java/com/google/protobuf/LazyField.java | 12 +- .../com/google/protobuf/LazyFieldLite.java | 41 + .../google/protobuf/LazyStringArrayList.java | 48 +- .../com/google/protobuf/LongArrayList.java | 64 +- .../com/google/protobuf/MapEntryLite.java | 10 +- .../java/com/google/protobuf/MapField.java | 3 + .../java/com/google/protobuf/Message.java | 70 +- .../java/com/google/protobuf/MessageLite.java | 21 + .../google/protobuf/MessageLiteToString.java | 155 +- .../com/google/protobuf/MessageOrBuilder.java | 2 +- .../google/protobuf/MessageReflection.java | 107 +- .../google/protobuf/ProtobufArrayList.java | 22 +- .../google/protobuf/ProtocolMessageEnum.java | 1 + .../google/protobuf/RepeatedFieldBuilder.java | 8 +- .../java/com/google/protobuf/RpcUtil.java | 4 +- .../google/protobuf/SingleFieldBuilder.java | 2 +- .../com/google/protobuf/SmallSortedMap.java | 106 +- .../java/com/google/protobuf/TextFormat.java | 2 + .../com/google/protobuf/UnknownFieldSet.java | 77 +- .../protobuf/UnmodifiableLazyStringList.java | 50 +- .../java/com/google/protobuf/WireFormat.java | 19 +- .../google/protobuf/AbstractMessageTest.java | 41 +- .../google/protobuf/BooleanArrayListTest.java | 14 - .../google/protobuf/CodedInputStreamTest.java | 2 + .../protobuf/CodedOutputStreamTest.java | 786 ++++-- .../google/protobuf/DoubleArrayListTest.java | 14 - .../google/protobuf/FloatArrayListTest.java | 14 - .../protobuf/ForceFieldBuildersPreRun.java | 2 +- .../google/protobuf/GeneratedMessageTest.java | 8 +- .../com/google/protobuf/IntArrayListTest.java | 14 - .../java/com/google/protobuf/LiteTest.java | 692 ++++- .../google/protobuf/LongArrayListTest.java | 14 - .../java/com/google/protobuf/ParserTest.java | 16 +- .../protobuf/ProtobufArrayListTest.java | 14 - .../java/com/google/protobuf/ServiceTest.java | 20 +- .../google/protobuf/SmallSortedMapTest.java | 3 + .../java/com/google/protobuf/TestUtil.java | 409 +-- .../com/google/protobuf/TestUtilLite.java | 559 ++++ .../com/google/protobuf/TextFormatTest.java | 5 +- .../google/protobuf/UnknownFieldSetTest.java | 1 + .../com/google/protobuf/WireFormatTest.java | 10 +- .../protobuf/lite_equals_and_hash.proto | 3 - java/lite/generate-sources-build.xml | 20 + java/lite/generate-test-sources-build.xml | 43 + java/lite/pom.xml | 8 +- java/pom.xml | 2 + .../com/google/protobuf/AbstractMessage.java | 553 ++++ .../google/protobuf/AbstractMessageLite.java | 386 +++ .../com/google/protobuf/AbstractParser.java | 258 ++ .../google/protobuf/AbstractProtobufList.java | 180 ++ .../google/protobuf/BlockingRpcChannel.java | 51 + .../com/google/protobuf/BlockingService.java | 64 + .../google/protobuf/util/FieldMaskTree.java | 6 +- .../google/protobuf/util/FieldMaskUtil.java | 45 +- .../protobuf/util/FieldMaskTreeTest.java | 20 + .../protobuf/util/FieldMaskUtilTest.java | 9 + js/binary/utils.js | 50 + js/binary/utils_test.js | 35 + .../google/google/protobuf/Any.pbobjc.h | 134 + .../google/google/protobuf/Any.pbobjc.m | 93 + .../google/google/protobuf/Api.pbobjc.h | 262 ++ .../google/google/protobuf/Api.pbobjc.m | 348 +++ .../google/google/protobuf/Duration.pbobjc.h | 101 + .../google/google/protobuf/Duration.pbobjc.m | 88 + .../google/google/protobuf/Empty.pbobjc.h | 53 + .../google/google/protobuf/Empty.pbobjc.m | 64 + .../google/google/protobuf/FieldMask.pbobjc.h | 202 ++ .../google/google/protobuf/FieldMask.pbobjc.m | 77 + .../google/protobuf/SourceContext.pbobjc.h | 54 + .../google/protobuf/SourceContext.pbobjc.m | 77 + .../google/google/protobuf/Struct.pbobjc.h | 167 ++ .../google/google/protobuf/Struct.pbobjc.m | 273 ++ .../google/google/protobuf/Timestamp.pbobjc.h | 113 + .../google/google/protobuf/Timestamp.pbobjc.m | 88 + .../google/google/protobuf/Type.pbobjc.h | 373 +++ .../google/google/protobuf/Type.pbobjc.m | 693 +++++ .../google/google/protobuf/Wrappers.pbobjc.h | 182 ++ .../google/google/protobuf/Wrappers.pbobjc.m | 420 +++ php/tests/autoload.php | 4 + python/google/protobuf/descriptor.py | 9 +- python/google/protobuf/descriptor_pool.py | 4 +- .../protobuf/internal/api_implementation.py | 6 + .../protobuf/internal/descriptor_pool_test.py | 46 +- .../internal/descriptor_pool_test2.proto | 1 + .../protobuf/internal/message_factory_test.py | 54 + .../google/protobuf/internal/message_test.py | 36 +- .../protobuf/internal/proto_builder_test.py | 1 + .../protobuf/internal/python_message.py | 76 +- .../protobuf/internal/reflection_test.py | 12 +- .../protobuf/internal/text_format_test.py | 93 + .../google/protobuf/internal/type_checkers.py | 23 +- .../protobuf/internal/unknown_fields_test.py | 20 + .../protobuf/internal/well_known_types.py | 8 +- .../internal/well_known_types_test.py | 8 + python/google/protobuf/message.py | 3 + python/google/protobuf/pyext/descriptor.cc | 11 +- .../google/protobuf/pyext/descriptor_pool.cc | 8 +- .../google/protobuf/pyext/descriptor_pool.h | 11 +- .../google/protobuf/pyext/extension_dict.cc | 19 +- python/google/protobuf/pyext/extension_dict.h | 6 + python/google/protobuf/pyext/map_container.cc | 17 +- python/google/protobuf/pyext/map_container.h | 7 +- python/google/protobuf/pyext/message.cc | 120 +- python/google/protobuf/pyext/message.h | 33 +- .../pyext/repeated_composite_container.cc | 14 +- .../pyext/repeated_composite_container.h | 7 +- python/google/protobuf/text_format.py | 804 +++--- src/google/protobuf/any.pb.cc | 12 +- src/google/protobuf/any.pb.h | 2 + src/google/protobuf/any.proto | 2 + src/google/protobuf/api.pb.cc | 38 +- src/google/protobuf/api.pb.h | 8 + src/google/protobuf/arena.cc | 14 + src/google/protobuf/arena.h | 10 +- src/google/protobuf/arena_unittest.cc | 58 + src/google/protobuf/arenastring_unittest.cc | 3 - .../compiler/command_line_interface.cc | 15 +- .../compiler/command_line_interface.h | 1 + .../command_line_interface_unittest.cc | 6 +- .../compiler/cpp/cpp_bootstrap_unittest.cc | 1 + src/google/protobuf/compiler/cpp/cpp_enum.cc | 36 +- src/google/protobuf/compiler/cpp/cpp_enum.h | 11 +- .../protobuf/compiler/cpp/cpp_enum_field.cc | 40 +- .../protobuf/compiler/cpp/cpp_enum_field.h | 11 +- src/google/protobuf/compiler/cpp/cpp_field.cc | 3 + src/google/protobuf/compiler/cpp/cpp_field.h | 8 +- src/google/protobuf/compiler/cpp/cpp_file.cc | 122 +- src/google/protobuf/compiler/cpp/cpp_file.h | 5 +- .../protobuf/compiler/cpp/cpp_generator.cc | 6 +- .../protobuf/compiler/cpp/cpp_helpers.cc | 69 +- .../protobuf/compiler/cpp/cpp_helpers.h | 83 +- .../protobuf/compiler/cpp/cpp_map_field.cc | 65 +- .../protobuf/compiler/cpp/cpp_map_field.h | 3 +- .../protobuf/compiler/cpp/cpp_message.cc | 338 +-- .../compiler/cpp/cpp_message_field.cc | 100 +- .../protobuf/compiler/cpp/cpp_message_field.h | 12 +- .../protobuf/compiler/cpp/cpp_options.h | 7 +- .../compiler/cpp/cpp_plugin_unittest.cc | 3 +- .../compiler/cpp/cpp_primitive_field.cc | 35 +- .../compiler/cpp/cpp_primitive_field.h | 12 +- .../protobuf/compiler/cpp/cpp_string_field.cc | 93 +- .../protobuf/compiler/cpp/cpp_string_field.h | 12 +- .../protobuf/compiler/cpp/cpp_unittest.cc | 2 +- .../protobuf/compiler/cpp/metadata_test.cc | 3 +- .../protobuf/compiler/importer_unittest.cc | 13 +- .../compiler/java/java_doc_comment.cc | 66 +- .../protobuf/compiler/java/java_enum.cc | 69 +- .../compiler/java/java_enum_field_lite.cc | 89 +- .../compiler/java/java_enum_field_lite.h | 6 +- .../protobuf/compiler/java/java_field.h | 2 +- .../java/java_lazy_message_field_lite.cc | 27 +- .../java/java_lazy_message_field_lite.h | 4 +- .../protobuf/compiler/java/java_map_field.cc | 4 +- .../compiler/java/java_map_field_lite.cc | 4 +- .../compiler/java/java_map_field_lite.h | 2 +- .../protobuf/compiler/java/java_message.cc | 4 +- .../compiler/java/java_message_field_lite.cc | 50 +- .../compiler/java/java_message_field_lite.h | 6 +- .../compiler/java/java_message_lite.cc | 368 +-- .../compiler/java/java_message_lite.h | 5 +- .../compiler/java/java_plugin_unittest.cc | 3 +- .../java/java_primitive_field_lite.cc | 56 +- .../compiler/java/java_primitive_field_lite.h | 6 +- .../compiler/java/java_string_field_lite.cc | 47 +- .../compiler/java/java_string_field_lite.h | 6 +- .../protobuf/compiler/js/js_generator.cc | 5 +- src/google/protobuf/compiler/plugin.pb.cc | 36 +- src/google/protobuf/compiler/plugin.pb.h | 6 + .../compiler/python/python_plugin_unittest.cc | 3 +- src/google/protobuf/descriptor.cc | 33 +- src/google/protobuf/descriptor.pb.cc | 280 +- src/google/protobuf/descriptor.pb.h | 129 +- src/google/protobuf/descriptor_unittest.cc | 12 - src/google/protobuf/duration.pb.cc | 10 +- src/google/protobuf/empty.pb.cc | 10 +- src/google/protobuf/field_mask.pb.cc | 11 +- src/google/protobuf/field_mask.pb.h | 1 + src/google/protobuf/field_mask.proto | 2 +- .../protobuf/generated_message_reflection.cc | 54 +- .../protobuf/generated_message_reflection.h | 12 +- src/google/protobuf/generated_message_util.h | 4 +- .../protobuf/io/coded_stream_unittest.cc | 1 - .../protobuf/io/zero_copy_stream_impl_lite.h | 2 +- .../protobuf/io/zero_copy_stream_unittest.cc | 4 +- src/google/protobuf/map.h | 41 +- src/google/protobuf/map_field.cc | 25 +- src/google/protobuf/map_field.h | 7 +- src/google/protobuf/map_field_inl.h | 20 +- src/google/protobuf/map_field_test.cc | 2 +- src/google/protobuf/map_test.cc | 24 +- src/google/protobuf/message_lite.cc | 5 + src/google/protobuf/repeated_field.h | 7 + src/google/protobuf/source_context.pb.cc | 11 +- src/google/protobuf/source_context.pb.h | 1 + src/google/protobuf/struct.pb.cc | 34 +- src/google/protobuf/struct.pb.h | 3 + src/google/protobuf/text_format.cc | 12 +- src/google/protobuf/text_format_unittest.cc | 3 +- src/google/protobuf/timestamp.pb.cc | 10 +- src/google/protobuf/type.pb.cc | 62 +- src/google/protobuf/type.pb.h | 81 +- src/google/protobuf/util/field_comparator.cc | 22 +- .../util/internal/protostream_objectsource.cc | 24 +- .../util/internal/protostream_objectsource.h | 19 + .../internal/protostream_objectsource_test.cc | 29 + .../util/internal/protostream_objectwriter.cc | 91 +- .../util/internal/protostream_objectwriter.h | 11 +- .../internal/protostream_objectwriter_test.cc | 218 ++ .../util/internal/testdata/books.proto | 9 + .../protobuf/util/message_differencer.cc | 6 +- src/google/protobuf/wrappers.pb.cc | 98 +- src/google/protobuf/wrappers.pb.h | 8 +- 228 files changed, 14751 insertions(+), 3871 deletions(-) create mode 100644 java/core/src/test/java/com/google/protobuf/TestUtilLite.java create mode 100644 java/lite/generate-sources-build.xml create mode 100644 java/lite/generate-test-sources-build.xml create mode 100644 java/src/main/java/com/google/protobuf/AbstractMessage.java create mode 100644 java/src/main/java/com/google/protobuf/AbstractMessageLite.java create mode 100644 java/src/main/java/com/google/protobuf/AbstractParser.java create mode 100644 java/src/main/java/com/google/protobuf/AbstractProtobufList.java create mode 100644 java/src/main/java/com/google/protobuf/BlockingRpcChannel.java create mode 100644 java/src/main/java/com/google/protobuf/BlockingService.java create mode 100644 objectivec/google/google/protobuf/Any.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Any.pbobjc.m create mode 100644 objectivec/google/google/protobuf/Api.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Api.pbobjc.m create mode 100644 objectivec/google/google/protobuf/Duration.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Duration.pbobjc.m create mode 100644 objectivec/google/google/protobuf/Empty.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Empty.pbobjc.m create mode 100644 objectivec/google/google/protobuf/FieldMask.pbobjc.h create mode 100644 objectivec/google/google/protobuf/FieldMask.pbobjc.m create mode 100644 objectivec/google/google/protobuf/SourceContext.pbobjc.h create mode 100644 objectivec/google/google/protobuf/SourceContext.pbobjc.m create mode 100644 objectivec/google/google/protobuf/Struct.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Struct.pbobjc.m create mode 100644 objectivec/google/google/protobuf/Timestamp.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Timestamp.pbobjc.m create mode 100644 objectivec/google/google/protobuf/Type.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Type.pbobjc.m create mode 100644 objectivec/google/google/protobuf/Wrappers.pbobjc.h create mode 100644 objectivec/google/google/protobuf/Wrappers.pbobjc.m create mode 100644 php/tests/autoload.php diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java index 9f418f2b..03c0d579 100644 --- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java +++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java @@ -50,17 +50,23 @@ import java.util.Map; * * @author kenton@google.com Kenton Varda */ -public abstract class AbstractMessage extends AbstractMessageLite - implements Message { +public abstract class AbstractMessage + // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType. + extends AbstractMessageLite + implements Message { + + @Override public boolean isInitialized() { return MessageReflection.isInitialized(this); } + @Override public List findInitializationErrors() { return MessageReflection.findMissingFields(this); } + @Override public String getInitializationErrorString() { return MessageReflection.delimitWithCommas(findInitializationErrors()); } @@ -83,12 +89,14 @@ public abstract class AbstractMessage extends AbstractMessageLite return TextFormat.printToString(this); } + @Override public void writeTo(final CodedOutputStream output) throws IOException { MessageReflection.writeMessageTo(this, getAllFields(), output, false); } protected int memoizedSize = -1; + @Override public int getSerializedSize() { int size = memoizedSize; if (size != -1) { @@ -288,8 +296,8 @@ public abstract class AbstractMessage extends AbstractMessageLite * other methods. */ @SuppressWarnings("unchecked") - public static abstract class Builder - extends AbstractMessageLite.Builder + public static abstract class Builder> + extends AbstractMessageLite.Builder implements Message.Builder { // The compiler produces an error if this is not declared explicitly. @Override @@ -314,6 +322,7 @@ public abstract class AbstractMessage extends AbstractMessageLite throw new UnsupportedOperationException("clearOneof() is not implemented."); } + @Override public BuilderType clear() { for (final Map.Entry entry : getAllFields().entrySet()) { @@ -322,14 +331,22 @@ public abstract class AbstractMessage extends AbstractMessageLite return (BuilderType) this; } + @Override public List findInitializationErrors() { return MessageReflection.findMissingFields(this); } + @Override public String getInitializationErrorString() { return MessageReflection.delimitWithCommas(findInitializationErrors()); } + + @Override + protected BuilderType internalMergeFrom(AbstractMessageLite other) { + return mergeFrom((Message) other); + } + @Override public BuilderType mergeFrom(final Message other) { if (other.getDescriptorForType() != getDescriptorForType()) { throw new IllegalArgumentException( @@ -407,6 +424,7 @@ public abstract class AbstractMessage extends AbstractMessageLite return (BuilderType) this; } + @Override public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { setUnknownFields( UnknownFieldSet.newBuilder(getUnknownFields()) @@ -415,17 +433,19 @@ public abstract class AbstractMessage extends AbstractMessageLite return (BuilderType) this; } + @Override public Message.Builder getFieldBuilder(final FieldDescriptor field) { throw new UnsupportedOperationException( "getFieldBuilder() called on an unsupported message type."); } - public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, - int index) { + @Override + public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) { throw new UnsupportedOperationException( "getRepeatedFieldBuilder() called on an unsupported message type."); } + @Override public String toString() { return TextFormat.printToString(this); } @@ -462,7 +482,7 @@ public abstract class AbstractMessage extends AbstractMessageLite @Override public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException { - return super.mergeFrom(data); + return (BuilderType) super.mergeFrom(data); } @Override @@ -470,20 +490,20 @@ public abstract class AbstractMessage extends AbstractMessageLite final ByteString data, final ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { - return super.mergeFrom(data, extensionRegistry); + return (BuilderType) super.mergeFrom(data, extensionRegistry); } @Override public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException { - return super.mergeFrom(data); + return (BuilderType) super.mergeFrom(data); } @Override public BuilderType mergeFrom( final byte[] data, final int off, final int len) throws InvalidProtocolBufferException { - return super.mergeFrom(data, off, len); + return (BuilderType) super.mergeFrom(data, off, len); } @Override @@ -491,7 +511,7 @@ public abstract class AbstractMessage extends AbstractMessageLite final byte[] data, final ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { - return super.mergeFrom(data, extensionRegistry); + return (BuilderType) super.mergeFrom(data, extensionRegistry); } @Override @@ -499,13 +519,13 @@ public abstract class AbstractMessage extends AbstractMessageLite final byte[] data, final int off, final int len, final ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { - return super.mergeFrom(data, off, len, extensionRegistry); + return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry); } @Override public BuilderType mergeFrom(final InputStream input) throws IOException { - return super.mergeFrom(input); + return (BuilderType) super.mergeFrom(input); } @Override @@ -513,7 +533,7 @@ public abstract class AbstractMessage extends AbstractMessageLite final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { - return super.mergeFrom(input, extensionRegistry); + return (BuilderType) super.mergeFrom(input, extensionRegistry); } @Override diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java index 12384983..43736dd1 100644 --- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java @@ -43,9 +43,13 @@ import java.util.Collection; * * @author kenton@google.com Kenton Varda */ -public abstract class AbstractMessageLite implements MessageLite { +public abstract class AbstractMessageLite< + MessageType extends AbstractMessageLite, + BuilderType extends AbstractMessageLite.Builder> + implements MessageLite { protected int memoizedHashCode = 0; - + + @Override public ByteString toByteString() { try { final ByteString.CodedBuilder out = @@ -59,6 +63,7 @@ public abstract class AbstractMessageLite implements MessageLite { } } + @Override public byte[] toByteArray() { try { final byte[] result = new byte[getSerializedSize()]; @@ -73,6 +78,7 @@ public abstract class AbstractMessageLite implements MessageLite { } } + @Override public void writeTo(final OutputStream output) throws IOException { final int bufferSize = CodedOutputStream.computePreferredBufferSize(getSerializedSize()); @@ -82,6 +88,7 @@ public abstract class AbstractMessageLite implements MessageLite { codedOutput.flush(); } + @Override public void writeDelimitedTo(final OutputStream output) throws IOException { final int serialized = getSerializedSize(); final int bufferSize = CodedOutputStream.computePreferredBufferSize( @@ -120,25 +127,27 @@ public abstract class AbstractMessageLite implements MessageLite { * other methods. */ @SuppressWarnings("unchecked") - public static abstract class Builder + public abstract static class Builder< + MessageType extends AbstractMessageLite, + BuilderType extends Builder> implements MessageLite.Builder { // The compiler produces an error if this is not declared explicitly. @Override public abstract BuilderType clone(); - public BuilderType mergeFrom(final CodedInputStream input) - throws IOException { + @Override + public BuilderType mergeFrom(final CodedInputStream input) throws IOException { return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry()); } // Re-defined here for return type covariance. + @Override public abstract BuilderType mergeFrom( - final CodedInputStream input, - final ExtensionRegistryLite extensionRegistry) + final CodedInputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException; - public BuilderType mergeFrom(final ByteString data) - throws InvalidProtocolBufferException { + @Override + public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException { try { final CodedInputStream input = data.newCodedInput(); mergeFrom(input); @@ -153,9 +162,9 @@ public abstract class AbstractMessageLite implements MessageLite { } } + @Override public BuilderType mergeFrom( - final ByteString data, - final ExtensionRegistryLite extensionRegistry) + final ByteString data, final ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { try { final CodedInputStream input = data.newCodedInput(); @@ -171,14 +180,14 @@ public abstract class AbstractMessageLite implements MessageLite { } } - public BuilderType mergeFrom(final byte[] data) - throws InvalidProtocolBufferException { + @Override + public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException { return mergeFrom(data, 0, data.length); } - public BuilderType mergeFrom(final byte[] data, final int off, - final int len) - throws InvalidProtocolBufferException { + @Override + public BuilderType mergeFrom(final byte[] data, final int off, final int len) + throws InvalidProtocolBufferException { try { final CodedInputStream input = CodedInputStream.newInstance(data, off, len); @@ -194,15 +203,17 @@ public abstract class AbstractMessageLite implements MessageLite { } } - public BuilderType mergeFrom( - final byte[] data, - final ExtensionRegistryLite extensionRegistry) + @Override + public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return mergeFrom(data, 0, data.length, extensionRegistry); } + @Override public BuilderType mergeFrom( - final byte[] data, final int off, final int len, + final byte[] data, + final int off, + final int len, final ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { try { @@ -220,6 +231,7 @@ public abstract class AbstractMessageLite implements MessageLite { } } + @Override public BuilderType mergeFrom(final InputStream input) throws IOException { final CodedInputStream codedInput = CodedInputStream.newInstance(input); mergeFrom(codedInput); @@ -227,10 +239,9 @@ public abstract class AbstractMessageLite implements MessageLite { return (BuilderType) this; } + @Override public BuilderType mergeFrom( - final InputStream input, - final ExtensionRegistryLite extensionRegistry) - throws IOException { + final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { final CodedInputStream codedInput = CodedInputStream.newInstance(input); mergeFrom(codedInput, extensionRegistry); codedInput.checkLastTagWas(0); @@ -292,10 +303,9 @@ public abstract class AbstractMessageLite implements MessageLite { } } + @Override public boolean mergeDelimitedFrom( - final InputStream input, - final ExtensionRegistryLite extensionRegistry) - throws IOException { + final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { final int firstByte = input.read(); if (firstByte == -1) { return false; @@ -306,11 +316,24 @@ public abstract class AbstractMessageLite implements MessageLite { return true; } - public boolean mergeDelimitedFrom(final InputStream input) - throws IOException { + @Override + public boolean mergeDelimitedFrom(final InputStream input) throws IOException { return mergeDelimitedFrom(input, ExtensionRegistryLite.getEmptyRegistry()); } + + @Override + @SuppressWarnings("unchecked") // isInstance takes care of this + public BuilderType mergeFrom(final MessageLite other) { + if (!getDefaultInstanceForType().getClass().isInstance(other)) { + throw new IllegalArgumentException( + "mergeFrom(MessageLite) can only merge messages of the same type."); + } + + return internalMergeFrom((MessageType) other); + } + + protected abstract BuilderType internalMergeFrom(MessageType message); /** * Construct an UninitializedMessageException reporting missing fields in diff --git a/java/core/src/main/java/com/google/protobuf/AbstractParser.java b/java/core/src/main/java/com/google/protobuf/AbstractParser.java index 1a4c6311..66b0ee3b 100644 --- a/java/core/src/main/java/com/google/protobuf/AbstractParser.java +++ b/java/core/src/main/java/com/google/protobuf/AbstractParser.java @@ -78,26 +78,27 @@ public abstract class AbstractParser private static final ExtensionRegistryLite EMPTY_REGISTRY = ExtensionRegistryLite.getEmptyRegistry(); + @Override public MessageType parsePartialFrom(CodedInputStream input) throws InvalidProtocolBufferException { return parsePartialFrom(input, EMPTY_REGISTRY); } - public MessageType parseFrom(CodedInputStream input, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return checkMessageInitialized( parsePartialFrom(input, extensionRegistry)); } - public MessageType parseFrom(CodedInputStream input) - throws InvalidProtocolBufferException { + @Override + public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException { return parseFrom(input, EMPTY_REGISTRY); } - public MessageType parsePartialFrom(ByteString data, - ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { + @Override + public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { MessageType message; try { CodedInputStream input = data.newCodedInput(); @@ -113,24 +114,25 @@ public abstract class AbstractParser } } - public MessageType parsePartialFrom(ByteString data) - throws InvalidProtocolBufferException { + @Override + public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException { return parsePartialFrom(data, EMPTY_REGISTRY); } - public MessageType parseFrom(ByteString data, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return checkMessageInitialized(parsePartialFrom(data, extensionRegistry)); } - public MessageType parseFrom(ByteString data) - throws InvalidProtocolBufferException { + @Override + public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException { return parseFrom(data, EMPTY_REGISTRY); } - public MessageType parsePartialFrom(byte[] data, int off, int len, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parsePartialFrom( + byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { try { CodedInputStream input = CodedInputStream.newInstance(data, off, len); @@ -146,47 +148,50 @@ public abstract class AbstractParser } } + @Override public MessageType parsePartialFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException { return parsePartialFrom(data, off, len, EMPTY_REGISTRY); } - public MessageType parsePartialFrom(byte[] data, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return parsePartialFrom(data, 0, data.length, extensionRegistry); } - public MessageType parsePartialFrom(byte[] data) - throws InvalidProtocolBufferException { + @Override + public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException { return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY); } - public MessageType parseFrom(byte[] data, int off, int len, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parseFrom( + byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return checkMessageInitialized( parsePartialFrom(data, off, len, extensionRegistry)); } + @Override public MessageType parseFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException { return parseFrom(data, off, len, EMPTY_REGISTRY); } - public MessageType parseFrom(byte[] data, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return parseFrom(data, 0, data.length, extensionRegistry); } - public MessageType parseFrom(byte[] data) - throws InvalidProtocolBufferException { + @Override + public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException { return parseFrom(data, EMPTY_REGISTRY); } - public MessageType parsePartialFrom(InputStream input, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { CodedInputStream codedInput = CodedInputStream.newInstance(input); MessageType message = parsePartialFrom(codedInput, extensionRegistry); @@ -198,26 +203,26 @@ public abstract class AbstractParser return message; } - public MessageType parsePartialFrom(InputStream input) - throws InvalidProtocolBufferException { + @Override + public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException { return parsePartialFrom(input, EMPTY_REGISTRY); } - public MessageType parseFrom(InputStream input, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return checkMessageInitialized( parsePartialFrom(input, extensionRegistry)); } - public MessageType parseFrom(InputStream input) - throws InvalidProtocolBufferException { + @Override + public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException { return parseFrom(input, EMPTY_REGISTRY); } + @Override public MessageType parsePartialDelimitedFrom( - InputStream input, - ExtensionRegistryLite extensionRegistry) + InputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { int size; try { @@ -233,21 +238,21 @@ public abstract class AbstractParser return parsePartialFrom(limitedInput, extensionRegistry); } + @Override public MessageType parsePartialDelimitedFrom(InputStream input) throws InvalidProtocolBufferException { return parsePartialDelimitedFrom(input, EMPTY_REGISTRY); } - public MessageType parseDelimitedFrom( - InputStream input, - ExtensionRegistryLite extensionRegistry) + @Override + public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { return checkMessageInitialized( parsePartialDelimitedFrom(input, extensionRegistry)); } - public MessageType parseDelimitedFrom(InputStream input) - throws InvalidProtocolBufferException { + @Override + public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException { return parseDelimitedFrom(input, EMPTY_REGISTRY); } } 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 bb6446b2..b17db6e0 100644 --- a/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java +++ b/java/core/src/main/java/com/google/protobuf/AbstractProtobufList.java @@ -34,19 +34,25 @@ import com.google.protobuf.Internal.ProtobufList; import java.util.AbstractList; import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; /** * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate - * methods are check if the list is mutable before proceeding. Subclasses must invoke + * methods must check if the list is mutable before proceeding. Subclasses must invoke * {@link #ensureIsMutable()} manually when overriding those methods. + *

+ * This implementation assumes all subclasses are array based, supporting random access. */ abstract class AbstractProtobufList extends AbstractList implements ProtobufList { + protected static final int DEFAULT_CAPACITY = 10; + /** * Whether or not this list is modifiable. */ private boolean isMutable; - + /** * Constructs a mutable list by default. */ @@ -54,6 +60,44 @@ abstract class AbstractProtobufList extends AbstractList implements Protob isMutable = true; } + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof List)) { + return false; + } + // Handle lists that do not support RandomAccess as efficiently as possible by using an iterator + // based approach in our super class. Otherwise our index based approach will avoid those + // allocations. + if (!(o instanceof RandomAccess)) { + return super.equals(o); + } + + List other = (List) o; + final int size = size(); + if (size != other.size()) { + return false; + } + for (int i = 0; i < size; i++) { + if (!get(i).equals(other.get(i))) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + final int size = size(); + int hashCode = 1; + for (int i = 0; i < size; i++) { + hashCode = (31 * hashCode) + get(i).hashCode(); + } + return hashCode; + } + @Override public boolean add(E e) { ensureIsMutable(); 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 70e042f5..8b2820b6 100644 --- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java @@ -34,7 +34,6 @@ import com.google.protobuf.Internal.BooleanList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.RandomAccess; /** @@ -45,8 +44,6 @@ import java.util.RandomAccess; final class BooleanArrayList extends AbstractProtobufList implements BooleanList, RandomAccess { - private static final int DEFAULT_CAPACITY = 10; - private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList(); static { EMPTY_LIST.makeImmutable(); @@ -60,7 +57,7 @@ final class BooleanArrayList * The backing store for the list. */ private boolean[] array; - + /** * The size of the list distinct from the length of the array. That is, it is the number of * elements set in the list. @@ -71,35 +68,57 @@ final class BooleanArrayList * Constructs a new mutable {@code BooleanArrayList} with default capacity. */ BooleanArrayList() { - this(DEFAULT_CAPACITY); + this(new boolean[DEFAULT_CAPACITY], 0); } /** - * Constructs a new mutable {@code BooleanArrayList} with the provided capacity. + * Constructs a new mutable {@code BooleanArrayList}. */ - BooleanArrayList(int capacity) { - array = new boolean[capacity]; - size = 0; - } - - /** - * Constructs a new mutable {@code BooleanArrayList} containing the same elements as - * {@code other}. - */ - BooleanArrayList(List other) { - if (other instanceof BooleanArrayList) { - BooleanArrayList list = (BooleanArrayList) other; - array = list.array.clone(); - size = list.size; - } else { - size = other.size(); - array = new boolean[size]; - for (int i = 0; i < size; i++) { - array[i] = other.get(i); - } - } + private BooleanArrayList(boolean[] array, int size) { + this.array = array; + this.size = size; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof BooleanArrayList)) { + return super.equals(o); + } + BooleanArrayList other = (BooleanArrayList) o; + if (size != other.size) { + return false; + } + + final boolean[] arr = other.array; + for (int i = 0; i < size; i++) { + if (array[i] != arr[i]) { + return false; + } + } + + return true; + } + + @Override + public int hashCode() { + int result = 1; + for (int i = 0; i < size; i++) { + result = (31 * result) + Internal.hashBoolean(array[i]); + } + return result; + } + + @Override + public BooleanList mutableCopyWithCapacity(int capacity) { + if (capacity < size) { + throw new IllegalArgumentException(); + } + return new BooleanArrayList(Arrays.copyOf(array, capacity), size); + } + @Override public Boolean get(int index) { return getBoolean(index); diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java index b92394b8..ad174d0f 100644 --- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java +++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java @@ -30,11 +30,18 @@ package com.google.protobuf; +import static java.lang.Math.max; + import com.google.protobuf.Utf8.UnpairedSurrogateException; import java.io.IOException; import java.io.OutputStream; +import java.lang.reflect.Field; +import java.nio.BufferOverflowException; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; import java.util.logging.Level; import java.util.logging.Logger; @@ -50,23 +57,21 @@ import java.util.logging.Logger; * *

This class is totally unsynchronized. */ -public final class CodedOutputStream { +public abstract class CodedOutputStream extends ByteOutput { private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName()); + private static final sun.misc.Unsafe UNSAFE = getUnsafe(); + private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations(); + private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset(); - private static final int LITTLE_ENDIAN_64_SIZE = 8; + private static final int FIXED_32_SIZE = 4; + private static final int FIXED_64_SIZE = 8; + private static final int MAX_VARINT_SIZE = 10; /** * @deprecated Use {@link #computeFixed32SizeNoTag(int)} instead. */ - @Deprecated public static final int LITTLE_ENDIAN_32_SIZE = 4; - - // TODO(dweis): Consider migrating to a ByteBuffer. - private final byte[] buffer; - private final int limit; - private int position; - private int totalBytesWritten = 0; - - private final OutputStream output; + @Deprecated + public static final int LITTLE_ENDIAN_32_SIZE = FIXED_32_SIZE; /** * The buffer size used in {@link #newInstance(OutputStream)}. @@ -87,34 +92,27 @@ public final class CodedOutputStream { return dataLength; } - private CodedOutputStream(final byte[] buffer, final int offset, final int length) { - output = null; - this.buffer = buffer; - position = offset; - limit = offset + length; - } - - private CodedOutputStream(final OutputStream output, final byte[] buffer) { - this.output = output; - this.buffer = buffer; - position = 0; - limit = buffer.length; - } - /** - * Create a new {@code CodedOutputStream} wrapping the given - * {@code OutputStream}. + * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream}. + * + *

NOTE: The provided {@link OutputStream} MUST NOT retain access or + * modify the provided byte arrays. Doing so may result in corrupted data, which would be + * difficult to debug. */ public static CodedOutputStream newInstance(final OutputStream output) { return newInstance(output, DEFAULT_BUFFER_SIZE); } /** - * Create a new {@code CodedOutputStream} wrapping the given - * {@code OutputStream} with a given buffer size. + * Create a new {@code CodedOutputStream} wrapping the given {@code OutputStream} with a given + * buffer size. + * + *

NOTE: The provided {@link OutputStream} MUST NOT retain access or + * modify the provided byte arrays. Doing so may result in corrupted data, which would be + * difficult to debug. */ public static CodedOutputStream newInstance(final OutputStream output, final int bufferSize) { - return new CodedOutputStream(output, new byte[bufferSize]); + return new OutputStreamEncoder(output, bufferSize); } /** @@ -137,160 +135,144 @@ public final class CodedOutputStream { */ public static CodedOutputStream newInstance( final byte[] flatArray, final int offset, final int length) { - return new CodedOutputStream(flatArray, offset, length); + return new ArrayEncoder(flatArray, offset, length); } /** - * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer. + * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}. */ public static CodedOutputStream newInstance(ByteBuffer byteBuffer) { - return newInstance(byteBuffer, DEFAULT_BUFFER_SIZE); + if (byteBuffer.hasArray()) { + return new NioHeapEncoder(byteBuffer); + } + return new NioEncoder(byteBuffer); } /** - * Create a new {@code CodedOutputStream} that writes to the given ByteBuffer. + * Create a new {@code CodedOutputStream} that writes to the given {@link ByteBuffer}. + * + * @deprecated the size parameter is no longer used since use of an internal buffer is useless + * (and wasteful) when writing to a {@link ByteBuffer}. Use {@link #newInstance(ByteBuffer)} + * instead. */ - public static CodedOutputStream newInstance(ByteBuffer byteBuffer, int bufferSize) { - return newInstance(new ByteBufferOutputStream(byteBuffer), bufferSize); + @Deprecated + public static CodedOutputStream newInstance(ByteBuffer byteBuffer, + @SuppressWarnings("unused") int unused) { + return newInstance(byteBuffer); } - private static class ByteBufferOutputStream extends OutputStream { - private final ByteBuffer byteBuffer; - - public ByteBufferOutputStream(ByteBuffer byteBuffer) { - this.byteBuffer = byteBuffer; + /** + * Create a new {@code CodedOutputStream} that writes to the provided {@link ByteOutput}. + * + *

NOTE: The {@link ByteOutput} MUST NOT modify the provided buffers. Doing + * so may result in corrupted data, which would be difficult to debug. + * + * @param byteOutput the output target for encoded bytes. + * @param bufferSize the size of the internal scratch buffer to be used for string encoding. + * Setting this to {@code 0} will disable buffering, requiring an allocation for each encoded + * string. + */ + static CodedOutputStream newInstance(ByteOutput byteOutput, int bufferSize) { + if (bufferSize < 0) { + throw new IllegalArgumentException("bufferSize must be positive"); } - @Override - public void write(int b) throws IOException { - byteBuffer.put((byte) b); - } + return new ByteOutputEncoder(byteOutput, bufferSize); + } - @Override - public void write(byte[] data, int offset, int length) throws IOException { - byteBuffer.put(data, offset, length); - } + // Disallow construction outside of this class. + private CodedOutputStream() { } // ----------------------------------------------------------------- /** Encode and write a tag. */ - public void writeTag(final int fieldNumber, final int wireType) throws IOException { - writeRawVarint32(WireFormat.makeTag(fieldNumber, wireType)); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeTag(int fieldNumber, int wireType) throws IOException; /** Write an {@code int32} field, including tag, to the stream. */ - public void writeInt32(final int fieldNumber, final int value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeInt32NoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeInt32(int fieldNumber, int value) throws IOException; /** Write a {@code uint32} field, including tag, to the stream. */ - public void writeUInt32(final int fieldNumber, final int value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeUInt32NoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeUInt32(int fieldNumber, int value) throws IOException; /** Write a {@code sint32} field, including tag, to the stream. */ - public void writeSInt32(final int fieldNumber, final int value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeSInt32NoTag(value); + public final void writeSInt32(final int fieldNumber, final int value) throws IOException { + writeUInt32(fieldNumber, encodeZigZag32(value)); } /** Write a {@code fixed32} field, including tag, to the stream. */ - public void writeFixed32(final int fieldNumber, final int value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeFixed32NoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeFixed32(int fieldNumber, int value) throws IOException; /** Write an {@code sfixed32} field, including tag, to the stream. */ - public void writeSFixed32(final int fieldNumber, final int value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeSFixed32NoTag(value); + public final void writeSFixed32(final int fieldNumber, final int value) throws IOException { + writeFixed32(fieldNumber, value); } /** Write an {@code int64} field, including tag, to the stream. */ - public void writeInt64(final int fieldNumber, final long value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeInt64NoTag(value); + public final void writeInt64(final int fieldNumber, final long value) throws IOException { + writeUInt64(fieldNumber, value); } /** Write a {@code uint64} field, including tag, to the stream. */ - public void writeUInt64(final int fieldNumber, final long value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeUInt64NoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeUInt64(int fieldNumber, long value) throws IOException; /** Write an {@code sint64} field, including tag, to the stream. */ - public void writeSInt64(final int fieldNumber, final long value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeSInt64NoTag(value); + public final void writeSInt64(final int fieldNumber, final long value) throws IOException { + writeUInt64(fieldNumber, encodeZigZag64(value)); } /** Write a {@code fixed64} field, including tag, to the stream. */ - public void writeFixed64(final int fieldNumber, final long value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeFixed64NoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeFixed64(int fieldNumber, long value) throws IOException; /** Write an {@code sfixed64} field, including tag, to the stream. */ - public void writeSFixed64(final int fieldNumber, final long value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeSFixed64NoTag(value); + public final void writeSFixed64(final int fieldNumber, final long value) throws IOException { + writeFixed64(fieldNumber, value); } /** Write a {@code float} field, including tag, to the stream. */ - public void writeFloat(final int fieldNumber, final float value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); - writeFloatNoTag(value); + public final void writeFloat(final int fieldNumber, final float value) throws IOException { + writeFixed32(fieldNumber, Float.floatToRawIntBits(value)); } /** Write a {@code double} field, including tag, to the stream. */ - public void writeDouble(final int fieldNumber, final double value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); - writeDoubleNoTag(value); + public final void writeDouble(final int fieldNumber, final double value) throws IOException { + writeFixed64(fieldNumber, Double.doubleToRawLongBits(value)); } /** Write a {@code bool} field, including tag, to the stream. */ - public void writeBool(final int fieldNumber, final boolean value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeBoolNoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeBool(int fieldNumber, boolean value) throws IOException; /** * Write an enum field, including tag, to the stream. The provided value is the numeric * value used to represent the enum value on the wire (not the enum ordinal value). */ - public void writeEnum(final int fieldNumber, final int value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); - writeEnumNoTag(value); + public final void writeEnum(final int fieldNumber, final int value) throws IOException { + writeInt32(fieldNumber, value); } /** Write a {@code string} field, including tag, to the stream. */ - public void writeString(final int fieldNumber, final String value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeStringNoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeString(int fieldNumber, String value) throws IOException; /** Write a {@code bytes} field, including tag, to the stream. */ - public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeBytesNoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeBytes(int fieldNumber, ByteString value) throws IOException; /** Write a {@code bytes} field, including tag, to the stream. */ - public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeByteArrayNoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeByteArray(int fieldNumber, byte[] value) throws IOException; /** Write a {@code bytes} field, including tag, to the stream. */ - public void writeByteArray( - final int fieldNumber, final byte[] value, final int offset, final int length) - throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeByteArrayNoTag(value, offset, length); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeByteArray(int fieldNumber, byte[] value, int offset, int length) + throws IOException; /** * Write a {@code bytes} field, including tag, to the stream. @@ -302,67 +284,36 @@ public final class CodedOutputStream { * of a ByteBuffer, you can call * {@code writeByteBuffer(fieldNumber, byteBuffer.slice())}. */ - public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeByteBufferNoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeByteBuffer(int fieldNumber, ByteBuffer value) throws IOException; - /** Write a single byte. */ - public void writeRawByte(final byte value) throws IOException { - if (position == limit) { - refreshBuffer(); - } - - buffer[position++] = value; - ++totalBytesWritten; + /** + * Write a single byte. + */ + public final void writeRawByte(final byte value) throws IOException { + write(value); } /** Write a single byte, represented by an integer value. */ - public void writeRawByte(final int value) throws IOException { - writeRawByte((byte) value); + public final void writeRawByte(final int value) throws IOException { + write((byte) value); } /** Write an array of bytes. */ - public void writeRawBytes(final byte[] value) throws IOException { - writeRawBytes(value, 0, value.length); + public final void writeRawBytes(final byte[] value) throws IOException { + write(value, 0, value.length); } - /** Write part of an array of bytes. */ - public void writeRawBytes(final byte[] value, int offset, int length) throws IOException { - if (limit - position >= length) { - // We have room in the current buffer. - System.arraycopy(value, offset, buffer, position, length); - position += length; - totalBytesWritten += length; - } else { - // Write extends past current buffer. Fill the rest of this buffer and - // flush. - final int bytesWritten = limit - position; - System.arraycopy(value, offset, buffer, position, bytesWritten); - offset += bytesWritten; - length -= bytesWritten; - position = limit; - totalBytesWritten += bytesWritten; - refreshBuffer(); - - // Now deal with the rest. - // Since we have an output stream, this is our buffer - // and buffer offset == 0 - if (length <= limit) { - // Fits in new buffer. - System.arraycopy(value, offset, buffer, 0, length); - position = length; - } else { - // Write is very big. Let's do it all at once. - output.write(value, offset, length); - } - totalBytesWritten += length; - } + /** + * Write part of an array of bytes. + */ + public final void writeRawBytes(final byte[] value, int offset, int length) throws IOException { + write(value, offset, length); } /** Write a byte string. */ - public void writeRawBytes(final ByteString value) throws IOException { - writeRawBytes(value, 0, value.size()); + public final void writeRawBytes(final ByteString value) throws IOException { + value.writeTo(this); } /** @@ -374,155 +325,138 @@ public final class CodedOutputStream { * write the remaining bytes of a ByteBuffer, you can call * {@code writeRawBytes(byteBuffer.slice())}. */ - public void writeRawBytes(final ByteBuffer value) throws IOException { - if (value.hasArray()) { - writeRawBytes(value.array(), value.arrayOffset(), value.capacity()); - } else { - ByteBuffer duplicated = value.duplicate(); - duplicated.clear(); - writeRawBytesInternal(duplicated); - } - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeRawBytes(final ByteBuffer value) throws IOException; /** Write an embedded message field, including tag, to the stream. */ - public void writeMessage(final int fieldNumber, final MessageLite value) throws IOException { - writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); - writeMessageNoTag(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeMessage(final int fieldNumber, final MessageLite value) + throws IOException; /** * Write a MessageSet extension field to the stream. For historical reasons, * the wire format differs from normal fields. */ - public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) - throws IOException { - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); - writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); - writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeMessageSetExtension(final int fieldNumber, final MessageLite value) + throws IOException; /** * Write an unparsed MessageSet extension field to the stream. For * historical reasons, the wire format differs from normal fields. */ - public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) - throws IOException { - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); - writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); - writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); - writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) + throws IOException; // ----------------------------------------------------------------- /** Write an {@code int32} field to the stream. */ - public void writeInt32NoTag(final int value) throws IOException { - if (value >= 0) { - writeRawVarint32(value); - } else { - // Must sign-extend. - writeRawVarint64(value); - } - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeInt32NoTag(final int value) throws IOException; /** Write a {@code uint32} field to the stream. */ - public void writeUInt32NoTag(final int value) throws IOException { - writeRawVarint32(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeUInt32NoTag(int value) throws IOException; /** Write a {@code sint32} field to the stream. */ - public void writeSInt32NoTag(final int value) throws IOException { - writeRawVarint32(encodeZigZag32(value)); + public final void writeSInt32NoTag(final int value) throws IOException { + writeUInt32NoTag(encodeZigZag32(value)); } /** Write a {@code fixed32} field to the stream. */ - public void writeFixed32NoTag(final int value) throws IOException { - writeRawLittleEndian32(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeFixed32NoTag(int value) throws IOException; /** Write a {@code sfixed32} field to the stream. */ - public void writeSFixed32NoTag(final int value) throws IOException { - writeRawLittleEndian32(value); + public final void writeSFixed32NoTag(final int value) throws IOException { + writeFixed32NoTag(value); } /** Write an {@code int64} field to the stream. */ - public void writeInt64NoTag(final long value) throws IOException { - writeRawVarint64(value); + public final void writeInt64NoTag(final long value) throws IOException { + writeUInt64NoTag(value); } /** Write a {@code uint64} field to the stream. */ - public void writeUInt64NoTag(final long value) throws IOException { - writeRawVarint64(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeUInt64NoTag(long value) throws IOException; /** Write a {@code sint64} field to the stream. */ - public void writeSInt64NoTag(final long value) throws IOException { - writeRawVarint64(encodeZigZag64(value)); + public final void writeSInt64NoTag(final long value) throws IOException { + writeUInt64NoTag(encodeZigZag64(value)); } /** Write a {@code fixed64} field to the stream. */ - public void writeFixed64NoTag(final long value) throws IOException { - writeRawLittleEndian64(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeFixed64NoTag(long value) throws IOException; /** Write a {@code sfixed64} field to the stream. */ - public void writeSFixed64NoTag(final long value) throws IOException { - writeRawLittleEndian64(value); + public final void writeSFixed64NoTag(final long value) throws IOException { + writeFixed64NoTag(value); } /** Write a {@code float} field to the stream. */ - public void writeFloatNoTag(final float value) throws IOException { - writeRawLittleEndian32(Float.floatToRawIntBits(value)); + public final void writeFloatNoTag(final float value) throws IOException { + writeFixed32NoTag(Float.floatToRawIntBits(value)); } /** Write a {@code double} field to the stream. */ - public void writeDoubleNoTag(final double value) throws IOException { - writeRawLittleEndian64(Double.doubleToRawLongBits(value)); + public final void writeDoubleNoTag(final double value) throws IOException { + writeFixed64NoTag(Double.doubleToRawLongBits(value)); } /** Write a {@code bool} field to the stream. */ - public void writeBoolNoTag(final boolean value) throws IOException { - writeRawByte(value ? 1 : 0); + public final void writeBoolNoTag(final boolean value) throws IOException { + write((byte) (value ? 1 : 0)); } /** * Write an enum field to the stream. The provided value is the numeric * value used to represent the enum value on the wire (not the enum ordinal value). */ - public void writeEnumNoTag(final int value) throws IOException { + public final void writeEnumNoTag(final int value) throws IOException { writeInt32NoTag(value); } /** Write a {@code string} field to the stream. */ // TODO(dweis): Document behavior on ill-formed UTF-16 input. - public void writeStringNoTag(final String value) throws IOException { - try { - efficientWriteStringNoTag(value); - } catch (UnpairedSurrogateException e) { - logger.log(Level.WARNING, - "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", e); - inefficientWriteStringNoTag(value); - } - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeStringNoTag(String value) throws IOException; /** Write a {@code bytes} field to the stream. */ - public void writeBytesNoTag(final ByteString value) throws IOException { - writeRawVarint32(value.size()); - writeRawBytes(value); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeBytesNoTag(final ByteString value) throws IOException; /** Write a {@code bytes} field to the stream. */ - public void writeByteArrayNoTag(final byte[] value) throws IOException { - writeRawVarint32(value.length); - writeRawBytes(value); + public final void writeByteArrayNoTag(final byte[] value) throws IOException { + writeByteArrayNoTag(value, 0, value.length); } /** Write an embedded message field to the stream. */ - public void writeMessageNoTag(final MessageLite value) throws IOException { - writeRawVarint32(value.getSerializedSize()); - value.writeTo(this); - } + // Abstract to avoid overhead of additional virtual method calls. + public abstract void writeMessageNoTag(final MessageLite value) throws IOException; + + //================================================================= + + @ExperimentalApi + @Override + public abstract void write(byte value) throws IOException; + + @ExperimentalApi + @Override + public abstract void write(byte[] value, int offset, int length) throws IOException; + + @ExperimentalApi + @Override + public abstract void writeLazy(byte[] value, int offset, int length) throws IOException; + + @Override + public abstract void write(ByteBuffer value) throws IOException; + + @ExperimentalApi + @Override + public abstract void writeLazy(ByteBuffer value) throws IOException; // ================================================================= // ================================================================= @@ -727,7 +661,7 @@ public final class CodedOutputStream { /** Compute the number of bytes that would be needed to encode a tag. */ public static int computeTagSize(final int fieldNumber) { - return computeRawVarint32Size(WireFormat.makeTag(fieldNumber, 0)); + return computeUInt32SizeNoTag(WireFormat.makeTag(fieldNumber, 0)); } /** @@ -736,10 +670,10 @@ public final class CodedOutputStream { */ public static int computeInt32SizeNoTag(final int value) { if (value >= 0) { - return computeRawVarint32Size(value); + return computeUInt32SizeNoTag(value); } else { // Must sign-extend. - return 10; + return MAX_VARINT_SIZE; } } @@ -748,7 +682,19 @@ public final class CodedOutputStream { * {@code uint32} field. */ public static int computeUInt32SizeNoTag(final int value) { - return computeRawVarint32Size(value); + if ((value & (~0 << 7)) == 0) { + return 1; + } + if ((value & (~0 << 14)) == 0) { + return 2; + } + if ((value & (~0 << 21)) == 0) { + return 3; + } + if ((value & (~0 << 28)) == 0) { + return 4; + } + return 5; } /** @@ -756,7 +702,7 @@ public final class CodedOutputStream { * {@code sint32} field. */ public static int computeSInt32SizeNoTag(final int value) { - return computeRawVarint32Size(encodeZigZag32(value)); + return computeUInt32SizeNoTag(encodeZigZag32(value)); } /** @@ -764,7 +710,7 @@ public final class CodedOutputStream { * {@code fixed32} field. */ public static int computeFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { - return LITTLE_ENDIAN_32_SIZE; + return FIXED_32_SIZE; } /** @@ -772,7 +718,7 @@ public final class CodedOutputStream { * {@code sfixed32} field. */ public static int computeSFixed32SizeNoTag(@SuppressWarnings("unused") final int unused) { - return LITTLE_ENDIAN_32_SIZE; + return FIXED_32_SIZE; } /** @@ -780,15 +726,33 @@ public final class CodedOutputStream { * {@code int64} field, including tag. */ public static int computeInt64SizeNoTag(final long value) { - return computeRawVarint64Size(value); + return computeUInt64SizeNoTag(value); } /** * Compute the number of bytes that would be needed to encode a * {@code uint64} field, including tag. */ - public static int computeUInt64SizeNoTag(final long value) { - return computeRawVarint64Size(value); + public static int computeUInt64SizeNoTag(long value) { + // handle two popular special cases up front ... + if ((value & (~0L << 7)) == 0L) { + return 1; + } + if (value < 0L) { + return 10; + } + // ... leaving us with 8 remaining, which we can divide and conquer + int n = 2; + if ((value & (~0L << 35)) != 0L) { + n += 4; value >>>= 28; + } + if ((value & (~0L << 21)) != 0L) { + n += 2; value >>>= 14; + } + if ((value & (~0L << 14)) != 0L) { + n += 1; + } + return n; } /** @@ -796,7 +760,7 @@ public final class CodedOutputStream { * {@code sint64} field. */ public static int computeSInt64SizeNoTag(final long value) { - return computeRawVarint64Size(encodeZigZag64(value)); + return computeUInt64SizeNoTag(encodeZigZag64(value)); } /** @@ -804,7 +768,7 @@ public final class CodedOutputStream { * {@code fixed64} field. */ public static int computeFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { - return LITTLE_ENDIAN_64_SIZE; + return FIXED_64_SIZE; } /** @@ -812,7 +776,7 @@ public final class CodedOutputStream { * {@code sfixed64} field. */ public static int computeSFixed64SizeNoTag(@SuppressWarnings("unused") final long unused) { - return LITTLE_ENDIAN_64_SIZE; + return FIXED_64_SIZE; } /** @@ -820,7 +784,7 @@ public final class CodedOutputStream { * {@code float} field, including tag. */ public static int computeFloatSizeNoTag(@SuppressWarnings("unused") final float unused) { - return LITTLE_ENDIAN_32_SIZE; + return FIXED_32_SIZE; } /** @@ -828,7 +792,7 @@ public final class CodedOutputStream { * {@code double} field, including tag. */ public static int computeDoubleSizeNoTag(@SuppressWarnings("unused") final double unused) { - return LITTLE_ENDIAN_64_SIZE; + return FIXED_64_SIZE; } /** @@ -862,7 +826,7 @@ public final class CodedOutputStream { length = bytes.length; } - return computeRawVarint32Size(length) + length; + return computeLengthDelimitedFieldSize(length); } /** @@ -870,8 +834,7 @@ public final class CodedOutputStream { * message stored in lazy field. */ public static int computeLazyFieldSizeNoTag(final LazyFieldLite value) { - final int size = value.getSerializedSize(); - return computeRawVarint32Size(size) + size; + return computeLengthDelimitedFieldSize(value.getSerializedSize()); } /** @@ -879,7 +842,7 @@ public final class CodedOutputStream { * {@code bytes} field. */ public static int computeBytesSizeNoTag(final ByteString value) { - return computeRawVarint32Size(value.size()) + value.size(); + return computeLengthDelimitedFieldSize(value.size()); } /** @@ -887,7 +850,7 @@ public final class CodedOutputStream { * {@code bytes} field. */ public static int computeByteArraySizeNoTag(final byte[] value) { - return computeRawVarint32Size(value.length) + value.length; + return computeLengthDelimitedFieldSize(value.length); } /** @@ -895,7 +858,7 @@ public final class CodedOutputStream { * {@code bytes} field. */ public static int computeByteBufferSizeNoTag(final ByteBuffer value) { - return computeRawVarint32Size(value.capacity()) + value.capacity(); + return computeLengthDelimitedFieldSize(value.capacity()); } /** @@ -903,8 +866,11 @@ public final class CodedOutputStream { * message field. */ public static int computeMessageSizeNoTag(final MessageLite value) { - final int size = value.getSerializedSize(); - return computeRawVarint32Size(size) + size; + return computeLengthDelimitedFieldSize(value.getSerializedSize()); + } + + private static int computeLengthDelimitedFieldSize(int fieldLength) { + return computeUInt32SizeNoTag(fieldLength) + fieldLength; } /** @@ -943,25 +909,13 @@ public final class CodedOutputStream { * Flushes the stream and forces any buffered bytes to be written. This * does not flush the underlying OutputStream. */ - public void flush() throws IOException { - if (output != null) { - refreshBuffer(); - } - } + public abstract void flush() throws IOException; /** * If writing to a flat array, return the space left in the array. * Otherwise, throws {@code UnsupportedOperationException}. */ - public int spaceLeft() { - if (output == null) { - return limit - position; - } else { - throw new UnsupportedOperationException( - "spaceLeft() can only be called on CodedOutputStreams that are " - + "writing to a flat array."); - } - } + public abstract int spaceLeft(); /** * Verifies that {@link #spaceLeft()} returns zero. It's common to create @@ -970,7 +924,7 @@ public final class CodedOutputStream { * after writing verifies that the message was actually as big as expected, * which can help catch bugs. */ - public void checkNoSpaceLeft() { + public final void checkNoSpaceLeft() { if (spaceLeft() != 0) { throw new IllegalStateException("Did not write as much data as expected."); } @@ -1001,183 +955,31 @@ public final class CodedOutputStream { * returned value is not guaranteed to be accurate if exceptions have been * found in the middle of writing. */ - public int getTotalBytesWritten() { - return totalBytesWritten; - } + public abstract int getTotalBytesWritten(); // ================================================================= - /** - * Internal helper that writes the current buffer to the output. The - * buffer position is reset to its initial value when this returns. - */ - private void refreshBuffer() throws IOException { - if (output == null) { - // We're writing to a single buffer. - throw new OutOfSpaceException(); - } + /** Write a {@code bytes} field to the stream. Visible for testing. */ + abstract void writeByteArrayNoTag(final byte[] value, final int offset, final int length) + throws IOException; - // Since we have an output stream, this is our buffer - // and buffer offset == 0 - output.write(buffer, 0, position); - position = 0; - } + final void inefficientWriteStringNoTag(String value, UnpairedSurrogateException cause) + throws IOException { + logger.log(Level.WARNING, + "Converting ill-formed UTF-16. Your Protocol Buffer will not round trip correctly!", cause); - /** Write a {@code string} field to the stream. */ - private void inefficientWriteStringNoTag(final String value) throws IOException { // Unfortunately there does not appear to be any way to tell Java to encode // UTF-8 directly into our buffer, so we have to let it create its own byte // array and then copy. // TODO(dweis): Consider using nio Charset methods instead. final byte[] bytes = value.getBytes(Internal.UTF_8); - writeRawVarint32(bytes.length); - writeRawBytes(bytes); - } - - /** - * Write a {@code string} field to the stream efficiently. If the {@code string} is malformed, - * this method rolls back its changes and throws an {@link UnpairedSurrogateException} with the - * intent that the caller will catch and retry with {@link #inefficientWriteStringNoTag(String)}. - * - * @param value the string to write to the stream - * - * @throws UnpairedSurrogateException when {@code value} is ill-formed UTF-16. - */ - private void efficientWriteStringNoTag(final String value) throws IOException { - // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), - // and at most 3 times of it. We take advantage of this in both branches below. - final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; - final int maxLengthVarIntSize = computeRawVarint32Size(maxLength); - - // If we are streaming and the potential length is too big to fit in our buffer, we take the - // slower path. Otherwise, we're good to try the fast path. - if (output != null && maxLengthVarIntSize + maxLength > limit - position) { - // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes() - // does the same internally and then does *another copy* to return a byte[] of exactly the - // right size. We can skip that copy and just writeRawBytes up to the actualLength of the - // UTF-8 encoded bytes. - final byte[] encodedBytes = new byte[maxLength]; - int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength); - writeRawVarint32(actualLength); - writeRawBytes(encodedBytes, 0, actualLength); - } else { - // Optimize for the case where we know this length results in a constant varint length as this - // saves a pass for measuring the length of the string. - final int minLengthVarIntSize = computeRawVarint32Size(value.length()); - int oldPosition = position; - final int length; - try { - if (minLengthVarIntSize == maxLengthVarIntSize) { - position = oldPosition + minLengthVarIntSize; - int newPosition = Utf8.encode(value, buffer, position, limit - position); - // Since this class is stateful and tracks the position, we rewind and store the state, - // prepend the length, then reset it back to the end of the string. - position = oldPosition; - length = newPosition - oldPosition - minLengthVarIntSize; - writeRawVarint32(length); - position = newPosition; - } else { - length = Utf8.encodedLength(value); - writeRawVarint32(length); - position = Utf8.encode(value, buffer, position, limit - position); - } - } catch (UnpairedSurrogateException e) { - // Be extra careful and restore the original position for retrying the write with the less - // efficient path. - position = oldPosition; - throw e; - } catch (ArrayIndexOutOfBoundsException e) { - throw new OutOfSpaceException(e); - } - totalBytesWritten += length; - } - } - - /** Write a ByteBuffer that isn't backed by an array. */ - private void writeRawBytesInternal(final ByteBuffer value) throws IOException { - int length = value.remaining(); - if (limit - position >= length) { - // We have room in the current buffer. - value.get(buffer, position, length); - position += length; - totalBytesWritten += length; - } else { - // Write extends past current buffer. Fill the rest of this buffer and - // flush. - final int bytesWritten = limit - position; - value.get(buffer, position, bytesWritten); - length -= bytesWritten; - position = limit; - totalBytesWritten += bytesWritten; - refreshBuffer(); - - // Now deal with the rest. - // Since we have an output stream, this is our buffer - // and buffer offset == 0 - while (length > limit) { - // Copy data into the buffer before writing it to OutputStream. - // TODO(xiaofeng): Introduce ZeroCopyOutputStream to avoid this copy. - value.get(buffer, 0, limit); - output.write(buffer, 0, limit); - length -= limit; - totalBytesWritten += limit; - } - value.get(buffer, 0, length); - position = length; - totalBytesWritten += length; - } - } - - /** Write a {@code bytes} field to the stream. Visible for testing. */ - void writeByteArrayNoTag(final byte[] value, final int offset, final int length) - throws IOException { - writeRawVarint32(length); - writeRawBytes(value, offset, length); - } - - /** - * Write a {@code bytes} field to the stream. This method will write all - * content of the ByteBuffer regardless of the current position and limit - * (i.e., the number of bytes to be written is value.capacity(), not - * value.remaining()). Furthermore, this method doesn't alter the state of - * the passed-in ByteBuffer. Its position, limit, mark, etc. will remain - * unchanged. If you only want to write the remaining bytes of a ByteBuffer, - * you can call {@code writeByteBufferNoTag(byteBuffer.slice())}. - */ - private void writeByteBufferNoTag(final ByteBuffer value) throws IOException { - writeRawVarint32(value.capacity()); - writeRawBytes(value); - } - - /** Write part of a byte string. */ - private void writeRawBytes(final ByteString value, int offset, int length) throws IOException { - if (limit - position >= length) { - // We have room in the current buffer. - value.copyTo(buffer, offset, position, length); - position += length; - totalBytesWritten += length; - } else { - // Write extends past current buffer. Fill the rest of this buffer and - // flush. - final int bytesWritten = limit - position; - value.copyTo(buffer, offset, position, bytesWritten); - offset += bytesWritten; - length -= bytesWritten; - position = limit; - totalBytesWritten += bytesWritten; - refreshBuffer(); - - // Now deal with the rest. - // Since we have an output stream, this is our buffer - // and buffer offset == 0 - if (length <= limit) { - // Fits in new buffer. - value.copyTo(buffer, offset, 0, length); - position = length; - } else { - value.writeTo(output, offset, length); - } - totalBytesWritten += length; + try { + writeUInt32NoTag(bytes.length); + writeLazy(bytes, 0, bytes.length); + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException(e); + } catch (OutOfSpaceException e) { + throw e; } } @@ -1189,7 +991,7 @@ public final class CodedOutputStream { * @deprecated groups are deprecated. */ @Deprecated - public void writeGroup(final int fieldNumber, final MessageLite value) throws IOException { + public final void writeGroup(final int fieldNumber, final MessageLite value) throws IOException { writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP); writeGroupNoTag(value); writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP); @@ -1201,7 +1003,7 @@ public final class CodedOutputStream { * @deprecated groups are deprecated. */ @Deprecated - public void writeGroupNoTag(final MessageLite value) throws IOException { + public final void writeGroupNoTag(final MessageLite value) throws IOException { value.writeTo(this); } @@ -1232,16 +1034,8 @@ public final class CodedOutputStream { * @deprecated use {@link #writeUInt32NoTag} instead. */ @Deprecated - public void writeRawVarint32(int value) throws IOException { - while (true) { - if ((value & ~0x7F) == 0) { - writeRawByte(value); - return; - } else { - writeRawByte((value & 0x7F) | 0x80); - value >>>= 7; - } - } + public final void writeRawVarint32(int value) throws IOException { + writeUInt32NoTag(value); } /** @@ -1250,16 +1044,8 @@ public final class CodedOutputStream { * @deprecated use {@link #writeUInt64NoTag} instead. */ @Deprecated - public void writeRawVarint64(long value) throws IOException { - while (true) { - if ((value & ~0x7FL) == 0) { - writeRawByte((int) value); - return; - } else { - writeRawByte(((int) value & 0x7F) | 0x80); - value >>>= 7; - } - } + public final void writeRawVarint64(long value) throws IOException { + writeUInt64NoTag(value); } /** @@ -1271,19 +1057,7 @@ public final class CodedOutputStream { */ @Deprecated public static int computeRawVarint32Size(final int value) { - if ((value & (~0 << 7)) == 0) { - return 1; - } - if ((value & (~0 << 14)) == 0) { - return 2; - } - if ((value & (~0 << 21)) == 0) { - return 3; - } - if ((value & (~0 << 28)) == 0) { - return 4; - } - return 5; + return computeUInt32SizeNoTag(value); } /** @@ -1293,27 +1067,7 @@ public final class CodedOutputStream { */ @Deprecated public static int computeRawVarint64Size(long value) { - // handle two popular special cases up front ... - if ((value & (~0L << 7)) == 0L) { - return 1; - } - if (value < 0L) { - return 10; - } - // ... leaving us with 8 remaining, which we can divide and conquer - int n = 2; - if ((value & (~0L << 35)) != 0L) { - n += 4; - value >>>= 28; - } - if ((value & (~0L << 21)) != 0L) { - n += 2; - value >>>= 14; - } - if ((value & (~0L << 14)) != 0L) { - n += 1; - } - return n; + return computeUInt64SizeNoTag(value); } /** @@ -1322,11 +1076,8 @@ public final class CodedOutputStream { * @deprecated Use {@link #writeFixed32NoTag} instead. */ @Deprecated - public void writeRawLittleEndian32(final int value) throws IOException { - writeRawByte((value) & 0xFF); - writeRawByte((value >> 8) & 0xFF); - writeRawByte((value >> 16) & 0xFF); - writeRawByte((value >> 24) & 0xFF); + public final void writeRawLittleEndian32(final int value) throws IOException { + writeFixed32NoTag(value); } /** @@ -1335,14 +1086,1579 @@ public final class CodedOutputStream { * @deprecated Use {@link #writeFixed64NoTag} instead. */ @Deprecated - public void writeRawLittleEndian64(final long value) throws IOException { - writeRawByte((int) (value) & 0xFF); - writeRawByte((int) (value >> 8) & 0xFF); - writeRawByte((int) (value >> 16) & 0xFF); - writeRawByte((int) (value >> 24) & 0xFF); - writeRawByte((int) (value >> 32) & 0xFF); - writeRawByte((int) (value >> 40) & 0xFF); - writeRawByte((int) (value >> 48) & 0xFF); - writeRawByte((int) (value >> 56) & 0xFF); + public final void writeRawLittleEndian64(final long value) throws IOException { + writeFixed64NoTag(value); + } + + // ================================================================= + + /** + * A {@link CodedOutputStream} that writes directly to a byte array. + */ + private static class ArrayEncoder extends CodedOutputStream { + private final byte[] buffer; + private final int offset; + private final int limit; + private int position; + + ArrayEncoder(byte[] buffer, int offset, int length) { + if (buffer == null) { + throw new NullPointerException("buffer"); + } + if ((offset | length | (buffer.length - (offset + length))) < 0) { + throw new IllegalArgumentException(String.format( + "Array range is invalid. Buffer.length=%d, offset=%d, length=%d", + buffer.length, offset, length)); + } + this.buffer = buffer; + this.offset = offset; + position = offset; + limit = offset + length; + } + + @Override + public final void writeTag(final int fieldNumber, final int wireType) throws IOException { + writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + public final void writeInt32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeInt32NoTag(value); + } + + @Override + public final void writeUInt32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeUInt32NoTag(value); + } + + @Override + public final void writeFixed32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); + writeFixed32NoTag(value); + } + + @Override + public final void writeUInt64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeUInt64NoTag(value); + } + + @Override + public final void writeFixed64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); + writeFixed64NoTag(value); + } + + @Override + public final void writeBool(final int fieldNumber, final boolean value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + write((byte) (value ? 1 : 0)); + } + + @Override + public final void writeString(final int fieldNumber, final String value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeStringNoTag(value); + } + + @Override + public final void writeBytes(final int fieldNumber, final ByteString value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeBytesNoTag(value); + } + + @Override + public final void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { + writeByteArray(fieldNumber, value, 0, value.length); + } + + @Override + public final void writeByteArray( + final int fieldNumber, final byte[] value, final int offset, final int length) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeByteArrayNoTag(value, offset, length); + } + + @Override + public final void writeByteBuffer(final int fieldNumber, final ByteBuffer value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeUInt32NoTag(value.capacity()); + writeRawBytes(value); + } + + @Override + public final void writeBytesNoTag(final ByteString value) throws IOException { + writeUInt32NoTag(value.size()); + value.writeTo(this); + } + + @Override + public final void writeByteArrayNoTag(final byte[] value, int offset, int length) + throws IOException { + writeUInt32NoTag(length); + write(value, offset, length); + } + + @Override + public final void writeRawBytes(final ByteBuffer value) throws IOException { + if (value.hasArray()) { + write(value.array(), value.arrayOffset(), value.capacity()); + } else { + ByteBuffer duplicated = value.duplicate(); + duplicated.clear(); + write(duplicated); + } + } + + @Override + public final void writeMessage(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value); + } + + @Override + public final void writeMessageSetExtension(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public final void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public final void writeMessageNoTag(final MessageLite value) throws IOException { + writeUInt32NoTag(value.getSerializedSize()); + value.writeTo(this); + } + + @Override + public final void write(byte value) throws IOException { + try { + buffer[position++] = value; + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException(new IndexOutOfBoundsException( + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1))); + } + } + + @Override + public final void writeInt32NoTag(int value) throws IOException { + if (value >= 0) { + writeUInt32NoTag(value); + } else { + // Must sign-extend. + writeUInt64NoTag(value); + } + } + + @Override + public final void writeUInt32NoTag(int value) throws IOException { + if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { + long pos = ARRAY_BASE_OFFSET + position; + while (true) { + if ((value & ~0x7F) == 0) { + UNSAFE.putByte(buffer, pos++, (byte) value); + position++; + return; + } else { + UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); + position++; + value >>>= 7; + } + } + } else { + try { + while (true) { + if ((value & ~0x7F) == 0) { + buffer[position++] = (byte) value; + return; + } else { + buffer[position++] = (byte) ((value & 0x7F) | 0x80); + value >>>= 7; + } + } + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException( + new IndexOutOfBoundsException( + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1))); + } + } + } + + @Override + public final void writeFixed32NoTag(int value) throws IOException { + try { + buffer[position++] = (byte) (value & 0xFF); + buffer[position++] = (byte) ((value >> 8) & 0xFF); + buffer[position++] = (byte) ((value >> 16) & 0xFF); + buffer[position++] = (byte) ((value >> 24) & 0xFF); + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException( + new IndexOutOfBoundsException( + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1))); + } + } + + @Override + public final void writeUInt64NoTag(long value) throws IOException { + if (HAS_UNSAFE_ARRAY_OPERATIONS && spaceLeft() >= MAX_VARINT_SIZE) { + long pos = ARRAY_BASE_OFFSET + position; + while (true) { + if ((value & ~0x7FL) == 0) { + UNSAFE.putByte(buffer, pos++, (byte) value); + position++; + return; + } else { + UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); + position++; + value >>>= 7; + } + } + } else { + try { + while (true) { + if ((value & ~0x7FL) == 0) { + buffer[position++] = (byte) value; + return; + } else { + buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); + value >>>= 7; + } + } + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException( + new IndexOutOfBoundsException( + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1))); + } + } + } + + @Override + public final void writeFixed64NoTag(long value) throws IOException { + try { + buffer[position++] = (byte) ((int) (value) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 8) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 16) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 24) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException( + new IndexOutOfBoundsException( + String.format("Pos: %d, limit: %d, len: %d", position, limit, 1))); + } + } + + @Override + public final void write(byte[] value, int offset, int length) throws IOException { + try { + System.arraycopy(value, offset, buffer, position, length); + position += length; + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException( + new IndexOutOfBoundsException( + String.format("Pos: %d, limit: %d, len: %d", position, limit, length))); + } + } + + @Override + public final void writeLazy(byte[] value, int offset, int length) throws IOException { + write(value, offset, length); + } + + @Override + public final void write(ByteBuffer value) throws IOException { + final int length = value.remaining(); + try { + value.get(buffer, position, length); + position += length; + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException( + new IndexOutOfBoundsException( + String.format("Pos: %d, limit: %d, len: %d", position, limit, length))); + } + } + + @Override + public final void writeLazy(ByteBuffer value) throws IOException { + write(value); + } + + @Override + public final void writeStringNoTag(String value) throws IOException { + final int oldPosition = position; + try { + // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), + // and at most 3 times of it. We take advantage of this in both branches below. + final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; + final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength); + final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); + if (minLengthVarIntSize == maxLengthVarIntSize) { + position = oldPosition + minLengthVarIntSize; + int newPosition = Utf8.encode(value, buffer, position, spaceLeft()); + // Since this class is stateful and tracks the position, we rewind and store the state, + // prepend the length, then reset it back to the end of the string. + position = oldPosition; + int length = newPosition - oldPosition - minLengthVarIntSize; + writeUInt32NoTag(length); + position = newPosition; + } else { + int length = Utf8.encodedLength(value); + writeUInt32NoTag(length); + position = Utf8.encode(value, buffer, position, spaceLeft()); + } + } catch (UnpairedSurrogateException e) { + // Roll back the change - we fall back to inefficient path. + position = oldPosition; + + // TODO(nathanmittler): We should throw an IOException here instead. + inefficientWriteStringNoTag(value, e); + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void flush() { + // Do nothing. + } + + @Override + public final int spaceLeft() { + return limit - position; + } + + @Override + public final int getTotalBytesWritten() { + return position - offset; + } + } + + /** + * A {@link CodedOutputStream} that writes directly to a heap {@link ByteBuffer}. Writes are + * done directly to the underlying array. The buffer position is only updated after a flush. + */ + private static final class NioHeapEncoder extends ArrayEncoder { + private final ByteBuffer byteBuffer; + private int initialPosition; + + NioHeapEncoder(ByteBuffer byteBuffer) { + super(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), + byteBuffer.remaining()); + this.byteBuffer = byteBuffer; + this.initialPosition = byteBuffer.position(); + } + + @Override + public void flush() { + // Update the position on the buffer. + byteBuffer.position(initialPosition + getTotalBytesWritten()); + } + } + + /** + * A {@link CodedOutputStream} that writes directly to a {@link ByteBuffer}. + */ + private static final class NioEncoder extends CodedOutputStream { + private final ByteBuffer originalBuffer; + private final ByteBuffer buffer; + private final int initialPosition; + + NioEncoder(ByteBuffer buffer) { + this.originalBuffer = buffer; + this.buffer = buffer.duplicate().order(ByteOrder.LITTLE_ENDIAN); + initialPosition = buffer.position(); + } + + @Override + public void writeTag(final int fieldNumber, final int wireType) throws IOException { + writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + public void writeInt32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeInt32NoTag(value); + } + + @Override + public void writeUInt32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeUInt32NoTag(value); + } + + @Override + public void writeFixed32(final int fieldNumber, final int value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); + writeFixed32NoTag(value); + } + + @Override + public void writeUInt64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + writeUInt64NoTag(value); + } + + @Override + public void writeFixed64(final int fieldNumber, final long value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); + writeFixed64NoTag(value); + } + + @Override + public void writeBool(final int fieldNumber, final boolean value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + write((byte) (value ? 1 : 0)); + } + + @Override + public void writeString(final int fieldNumber, final String value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeStringNoTag(value); + } + + @Override + public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeBytesNoTag(value); + } + + @Override + public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { + writeByteArray(fieldNumber, value, 0, value.length); + } + + @Override + public void writeByteArray( + final int fieldNumber, final byte[] value, final int offset, final int length) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeByteArrayNoTag(value, offset, length); + } + + @Override + public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeUInt32NoTag(value.capacity()); + writeRawBytes(value); + } + + @Override + public void writeMessage(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value); + } + + @Override + public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public void writeMessageNoTag(final MessageLite value) throws IOException { + writeUInt32NoTag(value.getSerializedSize()); + value.writeTo(this); + } + + @Override + public void write(byte value) throws IOException { + try { + buffer.put(value); + } catch (BufferOverflowException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void writeBytesNoTag(final ByteString value) throws IOException { + writeUInt32NoTag(value.size()); + value.writeTo(this); + } + + @Override + public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException { + writeUInt32NoTag(length); + write(value, offset, length); + } + + @Override + public void writeRawBytes(final ByteBuffer value) throws IOException { + if (value.hasArray()) { + write(value.array(), value.arrayOffset(), value.capacity()); + } else { + ByteBuffer duplicated = value.duplicate(); + duplicated.clear(); + write(duplicated); + } + } + + @Override + public void writeInt32NoTag(int value) throws IOException { + if (value >= 0) { + writeUInt32NoTag(value); + } else { + // Must sign-extend. + writeUInt64NoTag(value); + } + } + + @Override + public void writeUInt32NoTag(int value) throws IOException { + try { + while (true) { + if ((value & ~0x7F) == 0) { + buffer.put((byte) value); + return; + } else { + buffer.put((byte) ((value & 0x7F) | 0x80)); + value >>>= 7; + } + } + } catch (BufferOverflowException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void writeFixed32NoTag(int value) throws IOException { + try { + buffer.putInt(value); + } catch (BufferOverflowException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void writeUInt64NoTag(long value) throws IOException { + try { + while (true) { + if ((value & ~0x7FL) == 0) { + buffer.put((byte) value); + return; + } else { + buffer.put((byte) (((int) value & 0x7F) | 0x80)); + value >>>= 7; + } + } + } catch (BufferOverflowException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void writeFixed64NoTag(long value) throws IOException { + try { + buffer.putLong(value); + } catch (BufferOverflowException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void write(byte[] value, int offset, int length) throws IOException { + try { + buffer.put(value, offset, length); + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException(e); + } catch (BufferOverflowException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void writeLazy(byte[] value, int offset, int length) throws IOException { + write(value, offset, length); + } + + @Override + public void write(ByteBuffer value) throws IOException { + try { + buffer.put(value); + } catch (BufferOverflowException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void writeLazy(ByteBuffer value) throws IOException { + write(value); + } + + @Override + public void writeStringNoTag(String value) throws IOException { + final int startPos = buffer.position(); + try { + // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), + // and at most 3 times of it. We take advantage of this in both branches below. + final int maxEncodedSize = value.length() * Utf8.MAX_BYTES_PER_CHAR; + final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxEncodedSize); + final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); + if (minLengthVarIntSize == maxLengthVarIntSize) { + // Save the current position and increment past the length field. We'll come back + // and write the length field after the encoding is complete. + final int startOfBytes = buffer.position() + minLengthVarIntSize; + buffer.position(startOfBytes); + + // Encode the string. + encode(value); + + // Now go back to the beginning and write the length. + int endOfBytes = buffer.position(); + buffer.position(startPos); + writeUInt32NoTag(endOfBytes - startOfBytes); + + // Reposition the buffer past the written data. + buffer.position(endOfBytes); + } else { + final int length = Utf8.encodedLength(value); + writeUInt32NoTag(length); + encode(value); + } + } catch (UnpairedSurrogateException e) { + // Roll back the change and convert to an IOException. + buffer.position(startPos); + + // TODO(nathanmittler): We should throw an IOException here instead. + inefficientWriteStringNoTag(value, e); + } catch (IllegalArgumentException e) { + // Thrown by buffer.position() if out of range. + throw new OutOfSpaceException(e); + } + } + + @Override + public void flush() { + // Update the position of the original buffer. + originalBuffer.position(buffer.position()); + } + + @Override + public int spaceLeft() { + return buffer.remaining(); + } + + @Override + public int getTotalBytesWritten() { + return buffer.position() - initialPosition; + } + + private void encode(String value) throws IOException { + try { + Utf8.encodeUtf8(value, buffer); + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException(e); + } + } + } + + /** + * Abstract base class for buffered encoders. + */ + private abstract static class AbstractBufferedEncoder extends CodedOutputStream { + final byte[] buffer; + final int limit; + int position; + int totalBytesWritten; + + AbstractBufferedEncoder(int bufferSize) { + if (bufferSize < 0) { + throw new IllegalArgumentException("bufferSize must be >= 0"); + } + // As an optimization, we require that the buffer be able to store at least 2 + // varints so that we can buffer any integer write (tag + value). This reduces the + // number of range checks for a single write to 1 (i.e. if there is not enough space + // to buffer the tag+value, flush and then buffer it). + this.buffer = new byte[max(bufferSize, MAX_VARINT_SIZE * 2)]; + this.limit = buffer.length; + } + + @Override + public final int spaceLeft() { + throw new UnsupportedOperationException( + "spaceLeft() can only be called on CodedOutputStreams that are " + + "writing to a flat array or ByteBuffer."); + } + + @Override + public final int getTotalBytesWritten() { + return totalBytesWritten; + } + + /** + * This method does not perform bounds checking on the array. Checking array bounds is the + * responsibility of the caller. + */ + final void buffer(byte value) { + buffer[position++] = value; + totalBytesWritten++; + } + + /** + * This method does not perform bounds checking on the array. Checking array bounds is the + * responsibility of the caller. + */ + final void bufferTag(final int fieldNumber, final int wireType) { + bufferUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); + } + + /** + * This method does not perform bounds checking on the array. Checking array bounds is the + * responsibility of the caller. + */ + final void bufferInt32NoTag(final int value) { + if (value >= 0) { + bufferUInt32NoTag(value); + } else { + // Must sign-extend. + bufferUInt64NoTag(value); + } + } + + /** + * This method does not perform bounds checking on the array. Checking array bounds is the + * responsibility of the caller. + */ + final void bufferUInt32NoTag(int value) { + if (HAS_UNSAFE_ARRAY_OPERATIONS) { + final long originalPos = ARRAY_BASE_OFFSET + position; + long pos = originalPos; + while (true) { + if ((value & ~0x7F) == 0) { + UNSAFE.putByte(buffer, pos++, (byte) value); + break; + } else { + UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80)); + value >>>= 7; + } + } + int delta = (int) (pos - originalPos); + position += delta; + totalBytesWritten += delta; + } else { + while (true) { + if ((value & ~0x7F) == 0) { + buffer[position++] = (byte) value; + totalBytesWritten++; + return; + } else { + buffer[position++] = (byte) ((value & 0x7F) | 0x80); + totalBytesWritten++; + value >>>= 7; + } + } + } + } + + /** + * This method does not perform bounds checking on the array. Checking array bounds is the + * responsibility of the caller. + */ + final void bufferUInt64NoTag(long value) { + if (HAS_UNSAFE_ARRAY_OPERATIONS) { + final long originalPos = ARRAY_BASE_OFFSET + position; + long pos = originalPos; + while (true) { + if ((value & ~0x7FL) == 0) { + UNSAFE.putByte(buffer, pos++, (byte) value); + break; + } else { + UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80)); + value >>>= 7; + } + } + int delta = (int) (pos - originalPos); + position += delta; + totalBytesWritten += delta; + } else { + while (true) { + if ((value & ~0x7FL) == 0) { + buffer[position++] = (byte) value; + totalBytesWritten++; + return; + } else { + buffer[position++] = (byte) (((int) value & 0x7F) | 0x80); + totalBytesWritten++; + value >>>= 7; + } + } + } + } + + /** + * This method does not perform bounds checking on the array. Checking array bounds is the + * responsibility of the caller. + */ + final void bufferFixed32NoTag(int value) { + buffer[position++] = (byte) (value & 0xFF); + buffer[position++] = (byte) ((value >> 8) & 0xFF); + buffer[position++] = (byte) ((value >> 16) & 0xFF); + buffer[position++] = (byte) ((value >> 24) & 0xFF); + totalBytesWritten += FIXED_32_SIZE; + } + + /** + * This method does not perform bounds checking on the array. Checking array bounds is the + * responsibility of the caller. + */ + final void bufferFixed64NoTag(long value) { + buffer[position++] = (byte) (value & 0xFF); + buffer[position++] = (byte) ((value >> 8) & 0xFF); + buffer[position++] = (byte) ((value >> 16) & 0xFF); + buffer[position++] = (byte) ((value >> 24) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 32) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 40) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 48) & 0xFF); + buffer[position++] = (byte) ((int) (value >> 56) & 0xFF); + totalBytesWritten += FIXED_64_SIZE; + } + } + + /** + * A {@link CodedOutputStream} that decorates a {@link ByteOutput}. It internal buffer only to + * support string encoding operations. All other writes are just passed through to the + * {@link ByteOutput}. + */ + private static final class ByteOutputEncoder extends AbstractBufferedEncoder { + private final ByteOutput out; + + ByteOutputEncoder(ByteOutput out, int bufferSize) { + super(bufferSize); + if (out == null) { + throw new NullPointerException("out"); + } + this.out = out; + } + + @Override + public void writeTag(final int fieldNumber, final int wireType) throws IOException { + writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + public void writeInt32(final int fieldNumber, final int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE * 2); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + bufferInt32NoTag(value); + } + + @Override + public void writeUInt32(final int fieldNumber, final int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE * 2); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + bufferUInt32NoTag(value); + } + + @Override + public void writeFixed32(final int fieldNumber, final int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE); + bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); + bufferFixed32NoTag(value); + } + + @Override + public void writeUInt64(final int fieldNumber, final long value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE * 2); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + bufferUInt64NoTag(value); + } + + @Override + public void writeFixed64(final int fieldNumber, final long value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE); + bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); + bufferFixed64NoTag(value); + } + + @Override + public void writeBool(final int fieldNumber, final boolean value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE + 1); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + buffer((byte) (value ? 1 : 0)); + } + + @Override + public void writeString(final int fieldNumber, final String value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeStringNoTag(value); + } + + @Override + public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeBytesNoTag(value); + } + + @Override + public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { + writeByteArray(fieldNumber, value, 0, value.length); + } + + @Override + public void writeByteArray( + final int fieldNumber, final byte[] value, final int offset, final int length) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeByteArrayNoTag(value, offset, length); + } + + @Override + public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeUInt32NoTag(value.capacity()); + writeRawBytes(value); + } + + @Override + public void writeBytesNoTag(final ByteString value) throws IOException { + writeUInt32NoTag(value.size()); + value.writeTo(this); + } + + @Override + public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException { + writeUInt32NoTag(length); + write(value, offset, length); + } + + @Override + public void writeRawBytes(final ByteBuffer value) throws IOException { + if (value.hasArray()) { + write(value.array(), value.arrayOffset(), value.capacity()); + } else { + ByteBuffer duplicated = value.duplicate(); + duplicated.clear(); + write(duplicated); + } + } + + @Override + public void writeMessage(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value); + } + + @Override + public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public void writeMessageNoTag(final MessageLite value) throws IOException { + writeUInt32NoTag(value.getSerializedSize()); + value.writeTo(this); + } + + @Override + public void write(byte value) throws IOException { + if (position == limit) { + doFlush(); + } + + buffer(value); + } + + @Override + public void writeInt32NoTag(int value) throws IOException { + if (value >= 0) { + writeUInt32NoTag(value); + } else { + // Must sign-extend. + writeUInt64NoTag(value); + } + } + + @Override + public void writeUInt32NoTag(int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE); + bufferUInt32NoTag(value); + } + + @Override + public void writeFixed32NoTag(final int value) throws IOException { + flushIfNotAvailable(FIXED_32_SIZE); + bufferFixed32NoTag(value); + } + + @Override + public void writeUInt64NoTag(long value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE); + bufferUInt64NoTag(value); + } + + @Override + public void writeFixed64NoTag(final long value) throws IOException { + flushIfNotAvailable(FIXED_64_SIZE); + bufferFixed64NoTag(value); + } + + @Override + public void writeStringNoTag(String value) throws IOException { + // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), + // and at most 3 times of it. We take advantage of this in both branches below. + final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; + final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength); + + // If we are streaming and the potential length is too big to fit in our buffer, we take the + // slower path. + if (maxLengthVarIntSize + maxLength > limit) { + // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes() + // does the same internally and then does *another copy* to return a byte[] of exactly the + // right size. We can skip that copy and just writeRawBytes up to the actualLength of the + // UTF-8 encoded bytes. + final byte[] encodedBytes = new byte[maxLength]; + int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength); + writeUInt32NoTag(actualLength); + writeLazy(encodedBytes, 0, actualLength); + return; + } + + // Fast path: we have enough space available in our buffer for the string... + if (maxLengthVarIntSize + maxLength > limit - position) { + // Flush to free up space. + doFlush(); + } + + final int oldPosition = position; + try { + // Optimize for the case where we know this length results in a constant varint length as + // this saves a pass for measuring the length of the string. + final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); + + if (minLengthVarIntSize == maxLengthVarIntSize) { + position = oldPosition + minLengthVarIntSize; + int newPosition = Utf8.encode(value, buffer, position, limit - position); + // Since this class is stateful and tracks the position, we rewind and store the state, + // prepend the length, then reset it back to the end of the string. + position = oldPosition; + int length = newPosition - oldPosition - minLengthVarIntSize; + bufferUInt32NoTag(length); + position = newPosition; + totalBytesWritten += length; + } else { + int length = Utf8.encodedLength(value); + bufferUInt32NoTag(length); + position = Utf8.encode(value, buffer, position, length); + totalBytesWritten += length; + } + } catch (UnpairedSurrogateException e) { + // Roll back the change and convert to an IOException. + totalBytesWritten -= position - oldPosition; + position = oldPosition; + + // TODO(nathanmittler): We should throw an IOException here instead. + inefficientWriteStringNoTag(value, e); + } catch (IndexOutOfBoundsException e) { + throw new OutOfSpaceException(e); + } + } + + @Override + public void flush() throws IOException { + if (position > 0) { + // Flush the buffer. + doFlush(); + } + } + + @Override + public void write(byte[] value, int offset, int length) throws IOException { + flush(); + out.write(value, offset, length); + totalBytesWritten += length; + } + + @Override + public void writeLazy(byte[] value, int offset, int length) throws IOException { + flush(); + out.writeLazy(value, offset, length); + totalBytesWritten += length; + } + + @Override + public void write(ByteBuffer value) throws IOException { + flush(); + int length = value.remaining(); + out.write(value); + totalBytesWritten += length; + } + + @Override + public void writeLazy(ByteBuffer value) throws IOException { + flush(); + int length = value.remaining(); + out.writeLazy(value); + totalBytesWritten += length; + } + + private void flushIfNotAvailable(int requiredSize) throws IOException { + if (limit - position < requiredSize) { + doFlush(); + } + } + + private void doFlush() throws IOException { + out.write(buffer, 0, position); + position = 0; + } + } + + /** + * An {@link CodedOutputStream} that decorates an {@link OutputStream}. It performs internal + * buffering to optimize writes to the {@link OutputStream}. + */ + private static final class OutputStreamEncoder extends AbstractBufferedEncoder { + private final OutputStream out; + + OutputStreamEncoder(OutputStream out, int bufferSize) { + super(bufferSize); + if (out == null) { + throw new NullPointerException("out"); + } + this.out = out; + } + + @Override + public void writeTag(final int fieldNumber, final int wireType) throws IOException { + writeUInt32NoTag(WireFormat.makeTag(fieldNumber, wireType)); + } + + @Override + public void writeInt32(final int fieldNumber, final int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE * 2); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + bufferInt32NoTag(value); + } + + @Override + public void writeUInt32(final int fieldNumber, final int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE * 2); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + bufferUInt32NoTag(value); + } + + @Override + public void writeFixed32(final int fieldNumber, final int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_32_SIZE); + bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED32); + bufferFixed32NoTag(value); + } + + @Override + public void writeUInt64(final int fieldNumber, final long value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE * 2); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + bufferUInt64NoTag(value); + } + + @Override + public void writeFixed64(final int fieldNumber, final long value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE + FIXED_64_SIZE); + bufferTag(fieldNumber, WireFormat.WIRETYPE_FIXED64); + bufferFixed64NoTag(value); + } + + @Override + public void writeBool(final int fieldNumber, final boolean value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE + 1); + bufferTag(fieldNumber, WireFormat.WIRETYPE_VARINT); + buffer((byte) (value ? 1 : 0)); + } + + @Override + public void writeString(final int fieldNumber, final String value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeStringNoTag(value); + } + + @Override + public void writeBytes(final int fieldNumber, final ByteString value) throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeBytesNoTag(value); + } + + @Override + public void writeByteArray(final int fieldNumber, final byte[] value) throws IOException { + writeByteArray(fieldNumber, value, 0, value.length); + } + + @Override + public void writeByteArray( + final int fieldNumber, final byte[] value, final int offset, final int length) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeByteArrayNoTag(value, offset, length); + } + + @Override + public void writeByteBuffer(final int fieldNumber, final ByteBuffer value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeUInt32NoTag(value.capacity()); + writeRawBytes(value); + } + + @Override + public void writeBytesNoTag(final ByteString value) throws IOException { + writeUInt32NoTag(value.size()); + value.writeTo(this); + } + + @Override + public void writeByteArrayNoTag(final byte[] value, int offset, int length) throws IOException { + writeUInt32NoTag(length); + write(value, offset, length); + } + + @Override + public void writeRawBytes(final ByteBuffer value) throws IOException { + if (value.hasArray()) { + write(value.array(), value.arrayOffset(), value.capacity()); + } else { + ByteBuffer duplicated = value.duplicate(); + duplicated.clear(); + write(duplicated); + } + } + + @Override + public void writeMessage(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED); + writeMessageNoTag(value); + } + + @Override + public void writeMessageSetExtension(final int fieldNumber, final MessageLite value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public void writeRawMessageSetExtension(final int fieldNumber, final ByteString value) + throws IOException { + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP); + writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber); + writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value); + writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP); + } + + @Override + public void writeMessageNoTag(final MessageLite value) throws IOException { + writeUInt32NoTag(value.getSerializedSize()); + value.writeTo(this); + } + + @Override + public void write(byte value) throws IOException { + if (position == limit) { + doFlush(); + } + + buffer(value); + } + + @Override + public void writeInt32NoTag(int value) throws IOException { + if (value >= 0) { + writeUInt32NoTag(value); + } else { + // Must sign-extend. + writeUInt64NoTag(value); + } + } + + @Override + public void writeUInt32NoTag(int value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE); + bufferUInt32NoTag(value); + } + + @Override + public void writeFixed32NoTag(final int value) throws IOException { + flushIfNotAvailable(FIXED_32_SIZE); + bufferFixed32NoTag(value); + } + + @Override + public void writeUInt64NoTag(long value) throws IOException { + flushIfNotAvailable(MAX_VARINT_SIZE); + bufferUInt64NoTag(value); + } + + @Override + public void writeFixed64NoTag(final long value) throws IOException { + flushIfNotAvailable(FIXED_64_SIZE); + bufferFixed64NoTag(value); + } + + @Override + public void writeStringNoTag(String value) throws IOException { + try { + // UTF-8 byte length of the string is at least its UTF-16 code unit length (value.length()), + // and at most 3 times of it. We take advantage of this in both branches below. + final int maxLength = value.length() * Utf8.MAX_BYTES_PER_CHAR; + final int maxLengthVarIntSize = computeUInt32SizeNoTag(maxLength); + + // If we are streaming and the potential length is too big to fit in our buffer, we take the + // slower path. + if (maxLengthVarIntSize + maxLength > limit) { + // Allocate a byte[] that we know can fit the string and encode into it. String.getBytes() + // does the same internally and then does *another copy* to return a byte[] of exactly the + // right size. We can skip that copy and just writeRawBytes up to the actualLength of the + // UTF-8 encoded bytes. + final byte[] encodedBytes = new byte[maxLength]; + int actualLength = Utf8.encode(value, encodedBytes, 0, maxLength); + writeUInt32NoTag(actualLength); + writeLazy(encodedBytes, 0, actualLength); + return; + } + + // Fast path: we have enough space available in our buffer for the string... + if (maxLengthVarIntSize + maxLength > limit - position) { + // Flush to free up space. + doFlush(); + } + + // Optimize for the case where we know this length results in a constant varint length as + // this saves a pass for measuring the length of the string. + final int minLengthVarIntSize = computeUInt32SizeNoTag(value.length()); + int oldPosition = position; + final int length; + try { + if (minLengthVarIntSize == maxLengthVarIntSize) { + position = oldPosition + minLengthVarIntSize; + int newPosition = Utf8.encode(value, buffer, position, limit - position); + // Since this class is stateful and tracks the position, we rewind and store the + // state, prepend the length, then reset it back to the end of the string. + position = oldPosition; + length = newPosition - oldPosition - minLengthVarIntSize; + bufferUInt32NoTag(length); + position = newPosition; + } else { + length = Utf8.encodedLength(value); + bufferUInt32NoTag(length); + position = Utf8.encode(value, buffer, position, length); + } + totalBytesWritten += length; + } catch (UnpairedSurrogateException e) { + // Be extra careful and restore the original position for retrying the write with the + // less efficient path. + totalBytesWritten -= position - oldPosition; + position = oldPosition; + throw e; + } catch (ArrayIndexOutOfBoundsException e) { + throw new OutOfSpaceException(e); + } + } catch (UnpairedSurrogateException e) { + inefficientWriteStringNoTag(value, e); + } + } + + @Override + public void flush() throws IOException { + if (position > 0) { + // Flush the buffer. + doFlush(); + } + } + + @Override + public void write(byte[] value, int offset, int length) + throws IOException { + if (limit - position >= length) { + // We have room in the current buffer. + System.arraycopy(value, offset, buffer, position, length); + position += length; + totalBytesWritten += length; + } else { + // Write extends past current buffer. Fill the rest of this buffer and + // flush. + final int bytesWritten = limit - position; + System.arraycopy(value, offset, buffer, position, bytesWritten); + offset += bytesWritten; + length -= bytesWritten; + position = limit; + totalBytesWritten += bytesWritten; + doFlush(); + + // Now deal with the rest. + // Since we have an output stream, this is our buffer + // and buffer offset == 0 + if (length <= limit) { + // Fits in new buffer. + System.arraycopy(value, offset, buffer, 0, length); + position = length; + } else { + // Write is very big. Let's do it all at once. + out.write(value, offset, length); + } + totalBytesWritten += length; + } + } + + @Override + public void writeLazy(byte[] value, int offset, int length) throws IOException { + write(value, offset, length); + } + + @Override + public void write(ByteBuffer value) throws IOException { + int length = value.remaining(); + if (limit - position >= length) { + // We have room in the current buffer. + value.get(buffer, position, length); + position += length; + totalBytesWritten += length; + } else { + // Write extends past current buffer. Fill the rest of this buffer and + // flush. + final int bytesWritten = limit - position; + value.get(buffer, position, bytesWritten); + length -= bytesWritten; + position = limit; + totalBytesWritten += bytesWritten; + doFlush(); + + // Now deal with the rest. + // Since we have an output stream, this is our buffer + // and buffer offset == 0 + while (length > limit) { + // Copy data into the buffer before writing it to OutputStream. + value.get(buffer, 0, limit); + out.write(buffer, 0, limit); + length -= limit; + totalBytesWritten += limit; + } + value.get(buffer, 0, length); + position = length; + totalBytesWritten += length; + } + } + + @Override + public void writeLazy(ByteBuffer value) throws IOException { + write(value); + } + + private void flushIfNotAvailable(int requiredSize) throws IOException { + if (limit - position < requiredSize) { + doFlush(); + } + } + + private void doFlush() throws IOException { + out.write(buffer, 0, position); + position = 0; + } + } + + /** + * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this + * platform. + */ + private static sun.misc.Unsafe getUnsafe() { + sun.misc.Unsafe unsafe = null; + try { + unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction() { + @Override + public sun.misc.Unsafe run() throws Exception { + Class k = sun.misc.Unsafe.class; + + for (Field f : k.getDeclaredFields()) { + f.setAccessible(true); + Object x = f.get(null); + if (k.isInstance(x)) { + return k.cast(x); + } + } + // The sun.misc.Unsafe field does not exist. + return null; + } + }); + } catch (Throwable e) { + // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError + // for Unsafe. + } + + logger.log(Level.FINEST, "sun.misc.Unsafe: {}", + unsafe != null ? "available" : "unavailable"); + return unsafe; + } + + /** + * Indicates whether or not unsafe array operations are supported on this platform. + */ + // TODO(nathanmittler): Add support for Android's MemoryBlock. + private static boolean supportsUnsafeArrayOperations() { + boolean supported = false; + if (UNSAFE != null) { + try { + UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class); + UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.class); + supported = true; + } catch (Throwable e) { + // Do nothing. + } + } + logger.log(Level.FINEST, "Unsafe array operations: {}", + supported ? "available" : "unavailable"); + return supported; + } + + /** + * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not + * available. + */ + private static int byteArrayBaseOffset() { + return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1; } } 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 e303e138..e00ea342 100644 --- a/java/core/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java @@ -74,16 +74,28 @@ public final class Descriptors { */ public static final class FileDescriptor extends GenericDescriptor { /** Convert the descriptor to its protocol message representation. */ - public FileDescriptorProto toProto() { return proto; } + @Override + public FileDescriptorProto toProto() { + return proto; + } /** Get the file name. */ - public String getName() { return proto.getName(); } + @Override + public String getName() { + return proto.getName(); + } /** Returns this object. */ - public FileDescriptor getFile() { return this; } + @Override + public FileDescriptor getFile() { + return this; + } /** Returns the same as getName(). */ - public String getFullName() { return proto.getName(); } + @Override + public String getFullName() { + return proto.getName(); + } /** * Get the proto package name. This is the package name given by the @@ -582,10 +594,16 @@ public final class Descriptors { public int getIndex() { return index; } /** Convert the descriptor to its protocol message representation. */ - public DescriptorProto toProto() { return proto; } + @Override + public DescriptorProto toProto() { + return proto; + } /** Get the type's unqualified name. */ - public String getName() { return proto.getName(); } + @Override + public String getName() { + return proto.getName(); + } /** * Get the type's fully-qualified name, within the proto language's @@ -598,10 +616,16 @@ public final class Descriptors { * * {@code Baz}'s full name is "foo.bar.Baz". */ - public String getFullName() { return fullName; } + @Override + public String getFullName() { + return fullName; + } /** Get the {@link FileDescriptor} containing this descriptor. */ - public FileDescriptor getFile() { return file; } + @Override + public FileDescriptor getFile() { + return file; + } /** If this is a nested type, get the outer descriptor, otherwise null. */ public Descriptor getContainingType() { return containingType; } @@ -875,19 +899,31 @@ public final class Descriptors { public int getIndex() { return index; } /** Convert the descriptor to its protocol message representation. */ - public FieldDescriptorProto toProto() { return proto; } + @Override + public FieldDescriptorProto toProto() { + return proto; + } /** Get the field's unqualified name. */ - public String getName() { return proto.getName(); } + @Override + public String getName() { + return proto.getName(); + } /** Get the field's number. */ - public int getNumber() { return proto.getNumber(); } + @Override + public int getNumber() { + return proto.getNumber(); + } /** * Get the field's fully-qualified name. * @see Descriptors.Descriptor#getFullName() */ - public String getFullName() { return fullName; } + @Override + public String getFullName() { + return fullName; + } /** Get the JSON name of this field. */ public String getJsonName() { @@ -901,17 +937,22 @@ public final class Descriptors { public JavaType getJavaType() { return type.getJavaType(); } /** For internal use only. */ + @Override public WireFormat.JavaType getLiteJavaType() { return getLiteType().getJavaType(); } /** Get the {@code FileDescriptor} containing this descriptor. */ - public FileDescriptor getFile() { return file; } + @Override + public FileDescriptor getFile() { + return file; + } /** Get the field's declared type. */ public Type getType() { return type; } /** For internal use only. */ + @Override public WireFormat.FieldType getLiteType() { return table[type.ordinal()]; } @@ -953,6 +994,7 @@ public final class Descriptors { } /** Is this field declared repeated? */ + @Override public boolean isRepeated() { return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED; } @@ -960,6 +1002,7 @@ public final class Descriptors { /** Does this field have the {@code [packed = true]} option or is this field * packable in proto3 and not explicitly setted to unpacked? */ + @Override public boolean isPacked() { if (!isPackable()) { return false; @@ -1048,6 +1091,7 @@ public final class Descriptors { } /** For enum fields, gets the field's type. */ + @Override public EnumDescriptor getEnumType() { if (getJavaType() != JavaType.ENUM) { throw new UnsupportedOperationException( @@ -1066,6 +1110,7 @@ public final class Descriptors { * @return negative, zero, or positive if {@code this} is less than, * equal to, or greater than {@code other}, respectively. */ + @Override public int compareTo(final FieldDescriptor other) { if (other.containingType != containingType) { throw new IllegalArgumentException( @@ -1466,8 +1511,8 @@ public final class Descriptors { * For internal use only. This is to satisfy the FieldDescriptorLite * interface. */ - public MessageLite.Builder internalMergeFrom( - MessageLite.Builder to, MessageLite from) { + @Override + public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) { // FieldDescriptors are only used with non-lite messages so we can just // down-cast and call mergeFrom directly. return ((Message.Builder) to).mergeFrom((Message) from); @@ -1487,19 +1532,31 @@ public final class Descriptors { public int getIndex() { return index; } /** Convert the descriptor to its protocol message representation. */ - public EnumDescriptorProto toProto() { return proto; } + @Override + public EnumDescriptorProto toProto() { + return proto; + } /** Get the type's unqualified name. */ - public String getName() { return proto.getName(); } + @Override + public String getName() { + return proto.getName(); + } /** * Get the type's fully-qualified name. * @see Descriptors.Descriptor#getFullName() */ - public String getFullName() { return fullName; } + @Override + public String getFullName() { + return fullName; + } /** Get the {@link FileDescriptor} containing this descriptor. */ - public FileDescriptor getFile() { return file; } + @Override + public FileDescriptor getFile() { + return file; + } /** If this is a nested type, get the outer descriptor, otherwise null. */ public Descriptor getContainingType() { return containingType; } @@ -1533,6 +1590,7 @@ public final class Descriptors { * @param number The value's number. * @return the value's descriptor, or {@code null} if not found. */ + @Override public EnumValueDescriptor findValueByNumber(final int number) { return file.pool.enumValuesByNumber.get( new DescriptorPool.DescriptorIntPair(this, number)); @@ -1659,13 +1717,22 @@ public final class Descriptors { public int getIndex() { return index; } /** Convert the descriptor to its protocol message representation. */ - public EnumValueDescriptorProto toProto() { return proto; } + @Override + public EnumValueDescriptorProto toProto() { + return proto; + } /** Get the value's unqualified name. */ - public String getName() { return proto.getName(); } + @Override + public String getName() { + return proto.getName(); + } /** Get the value's number. */ - public int getNumber() { return proto.getNumber(); } + @Override + public int getNumber() { + return proto.getNumber(); + } @Override public String toString() { return proto.getName(); } @@ -1674,10 +1741,16 @@ public final class Descriptors { * Get the value's fully-qualified name. * @see Descriptors.Descriptor#getFullName() */ - public String getFullName() { return fullName; } + @Override + public String getFullName() { + return fullName; + } /** Get the {@link FileDescriptor} containing this descriptor. */ - public FileDescriptor getFile() { return file; } + @Override + public FileDescriptor getFile() { + return file; + } /** Get the value's enum type. */ public EnumDescriptor getType() { return type; } @@ -1745,19 +1818,31 @@ public final class Descriptors { public int getIndex() { return index; } /** Convert the descriptor to its protocol message representation. */ - public ServiceDescriptorProto toProto() { return proto; } + @Override + public ServiceDescriptorProto toProto() { + return proto; + } /** Get the type's unqualified name. */ - public String getName() { return proto.getName(); } + @Override + public String getName() { + return proto.getName(); + } /** * Get the type's fully-qualified name. * @see Descriptors.Descriptor#getFullName() */ - public String getFullName() { return fullName; } + @Override + public String getFullName() { + return fullName; + } /** Get the {@link FileDescriptor} containing this descriptor. */ - public FileDescriptor getFile() { return file; } + @Override + public FileDescriptor getFile() { + return file; + } /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */ public ServiceOptions getOptions() { return proto.getOptions(); } @@ -1835,19 +1920,31 @@ public final class Descriptors { public int getIndex() { return index; } /** Convert the descriptor to its protocol message representation. */ - public MethodDescriptorProto toProto() { return proto; } + @Override + public MethodDescriptorProto toProto() { + return proto; + } /** Get the method's unqualified name. */ - public String getName() { return proto.getName(); } + @Override + public String getName() { + return proto.getName(); + } /** * Get the method's fully-qualified name. * @see Descriptors.Descriptor#getFullName() */ - public String getFullName() { return fullName; } + @Override + public String getFullName() { + return fullName; + } /** Get the {@link FileDescriptor} containing this descriptor. */ - public FileDescriptor getFile() { return file; } + @Override + public FileDescriptor getFile() { + return file; + } /** Get the method's service type. */ public ServiceDescriptor getService() { return service; } @@ -2248,10 +2345,22 @@ public final class Descriptors { * that has the same name as an existing package. */ private static final class PackageDescriptor extends GenericDescriptor { - public Message toProto() { return file.toProto(); } - public String getName() { return name; } - public String getFullName() { return fullName; } - public FileDescriptor getFile() { return file; } + @Override + public Message toProto() { + return file.toProto(); + } + @Override + public String getName() { + return name; + } + @Override + public String getFullName() { + return fullName; + } + @Override + public FileDescriptor getFile() { + return file; + } PackageDescriptor(final String name, final String fullName, final FileDescriptor file) { 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 bcc9d6ee..a9543b83 100644 --- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java @@ -34,7 +34,6 @@ import com.google.protobuf.Internal.DoubleList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.RandomAccess; /** @@ -45,8 +44,6 @@ import java.util.RandomAccess; final class DoubleArrayList extends AbstractProtobufList implements DoubleList, RandomAccess { - private static final int DEFAULT_CAPACITY = 10; - private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList(); static { EMPTY_LIST.makeImmutable(); @@ -71,32 +68,56 @@ final class DoubleArrayList * Constructs a new mutable {@code DoubleArrayList} with default capacity. */ DoubleArrayList() { - this(DEFAULT_CAPACITY); - } - - /** - * Constructs a new mutable {@code DoubleArrayList} with the provided capacity. - */ - DoubleArrayList(int capacity) { - array = new double[capacity]; - size = 0; + this(new double[DEFAULT_CAPACITY], 0); } /** * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}. */ - DoubleArrayList(List other) { - if (other instanceof DoubleArrayList) { - DoubleArrayList list = (DoubleArrayList) other; - array = list.array.clone(); - size = list.size; - } else { - size = other.size(); - array = new double[size]; - for (int i = 0; i < size; i++) { - array[i] = other.get(i); + private DoubleArrayList(double[] array, int size) { + this.array = array; + this.size = size; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof DoubleArrayList)) { + return super.equals(o); + } + DoubleArrayList other = (DoubleArrayList) o; + if (size != other.size) { + return false; + } + + final double[] arr = other.array; + for (int i = 0; i < size; i++) { + if (array[i] != arr[i]) { + return false; } } + + return true; + } + + @Override + public int hashCode() { + int result = 1; + for (int i = 0; i < size; i++) { + long bits = Double.doubleToLongBits(array[i]); + result = (31 * result) + Internal.hashLong(bits); + } + return result; + } + + @Override + public DoubleList mutableCopyWithCapacity(int capacity) { + if (capacity < size) { + throw new IllegalArgumentException(); + } + return new DoubleArrayList(Arrays.copyOf(array, capacity), size); } @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 3ea1b688..859a9e8f 100644 --- a/java/core/src/main/java/com/google/protobuf/DynamicMessage.java +++ b/java/core/src/main/java/com/google/protobuf/DynamicMessage.java @@ -156,18 +156,22 @@ public final class DynamicMessage extends AbstractMessage { // ----------------------------------------------------------------- // Implementation of Message interface. + @Override public Descriptor getDescriptorForType() { return type; } + @Override public DynamicMessage getDefaultInstanceForType() { return getDefaultInstance(type); } + @Override public Map getAllFields() { return fields.getAllFields(); } + @Override public boolean hasOneof(OneofDescriptor oneof) { verifyOneofContainingType(oneof); FieldDescriptor field = oneofCases[oneof.getIndex()]; @@ -177,16 +181,19 @@ public final class DynamicMessage extends AbstractMessage { return true; } + @Override public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { verifyOneofContainingType(oneof); return oneofCases[oneof.getIndex()]; } + @Override public boolean hasField(FieldDescriptor field) { verifyContainingType(field); return fields.hasField(field); } + @Override public Object getField(FieldDescriptor field) { verifyContainingType(field); Object result = fields.getField(field); @@ -202,16 +209,19 @@ public final class DynamicMessage extends AbstractMessage { return result; } + @Override public int getRepeatedFieldCount(FieldDescriptor field) { verifyContainingType(field); return fields.getRepeatedFieldCount(field); } + @Override public Object getRepeatedField(FieldDescriptor field, int index) { verifyContainingType(field); return fields.getRepeatedField(field, index); } + @Override public UnknownFieldSet getUnknownFields() { return unknownFields; } @@ -264,19 +274,22 @@ public final class DynamicMessage extends AbstractMessage { return size; } + @Override public Builder newBuilderForType() { return new Builder(type); } + @Override public Builder toBuilder() { return newBuilderForType().mergeFrom(this); } + @Override public Parser getParserForType() { return new AbstractParser() { + @Override public DynamicMessage parsePartialFrom( - CodedInputStream input, - ExtensionRegistryLite extensionRegistry) + CodedInputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { Builder builder = newBuilder(type); try { @@ -370,6 +383,7 @@ public final class DynamicMessage extends AbstractMessage { } } + @Override public DynamicMessage build() { if (!isInitialized()) { throw newUninitializedMessageException( @@ -394,6 +408,7 @@ public final class DynamicMessage extends AbstractMessage { return buildPartial(); } + @Override public DynamicMessage buildPartial() { fields.makeImmutable(); DynamicMessage result = @@ -411,22 +426,27 @@ public final class DynamicMessage extends AbstractMessage { return result; } + @Override public boolean isInitialized() { return DynamicMessage.isInitialized(type, fields); } + @Override public Descriptor getDescriptorForType() { return type; } + @Override public DynamicMessage getDefaultInstanceForType() { return getDefaultInstance(type); } + @Override public Map getAllFields() { return fields.getAllFields(); } + @Override public Builder newBuilderForField(FieldDescriptor field) { verifyContainingType(field); @@ -438,6 +458,7 @@ public final class DynamicMessage extends AbstractMessage { return new Builder(field.getMessageType()); } + @Override public boolean hasOneof(OneofDescriptor oneof) { verifyOneofContainingType(oneof); FieldDescriptor field = oneofCases[oneof.getIndex()]; @@ -447,11 +468,13 @@ public final class DynamicMessage extends AbstractMessage { return true; } + @Override public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { verifyOneofContainingType(oneof); return oneofCases[oneof.getIndex()]; } + @Override public Builder clearOneof(OneofDescriptor oneof) { verifyOneofContainingType(oneof); FieldDescriptor field = oneofCases[oneof.getIndex()]; @@ -461,11 +484,13 @@ public final class DynamicMessage extends AbstractMessage { return this; } + @Override public boolean hasField(FieldDescriptor field) { verifyContainingType(field); return fields.hasField(field); } + @Override public Object getField(FieldDescriptor field) { verifyContainingType(field); Object result = fields.getField(field); @@ -481,6 +506,7 @@ public final class DynamicMessage extends AbstractMessage { return result; } + @Override public Builder setField(FieldDescriptor field, Object value) { verifyContainingType(field); ensureIsMutable(); @@ -505,6 +531,7 @@ public final class DynamicMessage extends AbstractMessage { return this; } + @Override public Builder clearField(FieldDescriptor field) { verifyContainingType(field); ensureIsMutable(); @@ -519,24 +546,27 @@ public final class DynamicMessage extends AbstractMessage { return this; } + @Override public int getRepeatedFieldCount(FieldDescriptor field) { verifyContainingType(field); return fields.getRepeatedFieldCount(field); } + @Override public Object getRepeatedField(FieldDescriptor field, int index) { verifyContainingType(field); return fields.getRepeatedField(field, index); } - public Builder setRepeatedField(FieldDescriptor field, - int index, Object value) { + @Override + public Builder setRepeatedField(FieldDescriptor field, int index, Object value) { verifyContainingType(field); ensureIsMutable(); fields.setRepeatedField(field, index, value); return this; } + @Override public Builder addRepeatedField(FieldDescriptor field, Object value) { verifyContainingType(field); ensureIsMutable(); @@ -544,10 +574,12 @@ public final class DynamicMessage extends AbstractMessage { return this; } + @Override public UnknownFieldSet getUnknownFields() { return unknownFields; } + @Override public Builder setUnknownFields(UnknownFieldSet unknownFields) { if (getDescriptorForType().getFile().getSyntax() == Descriptors.FileDescriptor.Syntax.PROTO3) { diff --git a/java/core/src/main/java/com/google/protobuf/Extension.java b/java/core/src/main/java/com/google/protobuf/Extension.java index 68d29f33..08ec5b45 100644 --- a/java/core/src/main/java/com/google/protobuf/Extension.java +++ b/java/core/src/main/java/com/google/protobuf/Extension.java @@ -42,6 +42,7 @@ public abstract class Extension public abstract Descriptors.FieldDescriptor getDescriptor(); /** Returns whether or not this extension is a Lite Extension. */ + @Override final boolean isLite() { return false; } diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java index 47924b65..4e89709f 100644 --- a/java/core/src/main/java/com/google/protobuf/FieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java @@ -120,6 +120,25 @@ final class FieldSet other = (FieldSet) o; + return other.fields.equals(other.fields); + } + + @Override + public int hashCode() { + return fields.hashCode(); + } /** * Clones the FieldSet. The returned FieldSet will be mutable even if the 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 033b5eed..63cb6d77 100644 --- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java @@ -34,7 +34,6 @@ import com.google.protobuf.Internal.FloatList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.RandomAccess; /** @@ -44,8 +43,6 @@ import java.util.RandomAccess; */ final class FloatArrayList extends AbstractProtobufList implements FloatList, RandomAccess { - private static final int DEFAULT_CAPACITY = 10; - private static final FloatArrayList EMPTY_LIST = new FloatArrayList(); static { EMPTY_LIST.makeImmutable(); @@ -70,32 +67,55 @@ final class FloatArrayList extends AbstractProtobufList implements FloatL * Constructs a new mutable {@code FloatArrayList} with default capacity. */ FloatArrayList() { - this(DEFAULT_CAPACITY); - } - - /** - * Constructs a new mutable {@code FloatArrayList} with the provided capacity. - */ - FloatArrayList(int capacity) { - array = new float[capacity]; - size = 0; + this(new float[DEFAULT_CAPACITY], 0); } /** * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}. */ - FloatArrayList(List other) { - if (other instanceof FloatArrayList) { - FloatArrayList list = (FloatArrayList) other; - array = list.array.clone(); - size = list.size; - } else { - size = other.size(); - array = new float[size]; - for (int i = 0; i < size; i++) { - array[i] = other.get(i); + private FloatArrayList(float[] array, int size) { + this.array = array; + this.size = size; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof FloatArrayList)) { + return super.equals(o); + } + FloatArrayList other = (FloatArrayList) o; + if (size != other.size) { + return false; + } + + final float[] arr = other.array; + for (int i = 0; i < size; i++) { + if (array[i] != arr[i]) { + return false; } } + + return true; + } + + @Override + public int hashCode() { + int result = 1; + for (int i = 0; i < size; i++) { + result = (31 * result) + Float.floatToIntBits(array[i]); + } + return result; + } + + @Override + public FloatList mutableCopyWithCapacity(int capacity) { + if (capacity < size) { + throw new IllegalArgumentException(); + } + return new FloatArrayList(Arrays.copyOf(array, capacity), size); } @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 a50afe55..57e732a0 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java @@ -80,6 +80,7 @@ public abstract class GeneratedMessage extends AbstractMessage unknownFields = builder.getUnknownFields(); } + @Override public Parser getParserForType() { throw new UnsupportedOperationException( "This is supposed to be overridden by subclasses."); @@ -102,7 +103,7 @@ public abstract class GeneratedMessage extends AbstractMessage */ protected abstract FieldAccessorTable internalGetFieldAccessorTable(); - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Descriptor getDescriptorForType() { return internalGetFieldAccessorTable().descriptor; } @@ -191,7 +192,7 @@ public abstract class GeneratedMessage extends AbstractMessage return true; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Map getAllFields() { return Collections.unmodifiableMap( getAllFieldsMutable(/* getBytesForString = */ false)); @@ -212,22 +213,22 @@ public abstract class GeneratedMessage extends AbstractMessage getAllFieldsMutable(/* getBytesForString = */ true)); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasOneof(final OneofDescriptor oneof) { return internalGetFieldAccessorTable().getOneof(oneof).has(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) { return internalGetFieldAccessorTable().getOneof(oneof).get(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasField(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field).has(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Object getField(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field).get(this); } @@ -244,19 +245,19 @@ public abstract class GeneratedMessage extends AbstractMessage return internalGetFieldAccessorTable().getField(field).getRaw(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public int getRepeatedFieldCount(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field) .getRepeatedCount(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Object getRepeatedField(final FieldDescriptor field, final int index) { return internalGetFieldAccessorTable().getField(field) .getRepeated(this, index); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public UnknownFieldSet getUnknownFields() { throw new UnsupportedOperationException( "This is supposed to be overridden by subclasses."); @@ -380,7 +381,7 @@ public abstract class GeneratedMessage extends AbstractMessage } @SuppressWarnings("unchecked") - public abstract static class Builder + public abstract static class Builder > extends AbstractMessage.Builder { private BuilderParent builderParent; @@ -444,6 +445,7 @@ public abstract class GeneratedMessage extends AbstractMessage * Called by the initialization and clear code paths to allow subclasses to * reset any of their builtin fields back to the initial values. */ + @Override public BuilderType clear() { unknownFields = UnknownFieldSet.getDefaultInstance(); onChanged(); @@ -457,12 +459,12 @@ public abstract class GeneratedMessage extends AbstractMessage */ protected abstract FieldAccessorTable internalGetFieldAccessorTable(); - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Descriptor getDescriptorForType() { return internalGetFieldAccessorTable().descriptor; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Map getAllFields() { return Collections.unmodifiableMap(getAllFieldsMutable()); } @@ -510,39 +512,38 @@ public abstract class GeneratedMessage extends AbstractMessage return result; } - public Message.Builder newBuilderForField( - final FieldDescriptor field) { + @Override + public Message.Builder newBuilderForField(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field).newBuilder(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Message.Builder getFieldBuilder(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field).getBuilder(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) - public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, - int index) { + @Override + public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) { return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder( this, index); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasOneof(final OneofDescriptor oneof) { return internalGetFieldAccessorTable().getOneof(oneof).has(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) { return internalGetFieldAccessorTable().getOneof(oneof).get(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasField(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field).has(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Object getField(final FieldDescriptor field) { Object object = internalGetFieldAccessorTable().getField(field).get(this); if (field.isRepeated()) { @@ -554,52 +555,52 @@ public abstract class GeneratedMessage extends AbstractMessage } } - public BuilderType setField(final FieldDescriptor field, - final Object value) { + @Override + public BuilderType setField(final FieldDescriptor field, final Object value) { internalGetFieldAccessorTable().getField(field).set(this, value); return (BuilderType) this; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public BuilderType clearField(final FieldDescriptor field) { internalGetFieldAccessorTable().getField(field).clear(this); return (BuilderType) this; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public BuilderType clearOneof(final OneofDescriptor oneof) { internalGetFieldAccessorTable().getOneof(oneof).clear(this); return (BuilderType) this; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public int getRepeatedFieldCount(final FieldDescriptor field) { return internalGetFieldAccessorTable().getField(field) .getRepeatedCount(this); } - //@Override (Java 1.6 override semantics, but we must support 1.5) - public Object getRepeatedField(final FieldDescriptor field, - final int index) { + @Override + public Object getRepeatedField(final FieldDescriptor field, final int index) { return internalGetFieldAccessorTable().getField(field) .getRepeated(this, index); } - public BuilderType setRepeatedField(final FieldDescriptor field, - final int index, final Object value) { + @Override + public BuilderType setRepeatedField( + final FieldDescriptor field, final int index, final Object value) { internalGetFieldAccessorTable().getField(field) .setRepeated(this, index, value); return (BuilderType) this; } - public BuilderType addRepeatedField(final FieldDescriptor field, - final Object value) { + @Override + public BuilderType addRepeatedField(final FieldDescriptor field, final Object value) { internalGetFieldAccessorTable().getField(field).addRepeated(this, value); return (BuilderType) this; } - public BuilderType setUnknownFields( - final UnknownFieldSet unknownFields) { + @Override + public BuilderType setUnknownFields(final UnknownFieldSet unknownFields) { this.unknownFields = unknownFields; onChanged(); return (BuilderType) this; @@ -616,7 +617,7 @@ public abstract class GeneratedMessage extends AbstractMessage return (BuilderType) this; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean isInitialized() { for (final FieldDescriptor field : getDescriptorForType().getFields()) { // Check that all required fields are present. @@ -646,7 +647,7 @@ public abstract class GeneratedMessage extends AbstractMessage return true; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final UnknownFieldSet getUnknownFields() { return unknownFields; } @@ -670,7 +671,7 @@ public abstract class GeneratedMessage extends AbstractMessage */ private class BuilderParentImpl implements BuilderParent { - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void markDirty() { onChanged(); } @@ -735,6 +736,7 @@ public abstract class GeneratedMessage extends AbstractMessage public interface ExtendableMessageOrBuilder< MessageType extends ExtendableMessage> extends MessageOrBuilder { // Re-define for return type covariance. + @Override Message getDefaultInstanceForType(); /** Check if a singular extension is present. */ @@ -821,9 +823,8 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Check if a singular extension is present. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) - public final boolean hasExtension( - final ExtensionLite extensionLite) { + @Override + public final boolean hasExtension(final ExtensionLite extensionLite) { Extension extension = checkNotLite(extensionLite); verifyExtensionContainingType(extension); @@ -831,7 +832,7 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Get the number of elements in a repeated extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final int getExtensionCount( final ExtensionLite> extensionLite) { Extension> extension = checkNotLite(extensionLite); @@ -842,10 +843,9 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Get the value of an extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override @SuppressWarnings("unchecked") - public final Type getExtension( - final ExtensionLite extensionLite) { + public final Type getExtension(final ExtensionLite extensionLite) { Extension extension = checkNotLite(extensionLite); verifyExtensionContainingType(extension); @@ -867,11 +867,10 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Get one element of a repeated extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override @SuppressWarnings("unchecked") public final Type getExtension( - final ExtensionLite> extensionLite, - final int index) { + final ExtensionLite> extensionLite, final int index) { Extension> extension = checkNotLite(extensionLite); verifyExtensionContainingType(extension); @@ -1105,7 +1104,7 @@ public abstract class GeneratedMessage extends AbstractMessage @SuppressWarnings("unchecked") public abstract static class ExtendableBuilder< MessageType extends ExtendableMessage, - BuilderType extends ExtendableBuilder> + BuilderType extends ExtendableBuilder> extends Builder implements ExtendableMessageOrBuilder { @@ -1157,9 +1156,8 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Check if a singular extension is present. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) - public final boolean hasExtension( - final ExtensionLite extensionLite) { + @Override + public final boolean hasExtension(final ExtensionLite extensionLite) { Extension extension = checkNotLite(extensionLite); verifyExtensionContainingType(extension); @@ -1167,7 +1165,7 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Get the number of elements in a repeated extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final int getExtensionCount( final ExtensionLite> extensionLite) { Extension> extension = checkNotLite(extensionLite); @@ -1178,9 +1176,8 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Get the value of an extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) - public final Type getExtension( - final ExtensionLite extensionLite) { + @Override + public final Type getExtension(final ExtensionLite extensionLite) { Extension extension = checkNotLite(extensionLite); verifyExtensionContainingType(extension); @@ -1202,10 +1199,9 @@ public abstract class GeneratedMessage extends AbstractMessage } /** Get one element of a repeated extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final Type getExtension( - final ExtensionLite> extensionLite, - final int index) { + final ExtensionLite> extensionLite, final int index) { Extension> extension = checkNotLite(extensionLite); verifyExtensionContainingType(extension); @@ -1458,10 +1454,9 @@ public abstract class GeneratedMessage extends AbstractMessage // obtained. return new GeneratedExtension( new CachedDescriptorRetriever() { - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public FieldDescriptor loadDescriptor() { - return scope.getDescriptorForType().getExtensions() - .get(descriptorIndex); + return scope.getDescriptorForType().getExtensions().get(descriptorIndex); } }, singularType, @@ -1489,6 +1484,7 @@ public abstract class GeneratedMessage extends AbstractMessage private volatile FieldDescriptor descriptor; protected abstract FieldDescriptor loadDescriptor(); + @Override public FieldDescriptor getDescriptor() { if (descriptor == null) { synchronized (this) { @@ -1518,6 +1514,7 @@ public abstract class GeneratedMessage extends AbstractMessage // obtained. return new GeneratedExtension( new CachedDescriptorRetriever() { + @Override protected FieldDescriptor loadDescriptor() { return scope.getDescriptorForType().findFieldByName(name); } @@ -1544,17 +1541,18 @@ public abstract class GeneratedMessage extends AbstractMessage // used to obtain the extension's FieldDescriptor. return new GeneratedExtension( new CachedDescriptorRetriever() { + @Override protected FieldDescriptor loadDescriptor() { try { - Class clazz = - singularType.getClassLoader().loadClass(descriptorOuterClass); - FileDescriptor file = - (FileDescriptor) clazz.getField("descriptor").get(null); + Class clazz = singularType.getClassLoader().loadClass(descriptorOuterClass); + FileDescriptor file = (FileDescriptor) clazz.getField("descriptor").get(null); return file.findExtensionByName(extensionName); } catch (Exception e) { throw new RuntimeException( - "Cannot load descriptors: " + descriptorOuterClass + - " is not a valid descriptor class name", e); + "Cannot load descriptors: " + + descriptorOuterClass + + " is not a valid descriptor class name", + e); } } }, @@ -1636,12 +1634,13 @@ public abstract class GeneratedMessage extends AbstractMessage if (descriptorRetriever != null) { throw new IllegalStateException("Already initialized."); } - descriptorRetriever = new ExtensionDescriptorRetriever() { - //@Override (Java 1.6 override semantics, but we must support 1.5) - public FieldDescriptor getDescriptor() { - return descriptor; - } - }; + descriptorRetriever = + new ExtensionDescriptorRetriever() { + @Override + public FieldDescriptor getDescriptor() { + return descriptor; + } + }; } private ExtensionDescriptorRetriever descriptorRetriever; @@ -1651,6 +1650,7 @@ public abstract class GeneratedMessage extends AbstractMessage private final Method enumGetValueDescriptor; private final ExtensionType extensionType; + @Override public FieldDescriptor getDescriptor() { if (descriptorRetriever == null) { throw new IllegalStateException( @@ -1663,10 +1663,12 @@ public abstract class GeneratedMessage extends AbstractMessage * If the extension is an embedded message or group, returns the default * instance of the message. */ + @Override public Message getMessageDefaultInstance() { return messageDefaultInstance; } + @Override protected ExtensionType getExtensionType() { return extensionType; } @@ -1677,7 +1679,7 @@ public abstract class GeneratedMessage extends AbstractMessage * EnumValueDescriptors but the native accessors use the generated enum * type. */ - // @Override + @Override @SuppressWarnings("unchecked") protected Object fromReflectionType(final Object value) { FieldDescriptor descriptor = getDescriptor(); @@ -1702,7 +1704,7 @@ public abstract class GeneratedMessage extends AbstractMessage * Like {@link #fromReflectionType(Object)}, but if the type is a repeated * type, this converts a single element. */ - // @Override + @Override protected Object singularFromReflectionType(final Object value) { FieldDescriptor descriptor = getDescriptor(); switch (descriptor.getJavaType()) { @@ -1726,7 +1728,7 @@ public abstract class GeneratedMessage extends AbstractMessage * EnumValueDescriptors but the native accessors use the generated enum * type. */ - // @Override + @Override @SuppressWarnings("unchecked") protected Object toReflectionType(final Object value) { FieldDescriptor descriptor = getDescriptor(); @@ -1750,7 +1752,7 @@ public abstract class GeneratedMessage extends AbstractMessage * Like {@link #toReflectionType(Object)}, but if the type is a repeated * type, this converts a single element. */ - // @Override + @Override protected Object singularToReflectionType(final Object value) { FieldDescriptor descriptor = getDescriptor(); switch (descriptor.getJavaType()) { @@ -1761,22 +1763,22 @@ public abstract class GeneratedMessage extends AbstractMessage } } - // @Override + @Override public int getNumber() { return getDescriptor().getNumber(); } - // @Override + @Override public WireFormat.FieldType getLiteType() { return getDescriptor().getLiteType(); } - // @Override + @Override public boolean isRepeated() { return getDescriptor().isRepeated(); } - // @Override + @Override @SuppressWarnings("unchecked") public Type getDefaultValue() { if (isRepeated()) { @@ -2126,49 +2128,57 @@ public abstract class GeneratedMessage extends AbstractMessage return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber(); } + @Override public Object get(final GeneratedMessage message) { return invokeOrDie(getMethod, message); } + @Override public Object get(GeneratedMessage.Builder builder) { return invokeOrDie(getMethodBuilder, builder); } + @Override public Object getRaw(final GeneratedMessage message) { return get(message); } + @Override public Object getRaw(GeneratedMessage.Builder builder) { return get(builder); } + @Override public void set(final Builder builder, final Object value) { invokeOrDie(setMethod, builder, value); } - public Object getRepeated(final GeneratedMessage message, - final int index) { + @Override + public Object getRepeated(final GeneratedMessage message, final int index) { throw new UnsupportedOperationException( "getRepeatedField() called on a singular field."); } - public Object getRepeatedRaw(final GeneratedMessage message, - final int index) { + @Override + public Object getRepeatedRaw(final GeneratedMessage message, final int index) { throw new UnsupportedOperationException( "getRepeatedFieldRaw() called on a singular field."); } + @Override public Object getRepeated(GeneratedMessage.Builder builder, int index) { throw new UnsupportedOperationException( "getRepeatedField() called on a singular field."); } - public Object getRepeatedRaw(GeneratedMessage.Builder builder, - int index) { + @Override + public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) { throw new UnsupportedOperationException( "getRepeatedFieldRaw() called on a singular field."); } - public void setRepeated(final Builder builder, final int index, - final Object value) { + @Override + public void setRepeated(final Builder builder, final int index, final Object value) { throw new UnsupportedOperationException( "setRepeatedField() called on a singular field."); } + @Override public void addRepeated(final Builder builder, final Object value) { throw new UnsupportedOperationException( "addRepeatedField() called on a singular field."); } + @Override public boolean has(final GeneratedMessage message) { if (!hasHasMethod) { if (isOneofField) { @@ -2178,6 +2188,7 @@ public abstract class GeneratedMessage extends AbstractMessage } return (Boolean) invokeOrDie(hasMethod, message); } + @Override public boolean has(GeneratedMessage.Builder builder) { if (!hasHasMethod) { if (isOneofField) { @@ -2187,27 +2198,32 @@ public abstract class GeneratedMessage extends AbstractMessage } return (Boolean) invokeOrDie(hasMethodBuilder, builder); } + @Override public int getRepeatedCount(final GeneratedMessage message) { throw new UnsupportedOperationException( "getRepeatedFieldSize() called on a singular field."); } + @Override public int getRepeatedCount(GeneratedMessage.Builder builder) { throw new UnsupportedOperationException( "getRepeatedFieldSize() called on a singular field."); } + @Override public void clear(final Builder builder) { invokeOrDie(clearMethod, builder); } + @Override public Message.Builder newBuilder() { throw new UnsupportedOperationException( "newBuilderForField() called on a non-Message type."); } + @Override public Message.Builder getBuilder(GeneratedMessage.Builder builder) { throw new UnsupportedOperationException( "getFieldBuilder() called on a non-Message type."); } - public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, - int index) { + @Override + public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) { throw new UnsupportedOperationException( "getRepeatedFieldBuilder() called on a non-Message type."); } @@ -2251,18 +2267,23 @@ public abstract class GeneratedMessage extends AbstractMessage clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName); } + @Override public Object get(final GeneratedMessage message) { return invokeOrDie(getMethod, message); } + @Override public Object get(GeneratedMessage.Builder builder) { return invokeOrDie(getMethodBuilder, builder); } + @Override public Object getRaw(final GeneratedMessage message) { return get(message); } + @Override public Object getRaw(GeneratedMessage.Builder builder) { return get(builder); } + @Override public void set(final Builder builder, final Object value) { // Add all the elements individually. This serves two purposes: // 1) Verifies that each element has the correct type. @@ -2273,54 +2294,64 @@ public abstract class GeneratedMessage extends AbstractMessage addRepeated(builder, element); } } - public Object getRepeated(final GeneratedMessage message, - final int index) { + @Override + public Object getRepeated(final GeneratedMessage message, final int index) { return invokeOrDie(getRepeatedMethod, message, index); } + @Override public Object getRepeated(GeneratedMessage.Builder builder, int index) { return invokeOrDie(getRepeatedMethodBuilder, builder, index); } + @Override public Object getRepeatedRaw(GeneratedMessage message, int index) { return getRepeated(message, index); } - public Object getRepeatedRaw(GeneratedMessage.Builder builder, - int index) { + @Override + public Object getRepeatedRaw(GeneratedMessage.Builder builder, int index) { return getRepeated(builder, index); } - public void setRepeated(final Builder builder, - final int index, final Object value) { + @Override + public void setRepeated(final Builder builder, final int index, final Object value) { invokeOrDie(setRepeatedMethod, builder, index, value); } + @Override public void addRepeated(final Builder builder, final Object value) { invokeOrDie(addRepeatedMethod, builder, value); } + @Override public boolean has(final GeneratedMessage message) { throw new UnsupportedOperationException( "hasField() called on a repeated field."); } + @Override public boolean has(GeneratedMessage.Builder builder) { throw new UnsupportedOperationException( "hasField() called on a repeated field."); } + @Override public int getRepeatedCount(final GeneratedMessage message) { return (Integer) invokeOrDie(getCountMethod, message); } + @Override public int getRepeatedCount(GeneratedMessage.Builder builder) { return (Integer) invokeOrDie(getCountMethodBuilder, builder); } + @Override public void clear(final Builder builder) { invokeOrDie(clearMethod, builder); } + @Override public Message.Builder newBuilder() { throw new UnsupportedOperationException( "newBuilderForField() called on a non-Message type."); } + @Override public Message.Builder getBuilder(GeneratedMessage.Builder builder) { throw new UnsupportedOperationException( "getFieldBuilder() called on a non-Message type."); } - public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, - int index) { + @Override + public Message.Builder getRepeatedBuilder(GeneratedMessage.Builder builder, int index) { throw new UnsupportedOperationException( "getRepeatedFieldBuilder() called on a non-Message type."); } @@ -2357,6 +2388,7 @@ public abstract class GeneratedMessage extends AbstractMessage field.getNumber()); } + @Override public Object get(GeneratedMessage message) { List result = new ArrayList(); for (int i = 0; i < getRepeatedCount(message); i++) { @@ -2365,6 +2397,7 @@ public abstract class GeneratedMessage extends AbstractMessage return Collections.unmodifiableList(result); } + @Override public Object get(Builder builder) { List result = new ArrayList(); for (int i = 0; i < getRepeatedCount(builder); i++) { @@ -2373,14 +2406,17 @@ public abstract class GeneratedMessage extends AbstractMessage return Collections.unmodifiableList(result); } + @Override public Object getRaw(GeneratedMessage message) { return get(message); } + @Override public Object getRaw(GeneratedMessage.Builder builder) { return get(builder); } + @Override public void set(Builder builder, Object value) { clear(builder); for (Object entry : (List) value) { @@ -2388,63 +2424,76 @@ public abstract class GeneratedMessage extends AbstractMessage } } + @Override public Object getRepeated(GeneratedMessage message, int index) { return getMapField(message).getList().get(index); } + @Override public Object getRepeated(Builder builder, int index) { return getMapField(builder).getList().get(index); } + @Override public Object getRepeatedRaw(GeneratedMessage message, int index) { return getRepeated(message, index); } + @Override public Object getRepeatedRaw(Builder builder, int index) { return getRepeated(builder, index); } + @Override public void setRepeated(Builder builder, int index, Object value) { getMutableMapField(builder).getMutableList().set(index, (Message) value); } + @Override public void addRepeated(Builder builder, Object value) { getMutableMapField(builder).getMutableList().add((Message) value); } + @Override public boolean has(GeneratedMessage message) { throw new UnsupportedOperationException( "hasField() is not supported for repeated fields."); } + @Override public boolean has(Builder builder) { throw new UnsupportedOperationException( "hasField() is not supported for repeated fields."); } + @Override public int getRepeatedCount(GeneratedMessage message) { return getMapField(message).getList().size(); } + @Override public int getRepeatedCount(Builder builder) { return getMapField(builder).getList().size(); } + @Override public void clear(Builder builder) { getMutableMapField(builder).getMutableList().clear(); } + @Override public com.google.protobuf.Message.Builder newBuilder() { return mapEntryMessageDefaultInstance.newBuilderForType(); } + @Override public com.google.protobuf.Message.Builder getBuilder(Builder builder) { throw new UnsupportedOperationException( "Nested builder not supported for map fields."); } - public com.google.protobuf.Message.Builder getRepeatedBuilder( - Builder builder, int index) { + @Override + public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) { throw new UnsupportedOperationException( "Nested builder not supported for map fields."); } diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java index 12a1472d..c5adc5ad 100644 --- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java @@ -31,6 +31,7 @@ package com.google.protobuf; import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream; +import com.google.protobuf.GeneratedMessageLite.EqualsVisitor.NotEqualsException; import com.google.protobuf.Internal.BooleanList; import com.google.protobuf.Internal.DoubleList; import com.google.protobuf.Internal.FloatList; @@ -59,24 +60,27 @@ import java.util.Map; public abstract class GeneratedMessageLite< MessageType extends GeneratedMessageLite, BuilderType extends GeneratedMessageLite.Builder> - extends AbstractMessageLite { + extends AbstractMessageLite { /** For use by generated code only. Lazily initialized to reduce allocations. */ - protected UnknownFieldSetLite unknownFields = null; + protected UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance(); /** For use by generated code only. */ protected int memoizedSerializedSize = -1; + @Override @SuppressWarnings("unchecked") // Guaranteed by runtime. public final Parser getParserForType() { return (Parser) dynamicMethod(MethodToInvoke.GET_PARSER); } + @Override @SuppressWarnings("unchecked") // Guaranteed by runtime. public final MessageType getDefaultInstanceForType() { return (MessageType) dynamicMethod(MethodToInvoke.GET_DEFAULT_INSTANCE); } + @Override @SuppressWarnings("unchecked") // Guaranteed by runtime. public final BuilderType newBuilderForType() { return (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER); @@ -99,7 +103,65 @@ public abstract class GeneratedMessageLite< return MessageLiteToString.toString(this, super.toString()); } + @SuppressWarnings("unchecked") // Guaranteed by runtime + @Override + public int hashCode() { + if (memoizedHashCode == 0) { + HashCodeVisitor visitor = new HashCodeVisitor(); + visit(visitor, (MessageType) this); + memoizedHashCode = visitor.hashCode; + } + return memoizedHashCode; + } + + @SuppressWarnings("unchecked") // Guaranteed by runtime + int hashCode(HashCodeVisitor visitor) { + if (memoizedHashCode == 0) { + int inProgressHashCode = visitor.hashCode; + visitor.hashCode = 0; + visit(visitor, (MessageType) this); + memoizedHashCode = visitor.hashCode; + visitor.hashCode = inProgressHashCode; + } + return memoizedHashCode; + } + + @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + + if (!getDefaultInstanceForType().getClass().isInstance(other)) { + return false; + } + + try { + visit(EqualsVisitor.INSTANCE, (MessageType) other); + } catch (NotEqualsException e) { + return false; + } + return true; + } + + /** + * Same as {@link #equals(Object)} but throws {@code NotEqualsException}. + */ + @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime + boolean equals(EqualsVisitor visitor, MessageLite other) { + if (this == other) { + return true; + } + + if (!getDefaultInstanceForType().getClass().isInstance(other)) { + return false; + } + visit(visitor, (MessageType) other); + return true; + } + // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as // mutable during the parsing constructor and immutable after. This allows us to avoid // any unnecessary intermediary allocations while reducing the generated code size. @@ -108,7 +170,7 @@ public abstract class GeneratedMessageLite< * Lazily initializes unknown fields. */ private final void ensureUnknownFieldsInitialized() { - if (unknownFields == null) { + if (unknownFields == UnknownFieldSetLite.getDefaultInstance()) { unknownFields = UnknownFieldSetLite.newInstance(); } } @@ -147,18 +209,18 @@ public abstract class GeneratedMessageLite< /** * Called by subclasses to complete parsing. For use by generated code only. */ - protected void doneParsing() { - if (unknownFields == null) { - unknownFields = UnknownFieldSetLite.getDefaultInstance(); - } else { - unknownFields.makeImmutable(); - } + protected void makeImmutable() { + dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); + + unknownFields.makeImmutable(); } + @Override public final boolean isInitialized() { return dynamicMethod(MethodToInvoke.IS_INITIALIZED, Boolean.TRUE) != null; } + @Override public final BuilderType toBuilder() { BuilderType builder = (BuilderType) dynamicMethod(MethodToInvoke.NEW_BUILDER); builder.mergeFrom((MessageType) this); @@ -172,11 +234,14 @@ public abstract class GeneratedMessageLite< * For use by generated code only. */ public static enum MethodToInvoke { + // Rely on/modify instance state IS_INITIALIZED, - PARSE_PARTIAL_FROM, - MERGE_FROM, + VISIT, + MERGE_FROM_STREAM, MAKE_IMMUTABLE, - NEW_INSTANCE, + + // Rely on static state + NEW_MUTABLE_INSTANCE, NEW_BUILDER, GET_DEFAULT_INSTANCE, GET_PARSER; @@ -188,17 +253,18 @@ public abstract class GeneratedMessageLite< * builders in the runtime. This method bundles those operations to reduce the generated methods * count. *

    - *
  • {@code PARSE_PARTIAL_FROM} is parameterized with an {@link CodedInputStream} and + *
  • {@code MERGE_FROM_STREAM} is parameterized with an {@link CodedInputStream} and * {@link ExtensionRegistryLite}. It consumes the input stream, parsing the contents into the * returned protocol buffer. If parsing throws an {@link InvalidProtocolBufferException}, the - * implementation wraps it in a RuntimeException - *
  • {@code NEW_INSTANCE} returns a new instance of the protocol buffer + * implementation wraps it in a RuntimeException. + *
  • {@code NEW_INSTANCE} returns a new instance of the protocol buffer that has not yet been + * made immutable. See {@code MAKE_IMMUTABLE}. *
  • {@code IS_INITIALIZED} is parameterized with a {@code Boolean} detailing whether to * memoize. It returns {@code null} for false and the default instance for true. We optionally * memoize to support the Builder case, where memoization is not desired. *
  • {@code NEW_BUILDER} returns a {@code BuilderType} instance. - *
  • {@code MERGE_FROM} is parameterized with a {@code MessageType} and merges the fields from - * that instance into this instance. + *
  • {@code VISIT} is parameterized with a {@code Visitor} and a {@code MessageType} and + * recursively iterates through the fields side by side between this and the instance. *
  • {@code MAKE_IMMUTABLE} sets all internal fields to an immutable state. *
* This method, plus the implementation of the Builder, enables the Builder class to be proguarded @@ -222,6 +288,11 @@ public abstract class GeneratedMessageLite< return dynamicMethod(method, null, null); } + void visit(Visitor visitor, MessageType other) { + dynamicMethod(MethodToInvoke.VISIT, visitor, other); + unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields); + } + /** * Merge some unknown fields into the {@link UnknownFieldSetLite} for this * message. @@ -236,7 +307,7 @@ public abstract class GeneratedMessageLite< public abstract static class Builder< MessageType extends GeneratedMessageLite, BuilderType extends Builder> - extends AbstractMessageLite.Builder { + extends AbstractMessageLite.Builder { private final MessageType defaultInstance; protected MessageType instance; @@ -244,7 +315,8 @@ public abstract class GeneratedMessageLite< protected Builder(MessageType defaultInstance) { this.defaultInstance = defaultInstance; - this.instance = (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_INSTANCE); + this.instance = + (MessageType) defaultInstance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); isBuilt = false; } @@ -254,26 +326,27 @@ public abstract class GeneratedMessageLite< */ protected void copyOnWrite() { if (isBuilt) { - MessageType newInstance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE); - newInstance.dynamicMethod(MethodToInvoke.MERGE_FROM, instance); + MessageType newInstance = + (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); + newInstance.visit(MergeFromVisitor.INSTANCE, instance); instance = newInstance; isBuilt = false; } } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final boolean isInitialized() { return GeneratedMessageLite.isInitialized(instance, false /* shouldMemoize */); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final BuilderType clear() { // No need to copy on write since we're dropping the instance anyways. - instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_INSTANCE); + instance = (MessageType) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); return (BuilderType) this; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public BuilderType clone() { BuilderType builder = (BuilderType) getDefaultInstanceForType().newBuilderForType(); @@ -281,20 +354,19 @@ public abstract class GeneratedMessageLite< return builder; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public MessageType buildPartial() { if (isBuilt) { return instance; } - instance.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); - instance.unknownFields.makeImmutable(); + instance.makeImmutable(); isBuilt = true; return instance; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final MessageType build() { MessageType result = buildPartial(); if (!result.isInitialized()) { @@ -303,32 +375,36 @@ public abstract class GeneratedMessageLite< return result; } + @Override + protected BuilderType internalMergeFrom(MessageType message) { + return mergeFrom(message); + } + /** All subclasses implement this. */ public BuilderType mergeFrom(MessageType message) { copyOnWrite(); - instance.dynamicMethod(MethodToInvoke.MERGE_FROM, message); + instance.visit(MergeFromVisitor.INSTANCE, message); return (BuilderType) this; } + @Override public MessageType getDefaultInstanceForType() { return defaultInstance; } + @Override public BuilderType mergeFrom( com.google.protobuf.CodedInputStream input, com.google.protobuf.ExtensionRegistryLite extensionRegistry) - throws java.io.IOException { - MessageType parsedMessage = null; + throws IOException { + copyOnWrite(); try { - parsedMessage = parsePartialFrom( - (MessageType) getDefaultInstanceForType(), input, extensionRegistry); - } catch (InvalidProtocolBufferException e) { - parsedMessage = (MessageType) e.getUnfinishedMessage(); - throw e; - } finally { - if (parsedMessage != null) { - mergeFrom(parsedMessage); + instance.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry); + } catch (RuntimeException e) { + if (e.getCause() instanceof IOException) { + throw (IOException) e.getCause(); } + throw e; } return (BuilderType) this; } @@ -384,6 +460,12 @@ public abstract class GeneratedMessageLite< } extensions.mergeFrom(((ExtendableMessage) other).extensions); } + + @Override + final void visit(Visitor visitor, MessageType other) { + super.visit(visitor, other); + extensions = visitor.visitExtensions(extensions, other.extensions); + } /** * Parse an unknown field or an extension. For use by generated code only. @@ -521,9 +603,8 @@ public abstract class GeneratedMessageLite< } /** Check if a singular extension is present. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) - public final boolean hasExtension( - final ExtensionLite extension) { + @Override + public final boolean hasExtension(final ExtensionLite extension) { GeneratedExtension extensionLite = checkIsLite(extension); @@ -532,7 +613,7 @@ public abstract class GeneratedMessageLite< } /** Get the number of elements in a repeated extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final int getExtensionCount( final ExtensionLite> extension) { GeneratedExtension> extensionLite = @@ -543,10 +624,9 @@ public abstract class GeneratedMessageLite< } /** Get the value of an extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override @SuppressWarnings("unchecked") - public final Type getExtension( - final ExtensionLite extension) { + public final Type getExtension(final ExtensionLite extension) { GeneratedExtension extensionLite = checkIsLite(extension); @@ -560,11 +640,10 @@ public abstract class GeneratedMessageLite< } /** Get one element of a repeated extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override @SuppressWarnings("unchecked") public final Type getExtension( - final ExtensionLite> extension, - final int index) { + final ExtensionLite> extension, final int index) { GeneratedExtension> extensionLite = checkIsLite(extension); @@ -579,8 +658,8 @@ public abstract class GeneratedMessageLite< } @Override - protected final void doneParsing() { - super.doneParsing(); + protected final void makeImmutable() { + super.makeImmutable(); extensions.makeImmutable(); } @@ -669,7 +748,7 @@ public abstract class GeneratedMessageLite< instance.extensions = extensions; } - // @Override (Java 1.6 override semantics, but we must support 1.5) + @Override protected void copyOnWrite() { if (!isBuilt) { return; @@ -679,7 +758,7 @@ public abstract class GeneratedMessageLite< instance.extensions = instance.extensions.clone(); } - // @Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final MessageType buildPartial() { if (isBuilt) { return instance; @@ -701,33 +780,30 @@ public abstract class GeneratedMessageLite< } /** Check if a singular extension is present. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) - public final boolean hasExtension( - final ExtensionLite extension) { + @Override + public final boolean hasExtension(final ExtensionLite extension) { return instance.hasExtension(extension); } /** Get the number of elements in a repeated extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public final int getExtensionCount( final ExtensionLite> extension) { return instance.getExtensionCount(extension); } /** Get the value of an extension. */ - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override @SuppressWarnings("unchecked") - public final Type getExtension( - final ExtensionLite extension) { + public final Type getExtension(final ExtensionLite extension) { return instance.getExtension(extension); } /** Get one element of a repeated extension. */ + @Override @SuppressWarnings("unchecked") - //@Override (Java 1.6 override semantics, but we must support 1.5) public final Type getExtension( - final ExtensionLite> extension, - final int index) { + final ExtensionLite> extension, final int index) { return instance.getExtension(extension, index); } @@ -859,37 +935,44 @@ public abstract class GeneratedMessageLite< final boolean isRepeated; final boolean isPacked; + @Override public int getNumber() { return number; } + @Override public WireFormat.FieldType getLiteType() { return type; } + @Override public WireFormat.JavaType getLiteJavaType() { return type.getJavaType(); } + @Override public boolean isRepeated() { return isRepeated; } + @Override public boolean isPacked() { return isPacked; } + @Override public Internal.EnumLiteMap getEnumType() { return enumTypeMap; } + @Override @SuppressWarnings("unchecked") - public MessageLite.Builder internalMergeFrom( - MessageLite.Builder to, MessageLite from) { + public MessageLite.Builder internalMergeFrom(MessageLite.Builder to, MessageLite from) { return ((Builder) to).mergeFrom((GeneratedMessageLite) from); } + @Override public int compareTo(ExtensionDescriptor other) { return number - other.number; } @@ -984,6 +1067,7 @@ public abstract class GeneratedMessageLite< } /** Get the field number. */ + @Override public int getNumber() { return descriptor.getNumber(); } @@ -993,6 +1077,7 @@ public abstract class GeneratedMessageLite< * If the extension is an embedded message or group, returns the default * instance of the message. */ + @Override public MessageLite getMessageDefaultInstance() { return messageDefaultInstance; } @@ -1047,14 +1132,17 @@ public abstract class GeneratedMessageLite< } } + @Override public FieldType getLiteType() { return descriptor.getLiteType(); } + @Override public boolean isRepeated() { return descriptor.isRepeated; } + @Override public Type getDefaultValue() { return defaultValue; } @@ -1139,112 +1227,72 @@ public abstract class GeneratedMessageLite< protected static final > boolean isInitialized( T message, boolean shouldMemoize) { return message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, shouldMemoize) != null; - } + } protected static final > void makeImmutable(T message) { message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE); } - - protected static IntList newIntList() { - return new IntArrayList(); - } - - protected static IntList newIntListWithCapacity(int capacity) { - return new IntArrayList(capacity); - } - - protected static IntList newIntList(List toCopy) { - return new IntArrayList(toCopy); - } - + protected static IntList emptyIntList() { return IntArrayList.emptyList(); } - protected static LongList newLongList() { - return new LongArrayList(); + protected static IntList mutableCopy(IntList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); } - protected static LongList newLongListWithCapacity(int capacity) { - return new LongArrayList(capacity); - } - - protected static LongList newLongList(List toCopy) { - return new LongArrayList(toCopy); - } - protected static LongList emptyLongList() { return LongArrayList.emptyList(); } - protected static FloatList newFloatList() { - return new FloatArrayList(); + protected static LongList mutableCopy(LongList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); } - - protected static FloatList newFloatListWithCapacity(int capacity) { - return new FloatArrayList(capacity); - } - - protected static FloatList newFloatList(List toCopy) { - return new FloatArrayList(toCopy); - } - + protected static FloatList emptyFloatList() { return FloatArrayList.emptyList(); } - protected static DoubleList newDoubleList() { - return new DoubleArrayList(); + protected static FloatList mutableCopy(FloatList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); } - - protected static DoubleList newDoubleListWithCapacity(int capacity) { - return new DoubleArrayList(capacity); - } - - protected static DoubleList newDoubleList(List toCopy) { - return new DoubleArrayList(toCopy); - } - + protected static DoubleList emptyDoubleList() { return DoubleArrayList.emptyList(); } - protected static BooleanList newBooleanList() { - return new BooleanArrayList(); + protected static DoubleList mutableCopy(DoubleList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); } - - protected static BooleanList newBooleanListWithCapacity(int capacity) { - return new BooleanArrayList(capacity); - } - - protected static BooleanList newBooleanList(List toCopy) { - return new BooleanArrayList(toCopy); - } - + protected static BooleanList emptyBooleanList() { return BooleanArrayList.emptyList(); } - protected static ProtobufList newProtobufList() { - return new ProtobufArrayList(); + protected static BooleanList mutableCopy(BooleanList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); } - - protected static ProtobufList newProtobufList(List toCopy) { - return new ProtobufArrayList(toCopy); - } - - protected static ProtobufList newProtobufListWithCapacity(int capacity) { - return new ProtobufArrayList(capacity); - } - + protected static ProtobufList emptyProtobufList() { return ProtobufArrayList.emptyList(); } - - protected static LazyStringArrayList emptyLazyStringArrayList() { - return LazyStringArrayList.emptyList(); - } + protected static ProtobufList mutableCopy(ProtobufList list) { + int size = list.size(); + return list.mutableCopyWithCapacity( + size == 0 ? AbstractProtobufList.DEFAULT_CAPACITY : size * 2); + } + /** * A {@link Parser} implementation that delegates to the default instance. *

@@ -1274,10 +1322,11 @@ public abstract class GeneratedMessageLite< static > T parsePartialFrom( T instance, CodedInputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { - T result; + @SuppressWarnings("unchecked") // Guaranteed by protoc + T result = (T) instance.dynamicMethod(MethodToInvoke.NEW_MUTABLE_INSTANCE); try { - result = (T) instance.dynamicMethod( - MethodToInvoke.PARSE_PARTIAL_FROM, input, extensionRegistry); + result.dynamicMethod(MethodToInvoke.MERGE_FROM_STREAM, input, extensionRegistry); + result.makeImmutable(); } catch (RuntimeException e) { if (e.getCause() instanceof InvalidProtocolBufferException) { throw (InvalidProtocolBufferException) e.getCause(); @@ -1454,4 +1503,740 @@ public abstract class GeneratedMessageLite< } return message; } + + /** + * An abstract visitor that the generated code calls into that we use to implement various + * features. Fields that are not members of oneofs are always visited. Members of a oneof are only + * visited when they are the set oneof case value on the "other" proto. The visitOneofNotSet + * method is invoked if other's oneof case is not set. + */ + protected interface Visitor { + boolean visitBoolean(boolean minePresent, boolean mine, boolean otherPresent, boolean other); + int visitInt(boolean minePresent, int mine, boolean otherPresent, int other); + double visitDouble(boolean minePresent, double mine, boolean otherPresent, double other); + float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other); + long visitLong(boolean minePresent, long mine, boolean otherPresent, long other); + String visitString(boolean minePresent, String mine, boolean otherPresent, String other); + ByteString visitByteString( + boolean minePresent, ByteString mine, boolean otherPresent, ByteString other); + + Object visitOneofBoolean(boolean minePresent, Object mine, Object other); + Object visitOneofInt(boolean minePresent, Object mine, Object other); + Object visitOneofDouble(boolean minePresent, Object mine, Object other); + Object visitOneofFloat(boolean minePresent, Object mine, Object other); + Object visitOneofLong(boolean minePresent, Object mine, Object other); + Object visitOneofString(boolean minePresent, Object mine, Object other); + Object visitOneofByteString(boolean minePresent, Object mine, Object other); + Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other); + Object visitOneofMessage(boolean minePresent, Object mine, Object other); + void visitOneofNotSet(boolean minePresent); + + /** + * Message fields use null sentinals. + */ + T visitMessage(T mine, T other); + LazyFieldLite visitLazyMessage( + boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other); + + ProtobufList visitList(ProtobufList mine, ProtobufList other); + BooleanList visitBooleanList(BooleanList mine, BooleanList other); + IntList visitIntList(IntList mine, IntList other); + DoubleList visitDoubleList(DoubleList mine, DoubleList other); + FloatList visitFloatList(FloatList mine, FloatList other); + LongList visitLongList(LongList mine, LongList other); + FieldSet visitExtensions( + FieldSet mine, FieldSet other); + UnknownFieldSetLite visitUnknownFields(UnknownFieldSetLite mine, UnknownFieldSetLite other); + MapFieldLite visitMap(MapFieldLite mine, MapFieldLite other); + } + + /** + * Implements equals. Throws a {@link NotEqualsException} when not equal. + */ + static class EqualsVisitor implements Visitor { + + static final class NotEqualsException extends RuntimeException {} + + static final EqualsVisitor INSTANCE = new EqualsVisitor(); + + static final NotEqualsException NOT_EQUALS = new NotEqualsException(); + + private EqualsVisitor() {} + + @Override + public boolean visitBoolean( + boolean minePresent, boolean mine, boolean otherPresent, boolean other) { + if (minePresent != otherPresent || mine != other) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) { + if (minePresent != otherPresent || mine != other) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public double visitDouble( + boolean minePresent, double mine, boolean otherPresent, double other) { + if (minePresent != otherPresent || mine != other) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) { + if (minePresent != otherPresent || mine != other) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) { + if (minePresent != otherPresent || mine != other) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public String visitString( + boolean minePresent, String mine, boolean otherPresent, String other) { + if (minePresent != otherPresent || !mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public ByteString visitByteString( + boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) { + if (minePresent != otherPresent || !mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofInt(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofDouble(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofFloat(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofLong(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofString(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofByteString(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) { + if (minePresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { + if (minePresent && ((GeneratedMessageLite) mine).equals(this, (MessageLite) other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public void visitOneofNotSet(boolean minePresent) { + if (minePresent) { + throw NOT_EQUALS; + } + } + + @Override + public T visitMessage(T mine, T other) { + if (mine == null && other == null) { + return null; + } + + if (mine == null || other == null) { + throw NOT_EQUALS; + } + + ((GeneratedMessageLite) mine).equals(this, other); + + return mine; + } + + @Override + public LazyFieldLite visitLazyMessage( + boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) { + if (!minePresent && !otherPresent) { + return mine; + } else if (minePresent && otherPresent && mine.equals(other)) { + return mine; + } + throw NOT_EQUALS; + } + + @Override + public ProtobufList visitList(ProtobufList mine, ProtobufList other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public BooleanList visitBooleanList(BooleanList mine, BooleanList other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public IntList visitIntList(IntList mine, IntList other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public DoubleList visitDoubleList(DoubleList mine, DoubleList other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public FloatList visitFloatList(FloatList mine, FloatList other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public LongList visitLongList(LongList mine, LongList other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public FieldSet visitExtensions( + FieldSet mine, + FieldSet other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public UnknownFieldSetLite visitUnknownFields( + UnknownFieldSetLite mine, + UnknownFieldSetLite other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + + @Override + public MapFieldLite visitMap(MapFieldLite mine, MapFieldLite other) { + if (!mine.equals(other)) { + throw NOT_EQUALS; + } + return mine; + } + } + + /** + * Implements hashCode by accumulating state. + */ + private static class HashCodeVisitor implements Visitor { + + // The caller must ensure that the visitor is invoked parameterized with this and this such that + // other is this. This is required due to how oneof cases are handled. See the class comment + // on Visitor for more information. + + private int hashCode = 0; + + @Override + public boolean visitBoolean( + boolean minePresent, boolean mine, boolean otherPresent, boolean other) { + hashCode = (53 * hashCode) + Internal.hashBoolean(mine); + return mine; + } + + @Override + public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) { + hashCode = (53 * hashCode) + mine; + return mine; + } + + @Override + public double visitDouble( + boolean minePresent, double mine, boolean otherPresent, double other) { + hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits(mine)); + return mine; + } + + @Override + public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) { + hashCode = (53 * hashCode) + Float.floatToIntBits(mine); + return mine; + } + + @Override + public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) { + hashCode = (53 * hashCode) + Internal.hashLong(mine); + return mine; + } + + @Override + public String visitString( + boolean minePresent, String mine, boolean otherPresent, String other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public ByteString visitByteString( + boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + Internal.hashBoolean(((Boolean) mine)); + return mine; + } + + @Override + public Object visitOneofInt(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + (Integer) mine; + return mine; + } + + @Override + public Object visitOneofDouble(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + Internal.hashLong(Double.doubleToLongBits((Double) mine)); + return mine; + } + + @Override + public Object visitOneofFloat(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + Float.floatToIntBits((Float) mine); + return mine; + } + + @Override + public Object visitOneofLong(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + Internal.hashLong((Long) mine); + return mine; + } + + @Override + public Object visitOneofString(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public Object visitOneofByteString(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { + return visitMessage((MessageLite) mine, (MessageLite) other); + } + + @Override + public void visitOneofNotSet(boolean minePresent) { + if (minePresent) { + throw new IllegalStateException(); // Can't happen if other == this. + } + } + + @Override + public T visitMessage(T mine, T other) { + final int protoHash; + if (mine != null) { + if (mine instanceof GeneratedMessageLite) { + protoHash = ((GeneratedMessageLite) mine).hashCode(this); + } else { + protoHash = mine.hashCode(); + } + } else { + protoHash = 37; + } + hashCode = (53 * hashCode) + protoHash; + return mine; + } + + @Override + public LazyFieldLite visitLazyMessage( + boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public ProtobufList visitList(ProtobufList mine, ProtobufList other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public BooleanList visitBooleanList(BooleanList mine, BooleanList other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public IntList visitIntList(IntList mine, IntList other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public DoubleList visitDoubleList(DoubleList mine, DoubleList other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public FloatList visitFloatList(FloatList mine, FloatList other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public LongList visitLongList(LongList mine, LongList other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public FieldSet visitExtensions( + FieldSet mine, + FieldSet other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public UnknownFieldSetLite visitUnknownFields( + UnknownFieldSetLite mine, + UnknownFieldSetLite other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + + @Override + public MapFieldLite visitMap(MapFieldLite mine, MapFieldLite other) { + hashCode = (53 * hashCode) + mine.hashCode(); + return mine; + } + } + + /** + * Implements field merging semantics over the visitor interface. + */ + protected static class MergeFromVisitor implements Visitor { + + public static final MergeFromVisitor INSTANCE = new MergeFromVisitor(); + + private MergeFromVisitor() {} + + @Override + public boolean visitBoolean( + boolean minePresent, boolean mine, boolean otherPresent, boolean other) { + return otherPresent ? other : mine; + } + + @Override + public int visitInt(boolean minePresent, int mine, boolean otherPresent, int other) { + return otherPresent ? other : mine; + } + + @Override + public double visitDouble( + boolean minePresent, double mine, boolean otherPresent, double other) { + return otherPresent ? other : mine; + } + + @Override + public float visitFloat(boolean minePresent, float mine, boolean otherPresent, float other) { + return otherPresent ? other : mine; + } + + @Override + public long visitLong(boolean minePresent, long mine, boolean otherPresent, long other) { + return otherPresent ? other : mine; + } + + @Override + public String visitString( + boolean minePresent, String mine, boolean otherPresent, String other) { + return otherPresent ? other : mine; + } + + @Override + public ByteString visitByteString( + boolean minePresent, ByteString mine, boolean otherPresent, ByteString other) { + return otherPresent ? other : mine; + } + + @Override + public Object visitOneofBoolean(boolean minePresent, Object mine, Object other) { + return other; + } + + @Override + public Object visitOneofInt(boolean minePresent, Object mine, Object other) { + return other; + } + + @Override + public Object visitOneofDouble(boolean minePresent, Object mine, Object other) { + return other; + } + + @Override + public Object visitOneofFloat(boolean minePresent, Object mine, Object other) { + return other; + } + + @Override + public Object visitOneofLong(boolean minePresent, Object mine, Object other) { + return other; + } + + @Override + public Object visitOneofString(boolean minePresent, Object mine, Object other) { + return other; + } + + @Override + public Object visitOneofByteString(boolean minePresent, Object mine, Object other) { + return other; + } + + @Override + public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) { + if (minePresent) { + LazyFieldLite lazy = (LazyFieldLite) mine; + lazy.merge((LazyFieldLite) other); + return lazy; + } + return other; + } + + @Override + public Object visitOneofMessage(boolean minePresent, Object mine, Object other) { + if (minePresent) { + return visitMessage((MessageLite) mine, (MessageLite) other); + } + return other; + } + + @Override + public void visitOneofNotSet(boolean minePresent) { + return; + } + + @SuppressWarnings("unchecked") // Guaranteed by runtime. + @Override + public T visitMessage(T mine, T other) { + if (mine != null && other != null) { + return (T) mine.toBuilder().mergeFrom(other).build(); + } + + return mine != null ? mine : other; + } + + @Override + public LazyFieldLite visitLazyMessage( + boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) { + // LazyFieldLite's are never null so we can just copy across. Necessary to avoid leakage + // from builder into immutable message. + // TODO(dweis): Change to null sentinels? + mine.merge(other); + return mine; + } + + @Override + public ProtobufList visitList(ProtobufList mine, ProtobufList other) { + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + if (!mine.isModifiable()) { + mine = mine.mutableCopyWithCapacity(size + otherSize); + } + mine.addAll(other); + } + + return size > 0 ? mine : other; + } + + @Override + public BooleanList visitBooleanList(BooleanList mine, BooleanList other) { + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + if (!mine.isModifiable()) { + mine = mine.mutableCopyWithCapacity(size + otherSize); + } + mine.addAll(other); + } + + return size > 0 ? mine : other; + } + + @Override + public IntList visitIntList(IntList mine, IntList other) { + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + if (!mine.isModifiable()) { + mine = mine.mutableCopyWithCapacity(size + otherSize); + } + mine.addAll(other); + } + + return size > 0 ? mine : other; + } + + @Override + public DoubleList visitDoubleList(DoubleList mine, DoubleList other) { + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + if (!mine.isModifiable()) { + mine = mine.mutableCopyWithCapacity(size + otherSize); + } + mine.addAll(other); + } + + return size > 0 ? mine : other; + } + + @Override + public FloatList visitFloatList(FloatList mine, FloatList other) { + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + if (!mine.isModifiable()) { + mine = mine.mutableCopyWithCapacity(size + otherSize); + } + mine.addAll(other); + } + + return size > 0 ? mine : other; + } + + @Override + public LongList visitLongList(LongList mine, LongList other) { + int size = mine.size(); + int otherSize = other.size(); + if (size > 0 && otherSize > 0) { + if (!mine.isModifiable()) { + mine = mine.mutableCopyWithCapacity(size + otherSize); + } + mine.addAll(other); + } + + return size > 0 ? mine : other; + } + + @Override + public FieldSet visitExtensions( + FieldSet mine, + FieldSet other) { + if (mine.isImmutable()) { + mine = mine.clone(); + } + mine.mergeFrom(other); + return mine; + } + + @Override + public UnknownFieldSetLite visitUnknownFields( + UnknownFieldSetLite mine, + UnknownFieldSetLite other) { + return other == UnknownFieldSetLite.getDefaultInstance() + ? mine : UnknownFieldSetLite.mutableCopyOf(mine, other); + } + + @Override + public MapFieldLite visitMap(MapFieldLite mine, MapFieldLite other) { + mine.mergeFrom(other); + return mine; + } + } } 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 f4e68ed8..6d6ece5a 100644 --- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java @@ -34,7 +34,6 @@ import com.google.protobuf.Internal.IntList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.RandomAccess; /** @@ -44,8 +43,6 @@ import java.util.RandomAccess; */ final class IntArrayList extends AbstractProtobufList implements IntList, RandomAccess { - private static final int DEFAULT_CAPACITY = 10; - private static final IntArrayList EMPTY_LIST = new IntArrayList(); static { EMPTY_LIST.makeImmutable(); @@ -70,32 +67,55 @@ final class IntArrayList extends AbstractProtobufList implements IntLis * Constructs a new mutable {@code IntArrayList} with default capacity. */ IntArrayList() { - this(DEFAULT_CAPACITY); - } - - /** - * Constructs a new mutable {@code IntArrayList} with the provided capacity. - */ - IntArrayList(int capacity) { - array = new int[capacity]; - size = 0; + this(new int[DEFAULT_CAPACITY], 0); } /** * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}. */ - IntArrayList(List other) { - if (other instanceof IntArrayList) { - IntArrayList list = (IntArrayList) other; - array = list.array.clone(); - size = list.size; - } else { - size = other.size(); - array = new int[size]; - for (int i = 0; i < size; i++) { - array[i] = other.get(i); + private IntArrayList(int[] array, int size) { + this.array = array; + this.size = size; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof IntArrayList)) { + return super.equals(o); + } + IntArrayList other = (IntArrayList) o; + if (size != other.size) { + return false; + } + + final int[] arr = other.array; + for (int i = 0; i < size; i++) { + if (array[i] != arr[i]) { + return false; } } + + return true; + } + + @Override + public int hashCode() { + int result = 1; + for (int i = 0; i < size; i++) { + result = (31 * result) + array[i]; + } + return result; + } + + @Override + public IntList mutableCopyWithCapacity(int capacity) { + if (capacity < size) { + throw new IllegalArgumentException(); + } + return new IntArrayList(Arrays.copyOf(array, capacity), size); } @Override diff --git a/java/core/src/main/java/com/google/protobuf/Internal.java b/java/core/src/main/java/com/google/protobuf/Internal.java index abf7ddd6..d1de375e 100644 --- a/java/core/src/main/java/com/google/protobuf/Internal.java +++ b/java/core/src/main/java/com/google/protobuf/Internal.java @@ -41,6 +41,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.RandomAccess; import java.util.Set; /** @@ -457,10 +458,13 @@ public final class Internal { public static Converter newEnumConverter( final EnumLiteMap enumMap, final T unrecognizedValue) { return new Converter() { + @Override public T doForward(Integer value) { T result = enumMap.findValueByNumber(value); return result == null ? unrecognizedValue : result; } + + @Override public Integer doBackward(T value) { return value.getNumber(); } @@ -573,8 +577,10 @@ public final class Internal { /** * Extends {@link List} to add the capability to make the list immutable and inspect if it is * modifiable. + *

+ * All implementations must support efficient random access. */ - public static interface ProtobufList extends List { + public static interface ProtobufList extends List, RandomAccess { /** * Makes this list immutable. All subsequent modifications will throw an @@ -586,6 +592,11 @@ public final class Internal { * Returns whether this list can be modified via the publicly accessible {@link List} methods. */ boolean isModifiable(); + + /** + * Returns a mutable clone of this list with the specified capacity. + */ + ProtobufList mutableCopyWithCapacity(int capacity); } /** @@ -600,14 +611,20 @@ public final class Internal { int getInt(int index); /** - * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + * Like {@link #add(Integer)} but more efficient in that it doesn't box the element. */ void addInt(int element); /** - * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + * Like {@link #set(int, Integer)} but more efficient in that it doesn't box the element. */ int setInt(int index, int element); + + /** + * Returns a mutable clone of this list with the specified capacity. + */ + @Override + IntList mutableCopyWithCapacity(int capacity); } /** @@ -622,14 +639,20 @@ public final class Internal { boolean getBoolean(int index); /** - * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + * Like {@link #add(Boolean)} but more efficient in that it doesn't box the element. */ void addBoolean(boolean element); /** - * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + * Like {@link #set(int, Boolean)} but more efficient in that it doesn't box the element. */ boolean setBoolean(int index, boolean element); + + /** + * Returns a mutable clone of this list with the specified capacity. + */ + @Override + BooleanList mutableCopyWithCapacity(int capacity); } /** @@ -644,14 +667,20 @@ public final class Internal { long getLong(int index); /** - * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + * Like {@link #add(Long)} but more efficient in that it doesn't box the element. */ void addLong(long element); /** - * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + * Like {@link #set(int, Long)} but more efficient in that it doesn't box the element. */ long setLong(int index, long element); + + /** + * Returns a mutable clone of this list with the specified capacity. + */ + @Override + LongList mutableCopyWithCapacity(int capacity); } /** @@ -666,14 +695,20 @@ public final class Internal { double getDouble(int index); /** - * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + * Like {@link #add(Double)} but more efficient in that it doesn't box the element. */ void addDouble(double element); /** - * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + * Like {@link #set(int, Double)} but more efficient in that it doesn't box the element. */ double setDouble(int index, double element); + + /** + * Returns a mutable clone of this list with the specified capacity. + */ + @Override + DoubleList mutableCopyWithCapacity(int capacity); } /** @@ -688,13 +723,19 @@ public final class Internal { float getFloat(int index); /** - * Like {@link #add(Object)} but more efficient in that it doesn't box the element. + * Like {@link #add(Float)} but more efficient in that it doesn't box the element. */ void addFloat(float element); /** - * Like {@link #set(int, Object)} but more efficient in that it doesn't box the element. + * Like {@link #set(int, Float)} but more efficient in that it doesn't box the element. */ float setFloat(int index, float element); + + /** + * Returns a mutable clone of this list with the specified capacity. + */ + @Override + FloatList mutableCopyWithCapacity(int capacity); } } diff --git a/java/core/src/main/java/com/google/protobuf/LazyField.java b/java/core/src/main/java/com/google/protobuf/LazyField.java index 3da8b900..98e13ca1 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyField.java +++ b/java/core/src/main/java/com/google/protobuf/LazyField.java @@ -95,12 +95,12 @@ public class LazyField extends LazyFieldLite { this.entry = entry; } - // @Override + @Override public K getKey() { return entry.getKey(); } - // @Override + @Override public Object getValue() { LazyField field = entry.getValue(); if (field == null) { @@ -113,7 +113,7 @@ public class LazyField extends LazyFieldLite { return entry.getValue(); } - // @Override + @Override public Object setValue(Object value) { if (!(value instanceof MessageLite)) { throw new IllegalArgumentException( @@ -131,13 +131,13 @@ public class LazyField extends LazyFieldLite { this.iterator = iterator; } - // @Override + @Override public boolean hasNext() { return iterator.hasNext(); } + @Override @SuppressWarnings("unchecked") - // @Override public Entry next() { Entry entry = iterator.next(); if (entry.getValue() instanceof LazyField) { @@ -146,7 +146,7 @@ public class LazyField extends LazyFieldLite { return (Entry) entry; } - // @Override + @Override public void remove() { iterator.remove(); } diff --git a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java index 016ec20d..2febaace 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java +++ b/java/core/src/main/java/com/google/protobuf/LazyFieldLite.java @@ -135,6 +135,43 @@ public class LazyFieldLite { return lf; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof LazyFieldLite)) { + return false; + } + + LazyFieldLite other = (LazyFieldLite) o; + + // Lazy fields do not work well with equals... If both are delayedBytes, we do not have a + // mechanism to deserialize them so we rely on bytes equality. Otherwise we coerce into an + // actual message (if necessary) and call equals on the message itself. This implies that two + // messages can by unequal but then be turned equal simply be invoking a getter on a lazy field. + MessageLite value1 = value; + MessageLite value2 = other.value; + if (value1 == null && value2 == null) { + return toByteString().equals(other.toByteString()); + } else if (value1 != null && value2 != null) { + return value1.equals(value2); + } else if (value1 != null) { + return value1.equals(other.getValue(value1.getDefaultInstanceForType())); + } else { + return getValue(value2.getDefaultInstanceForType()).equals(value2); + } + } + + @Override + public int hashCode() { + // We can't provide a memoizable hash code for lazy fields. The byte strings may have different + // hash codes but evaluate to equivalent messages. And we have no facility for constructing + // a message here if we were not already holding a value. + return 1; + } + /** * Determines whether this LazyFieldLite instance represents the default instance of this type. */ @@ -340,6 +377,8 @@ public class LazyFieldLite { * parsed. Be careful when using this method. */ public int getSerializedSize() { + // We *must* return delayed bytes size if it was ever set because the dependent messages may + // have memoized serialized size based off of it. if (memoizedBytes != null) { return memoizedBytes.size(); } else if (delayedBytes != null) { @@ -358,6 +397,8 @@ public class LazyFieldLite { if (memoizedBytes != null) { return memoizedBytes; } + // We *must* return delayed bytes if it was set because the dependent messages may have + // memoized serialized size based off of it. if (delayedBytes != null) { return delayedBytes; } 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 68c430cf..d474c51e 100644 --- a/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/LazyStringArrayList.java @@ -64,7 +64,7 @@ import java.util.RandomAccess; */ public class LazyStringArrayList extends AbstractProtobufList implements LazyStringList, RandomAccess { - + private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList(); static { EMPTY_LIST.makeImmutable(); @@ -80,11 +80,11 @@ public class LazyStringArrayList extends AbstractProtobufList private final List list; public LazyStringArrayList() { - list = new ArrayList(); + this(DEFAULT_CAPACITY); } public LazyStringArrayList(int intialCapacity) { - list = new ArrayList(intialCapacity); + this(new ArrayList(intialCapacity)); } public LazyStringArrayList(LazyStringList from) { @@ -93,7 +93,21 @@ public class LazyStringArrayList extends AbstractProtobufList } public LazyStringArrayList(List from) { - list = new ArrayList(from); + this(new ArrayList(from)); + } + + private LazyStringArrayList(ArrayList list) { + this.list = list; + } + + @Override + public LazyStringArrayList mutableCopyWithCapacity(int capacity) { + if (capacity < size()) { + throw new IllegalArgumentException(); + } + ArrayList newList = new ArrayList(capacity); + newList.addAll(list); + return new LazyStringArrayList(newList); } @Override @@ -170,7 +184,7 @@ public class LazyStringArrayList extends AbstractProtobufList return ret; } - // @Override + @Override public boolean addAllByteString(Collection values) { ensureIsMutable(); boolean ret = list.addAll(values); @@ -178,7 +192,7 @@ public class LazyStringArrayList extends AbstractProtobufList return ret; } - // @Override + @Override public boolean addAllByteArray(Collection c) { ensureIsMutable(); boolean ret = list.addAll(c); @@ -201,14 +215,14 @@ public class LazyStringArrayList extends AbstractProtobufList modCount++; } - // @Override + @Override public void add(ByteString element) { ensureIsMutable(); list.add(element); modCount++; } - // @Override + @Override public void add(byte[] element) { ensureIsMutable(); list.add(element); @@ -220,7 +234,7 @@ public class LazyStringArrayList extends AbstractProtobufList return list.get(index); } - // @Override + @Override public ByteString getByteString(int index) { Object o = list.get(index); ByteString b = asByteString(o); @@ -230,7 +244,7 @@ public class LazyStringArrayList extends AbstractProtobufList return b; } - // @Override + @Override public byte[] getByteArray(int index) { Object o = list.get(index); byte[] b = asByteArray(o); @@ -240,7 +254,7 @@ public class LazyStringArrayList extends AbstractProtobufList return b; } - // @Override + @Override public void set(int index, ByteString s) { setAndReturn(index, s); } @@ -250,7 +264,7 @@ public class LazyStringArrayList extends AbstractProtobufList return list.set(index, s); } - // @Override + @Override public void set(int index, byte[] s) { setAndReturn(index, s); } @@ -290,12 +304,12 @@ public class LazyStringArrayList extends AbstractProtobufList } } - // @Override + @Override public List getUnderlyingElements() { return Collections.unmodifiableList(list); } - // @Override + @Override public void mergeFrom(LazyStringList other) { ensureIsMutable(); for (Object o : other.getUnderlyingElements()) { @@ -349,7 +363,7 @@ public class LazyStringArrayList extends AbstractProtobufList } } - // @Override + @Override public List asByteArrayList() { return new ByteArrayListView(this); } @@ -393,12 +407,12 @@ public class LazyStringArrayList extends AbstractProtobufList } } - // @Override + @Override public List asByteStringList() { return new ByteStringListView(this); } - // @Override + @Override public LazyStringList getUnmodifiableView() { if (isModifiable()) { return new UnmodifiableLazyStringList(this); 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 ebe62029..bc4475d1 100644 --- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java @@ -34,7 +34,6 @@ import com.google.protobuf.Internal.LongList; import java.util.Arrays; import java.util.Collection; -import java.util.List; import java.util.RandomAccess; /** @@ -44,8 +43,6 @@ import java.util.RandomAccess; */ final class LongArrayList extends AbstractProtobufList implements LongList, RandomAccess { - private static final int DEFAULT_CAPACITY = 10; - private static final LongArrayList EMPTY_LIST = new LongArrayList(); static { EMPTY_LIST.makeImmutable(); @@ -70,32 +67,55 @@ final class LongArrayList extends AbstractProtobufList implements LongList * Constructs a new mutable {@code LongArrayList} with default capacity. */ LongArrayList() { - this(DEFAULT_CAPACITY); - } - - /** - * Constructs a new mutable {@code LongArrayList} with the provided capacity. - */ - LongArrayList(int capacity) { - array = new long[capacity]; - size = 0; + this(new long[DEFAULT_CAPACITY], 0); } /** * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}. */ - LongArrayList(List other) { - if (other instanceof LongArrayList) { - LongArrayList list = (LongArrayList) other; - array = list.array.clone(); - size = list.size; - } else { - size = other.size(); - array = new long[size]; - for (int i = 0; i < size; i++) { - array[i] = other.get(i); + private LongArrayList(long[] array, int size) { + this.array = array; + this.size = size; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof IntArrayList)) { + return super.equals(o); + } + LongArrayList other = (LongArrayList) o; + if (size != other.size) { + return false; + } + + final long[] arr = other.array; + for (int i = 0; i < size; i++) { + if (array[i] != arr[i]) { + return false; } } + + return true; + } + + @Override + public int hashCode() { + int result = 1; + for (int i = 0; i < size; i++) { + result = (31 * result) + Internal.hashLong(array[i]); + } + return result; + } + + @Override + public LongList mutableCopyWithCapacity(int capacity) { + if (capacity < size) { + throw new IllegalArgumentException(); + } + return new LongArrayList(Arrays.copyOf(array, capacity), size); } @Override diff --git a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java index bcffa946..12c64abb 100644 --- a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java +++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java @@ -41,7 +41,8 @@ import java.io.IOException; * * Protobuf internal. Users shouldn't use. */ -public class MapEntryLite extends AbstractMessageLite { +public class MapEntryLite + extends AbstractMessageLite, MapEntryLite.Builder> { private static class Metadata { public final MapEntryLite defaultInstance; public final WireFormat.FieldType keyType; @@ -233,7 +234,7 @@ public class MapEntryLite extends AbstractMessageLite { * Builder used to create {@link MapEntryLite} messages. */ public static class Builder - extends AbstractMessageLite.Builder> { + extends AbstractMessageLite.Builder, Builder> { private final Metadata metadata; private K key; private V value; @@ -327,5 +328,10 @@ public class MapEntryLite extends AbstractMessageLite { this.value = entry.value; return this; } + + @Override + protected Builder internalMergeFrom(MapEntryLite message) { + throw new UnsupportedOperationException(); + } } } diff --git a/java/core/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java index b290993c..907f0f71 100644 --- a/java/core/src/main/java/com/google/protobuf/MapField.java +++ b/java/core/src/main/java/com/google/protobuf/MapField.java @@ -93,15 +93,18 @@ public class MapField implements MutabilityOracle { this.defaultEntry = defaultEntry; } + @Override public Message convertKeyAndValueToMessage(K key, V value) { return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial(); } + @Override public void convertMessageToKeyAndValue(Message message, Map map) { MapEntry entry = (MapEntry) message; map.put(entry.getKey(), entry.getValue()); } + @Override public Message getMessageDefaultInstance() { return defaultEntry; } diff --git a/java/core/src/main/java/com/google/protobuf/Message.java b/java/core/src/main/java/com/google/protobuf/Message.java index 9516d71f..94590fb9 100644 --- a/java/core/src/main/java/com/google/protobuf/Message.java +++ b/java/core/src/main/java/com/google/protobuf/Message.java @@ -51,6 +51,7 @@ import java.util.Map; public interface Message extends MessageLite, MessageOrBuilder { // (From MessageLite, re-declared here only for return type covariance.) + @Override Parser getParserForType(); @@ -97,7 +98,10 @@ public interface Message extends MessageLite, MessageOrBuilder { // Builders // (From MessageLite, re-declared here only for return type covariance.) + @Override Builder newBuilderForType(); + + @Override Builder toBuilder(); /** @@ -106,6 +110,7 @@ public interface Message extends MessageLite, MessageOrBuilder { interface Builder extends MessageLite.Builder, MessageOrBuilder { // (From MessageLite.Builder, re-declared here only for return type // covariance.) + @Override Builder clear(); /** @@ -131,18 +136,27 @@ public interface Message extends MessageLite, MessageOrBuilder { // (From MessageLite.Builder, re-declared here only for return type // covariance.) + @Override Message build(); + + @Override Message buildPartial(); + + @Override Builder clone(); + + @Override Builder mergeFrom(CodedInputStream input) throws IOException; - Builder mergeFrom(CodedInputStream input, - ExtensionRegistryLite extensionRegistry) - throws IOException; + + @Override + Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException; /** * Get the message's type's descriptor. * See {@link Message#getDescriptorForType()}. */ + @Override Descriptors.Descriptor getDescriptorForType(); /** @@ -240,27 +254,39 @@ public interface Message extends MessageLite, MessageOrBuilder { // (From MessageLite.Builder, re-declared here only for return type // covariance.) + @Override Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException; - Builder mergeFrom(ByteString data, - ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException; + + @Override + Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException; + + @Override Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException; - Builder mergeFrom(byte[] data, int off, int len) - throws InvalidProtocolBufferException; - Builder mergeFrom(byte[] data, - ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException; - Builder mergeFrom(byte[] data, int off, int len, - ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException; + + @Override + Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException; + + @Override + Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException; + + @Override + Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException; + + @Override Builder mergeFrom(InputStream input) throws IOException; - Builder mergeFrom(InputStream input, - ExtensionRegistryLite extensionRegistry) - throws IOException; - boolean mergeDelimitedFrom(InputStream input) - throws IOException; - boolean mergeDelimitedFrom(InputStream input, - ExtensionRegistryLite extensionRegistry) - throws IOException; + + @Override + Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException; + + @Override + boolean mergeDelimitedFrom(InputStream input) throws IOException; + + @Override + boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException; } } diff --git a/java/core/src/main/java/com/google/protobuf/MessageLite.java b/java/core/src/main/java/com/google/protobuf/MessageLite.java index 798b7943..88f531df 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageLite.java +++ b/java/core/src/main/java/com/google/protobuf/MessageLite.java @@ -295,6 +295,27 @@ public interface MessageLite extends MessageLiteOrBuilder { Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry) throws IOException; + + /** + * Merge {@code other} into the message being built. {@code other} must + * have the exact same type as {@code this} (i.e. + * {@code getClass().equals(getDefaultInstanceForType().getClass())}). + * + * Merging occurs as follows. For each field:
+ * * For singular primitive fields, if the field is set in {@code other}, + * then {@code other}'s value overwrites the value in this message.
+ * * For singular message fields, if the field is set in {@code other}, + * it is merged into the corresponding sub-message of this message + * using the same merging rules.
+ * * For repeated fields, the elements in {@code other} are concatenated + * with the elements in this message. + * * For oneof groups, if the other message has one of the fields set, + * the group of this message is cleared and replaced by the field + * of the other message, so that the oneof constraint is preserved. + * + * This is equivalent to the {@code Message::MergeFrom} method in C++. + */ + Builder mergeFrom(MessageLite other); /** * Like {@link #mergeFrom(InputStream)}, but does not read until EOF. diff --git a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java index 2a6e0e30..43847651 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java +++ b/java/core/src/main/java/com/google/protobuf/MessageLiteToString.java @@ -30,23 +30,24 @@ package com.google.protobuf; -import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; +import java.util.TreeSet; /** * Helps generate {@link String} representations of {@link MessageLite} protos. */ +// TODO(dweis): Fix map fields. final class MessageLiteToString { - /** - * Suffix for *_FIELD_NUMBER fields. This is used to reflectively detect proto fields that should - * be toString()ed. - */ - private static final String FIELD_NUMBER_NAME_SUFFIX = "_FIELD_NUMBER"; + private static final String LIST_SUFFIX = "List"; + private static final String BUILDER_LIST_SUFFIX = "OrBuilderList"; + private static final String BYTES_SUFFIX = "Bytes"; + /** * Returns a {@link String} representation of the {@link MessageLite} object. The first line of * the {@code String} representation representation includes a comment string to uniquely identify @@ -73,50 +74,68 @@ final class MessageLiteToString { // Build a map of method name to method. We're looking for methods like getFoo(), hasFoo(), and // getFooList() which might be useful for building an object's string representation. Map nameToNoArgMethod = new HashMap(); + Map nameToMethod = new HashMap(); + Set getters = new TreeSet(); for (Method method : messageLite.getClass().getDeclaredMethods()) { + nameToMethod.put(method.getName(), method); if (method.getParameterTypes().length == 0) { nameToNoArgMethod.put(method.getName(), method); + + if (method.getName().startsWith("get")) { + getters.add(method.getName()); + } } } - for (Field field : messageLite.getClass().getDeclaredFields()) { - String fieldName = field.getName(); - // Skip all fields that aren't in a format like "FOO_BAR_FIELD_NUMBER" - if (!fieldName.endsWith(FIELD_NUMBER_NAME_SUFFIX)) { - continue; - } - - // For "FOO_BAR_FIELD_NUMBER" his would be "FOO_BAR" - String upperUnderscore = - fieldName.substring(0, fieldName.length() - FIELD_NUMBER_NAME_SUFFIX.length()); - - // For "FOO_BAR_FIELD_NUMBER" his would be "FooBar" - String upperCamelCaseName = upperUnderscoreToUpperCamel(upperUnderscore); - - // Try to reflectively get the value and toString() the field as if it were optional. This - // only works if the method names have not be proguarded out or renamed. - Method getMethod = nameToNoArgMethod.get("get" + upperCamelCaseName); - Method hasMethod = nameToNoArgMethod.get("has" + upperCamelCaseName); - if (getMethod != null && hasMethod != null) { - if ((Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite)) { + for (String getter : getters) { + String suffix = getter.replaceFirst("get", ""); + if (suffix.endsWith(LIST_SUFFIX) && !suffix.endsWith(BUILDER_LIST_SUFFIX)) { + String camelCase = suffix.substring(0, 1).toLowerCase() + + suffix.substring(1, suffix.length() - LIST_SUFFIX.length()); + // Try to reflectively get the value and toString() the field as if it were repeated. This + // only works if the method names have not be proguarded out or renamed. + Method listMethod = nameToNoArgMethod.get("get" + suffix); + if (listMethod != null) { printField( buffer, indent, - upperUnderscore.toLowerCase(), - GeneratedMessageLite.invokeOrDie(getMethod, messageLite)); + camelCaseToSnakeCase(camelCase), + GeneratedMessageLite.invokeOrDie(listMethod, messageLite)); + continue; } - continue; } - // Try to reflectively get the value and toString() the field as if it were repeated. This + Method setter = nameToMethod.get("set" + suffix); + if (setter == null) { + continue; + } + if (suffix.endsWith(BYTES_SUFFIX) + && nameToNoArgMethod.containsKey( + "get" + suffix.substring(0, suffix.length() - "Bytes".length()))) { + // Heuristic to skip bytes based accessors for string fields. + continue; + } + + String camelCase = suffix.substring(0, 1).toLowerCase() + suffix.substring(1); + + // Try to reflectively get the value and toString() the field as if it were optional. This // only works if the method names have not be proguarded out or renamed. - Method listMethod = nameToNoArgMethod.get("get" + upperCamelCaseName + "List"); - if (listMethod != null) { - printField( - buffer, - indent, - upperUnderscore.toLowerCase(), - GeneratedMessageLite.invokeOrDie(listMethod, messageLite)); + Method getMethod = nameToNoArgMethod.get("get" + suffix); + Method hasMethod = nameToNoArgMethod.get("has" + suffix); + // TODO(dweis): Fix proto3 semantics. + if (getMethod != null) { + Object value = GeneratedMessageLite.invokeOrDie(getMethod, messageLite); + final boolean hasValue = hasMethod == null + ? !isDefaultValue(value) + : (Boolean) GeneratedMessageLite.invokeOrDie(hasMethod, messageLite); + // TODO(dweis): This doesn't stop printing oneof case twice: value and enum style. + if (hasValue) { + printField( + buffer, + indent, + camelCaseToSnakeCase(camelCase), + value); + } continue; } } @@ -130,10 +149,39 @@ final class MessageLiteToString { } } - if (((GeneratedMessageLite) messageLite).unknownFields != null) { - ((GeneratedMessageLite) messageLite).unknownFields.printWithIndent(buffer, indent); + if (((GeneratedMessageLite) messageLite).unknownFields != null) { + ((GeneratedMessageLite) messageLite).unknownFields.printWithIndent(buffer, indent); } } + + private static boolean isDefaultValue(Object o) { + if (o instanceof Boolean) { + return !((Boolean) o); + } + if (o instanceof Integer) { + return ((Integer) o) == 0; + } + if (o instanceof Float) { + return ((Float) o) == 0f; + } + if (o instanceof Double) { + return ((Double) o) == 0d; + } + if (o instanceof String) { + return o.equals(""); + } + if (o instanceof ByteString) { + return o.equals(ByteString.EMPTY); + } + if (o instanceof MessageLite) { // Can happen in oneofs. + return o == ((MessageLite) o).getDefaultInstanceForType(); + } + if (o instanceof java.lang.Enum) { // Catches oneof enums. + return ((java.lang.Enum) o).ordinal() == 0; + } + + return false; + } /** * Formats a text proto field. @@ -166,7 +214,7 @@ final class MessageLiteToString { buffer.append(": \"").append(TextFormatEscaper.escapeBytes((ByteString) object)).append('"'); } else if (object instanceof GeneratedMessageLite) { buffer.append(" {"); - reflectivePrintWithIndent((GeneratedMessageLite) object, buffer, indent + 2); + reflectivePrintWithIndent((GeneratedMessageLite) object, buffer, indent + 2); buffer.append("\n"); for (int i = 0; i < indent; i++) { buffer.append(' '); @@ -176,25 +224,16 @@ final class MessageLiteToString { buffer.append(": ").append(object.toString()); } } - - /** - * A Guava-less implementation of: - * {@code CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, upperUnderscore)} - */ - private static String upperUnderscoreToUpperCamel(String upperUnderscore) { - String upperCamelCaseName = ""; - boolean nextCharacterShouldBeUpper = true; - for (int i = 0; i < upperUnderscore.length(); i++) { - char ch = upperUnderscore.charAt(i); - if (ch == '_') { - nextCharacterShouldBeUpper = true; - } else if (nextCharacterShouldBeUpper){ - upperCamelCaseName += Character.toUpperCase(ch); - nextCharacterShouldBeUpper = false; - } else { - upperCamelCaseName += Character.toLowerCase(ch); + + private static final String camelCaseToSnakeCase(String camelCase) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < camelCase.length(); i++) { + char ch = camelCase.charAt(i); + if (Character.isUpperCase(ch)) { + builder.append("_"); } + builder.append(Character.toLowerCase(ch)); } - return upperCamelCaseName; + return builder.toString(); } } 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 f0fc4859..5e7d7821 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java +++ b/java/core/src/main/java/com/google/protobuf/MessageOrBuilder.java @@ -42,7 +42,7 @@ import java.util.Map; public interface MessageOrBuilder extends MessageLiteOrBuilder { // (From MessageLite, re-declared here only for return type covariance.) - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override Message getDefaultInstanceForType(); /** 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 de4bfd3e..7b791d9e 100644 --- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java +++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java @@ -364,12 +364,14 @@ class MessageReflection { * Finishes the merge and returns the underlying object. */ Object finish(); + } static class BuilderAdapter implements MergeTarget { private final Message.Builder builder; + @Override public Descriptors.Descriptor getDescriptorForType() { return builder.getDescriptorForType(); } @@ -378,6 +380,7 @@ class MessageReflection { this.builder = builder; } + @Override public Object getField(Descriptors.FieldDescriptor field) { return builder.getField(field); } @@ -387,25 +390,27 @@ class MessageReflection { return builder.hasField(field); } - public MergeTarget setField(Descriptors.FieldDescriptor field, - Object value) { + @Override + public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { builder.setField(field, value); return this; } + @Override public MergeTarget clearField(Descriptors.FieldDescriptor field) { builder.clearField(field); return this; } + @Override public MergeTarget setRepeatedField( Descriptors.FieldDescriptor field, int index, Object value) { builder.setRepeatedField(field, index, value); return this; } - public MergeTarget addRepeatedField( - Descriptors.FieldDescriptor field, Object value) { + @Override + public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) { builder.addRepeatedField(field, value); return this; } @@ -426,25 +431,30 @@ class MessageReflection { return builder.getOneofFieldDescriptor(oneof); } + @Override public ContainerType getContainerType() { return ContainerType.MESSAGE; } + @Override public ExtensionRegistry.ExtensionInfo findExtensionByName( ExtensionRegistry registry, String name) { return registry.findImmutableExtensionByName(name); } + @Override public ExtensionRegistry.ExtensionInfo findExtensionByNumber( - ExtensionRegistry registry, Descriptors.Descriptor containingType, - int fieldNumber) { + ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { return registry.findImmutableExtensionByNumber(containingType, fieldNumber); } - public Object parseGroup(CodedInputStream input, + @Override + public Object parseGroup( + CodedInputStream input, ExtensionRegistryLite extensionRegistry, - Descriptors.FieldDescriptor field, Message defaultInstance) + Descriptors.FieldDescriptor field, + Message defaultInstance) throws IOException { Message.Builder subBuilder; // When default instance is not null. The field is an extension field. @@ -463,9 +473,12 @@ class MessageReflection { return subBuilder.buildPartial(); } - public Object parseMessage(CodedInputStream input, + @Override + public Object parseMessage( + CodedInputStream input, ExtensionRegistryLite extensionRegistry, - Descriptors.FieldDescriptor field, Message defaultInstance) + Descriptors.FieldDescriptor field, + Message defaultInstance) throws IOException { Message.Builder subBuilder; // When default instance is not null. The field is an extension field. @@ -484,9 +497,12 @@ class MessageReflection { return subBuilder.buildPartial(); } - public Object parseMessageFromBytes(ByteString bytes, + @Override + public Object parseMessageFromBytes( + ByteString bytes, ExtensionRegistryLite extensionRegistry, - Descriptors.FieldDescriptor field, Message defaultInstance) + Descriptors.FieldDescriptor field, + Message defaultInstance) throws IOException { Message.Builder subBuilder; // When default instance is not null. The field is an extension field. @@ -505,8 +521,9 @@ class MessageReflection { return subBuilder.buildPartial(); } - public MergeTarget newMergeTargetForField(Descriptors.FieldDescriptor field, - Message defaultInstance) { + @Override + public MergeTarget newMergeTargetForField( + Descriptors.FieldDescriptor field, Message defaultInstance) { if (defaultInstance != null) { return new BuilderAdapter( defaultInstance.newBuilderForType()); @@ -515,8 +532,8 @@ class MessageReflection { } } - public WireFormat.Utf8Validation - getUtf8Validation(Descriptors.FieldDescriptor descriptor) { + @Override + public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) { if (descriptor.needsUtf8Check()) { return WireFormat.Utf8Validation.STRICT; } @@ -528,9 +545,11 @@ class MessageReflection { return WireFormat.Utf8Validation.LOOSE; } + @Override public Object finish() { return builder.buildPartial(); } + } @@ -542,38 +561,43 @@ class MessageReflection { this.extensions = extensions; } + @Override public Descriptors.Descriptor getDescriptorForType() { throw new UnsupportedOperationException( "getDescriptorForType() called on FieldSet object"); } + @Override public Object getField(Descriptors.FieldDescriptor field) { return extensions.getField(field); } + @Override public boolean hasField(Descriptors.FieldDescriptor field) { return extensions.hasField(field); } - public MergeTarget setField(Descriptors.FieldDescriptor field, - Object value) { + @Override + public MergeTarget setField(Descriptors.FieldDescriptor field, Object value) { extensions.setField(field, value); return this; } + @Override public MergeTarget clearField(Descriptors.FieldDescriptor field) { extensions.clearField(field); return this; } + @Override public MergeTarget setRepeatedField( Descriptors.FieldDescriptor field, int index, Object value) { extensions.setRepeatedField(field, index, value); return this; } - public MergeTarget addRepeatedField( - Descriptors.FieldDescriptor field, Object value) { + @Override + public MergeTarget addRepeatedField(Descriptors.FieldDescriptor field, Object value) { extensions.addRepeatedField(field, value); return this; } @@ -594,25 +618,31 @@ class MessageReflection { return null; } + @Override public ContainerType getContainerType() { return ContainerType.EXTENSION_SET; } + @Override public ExtensionRegistry.ExtensionInfo findExtensionByName( ExtensionRegistry registry, String name) { return registry.findImmutableExtensionByName(name); } + @Override public ExtensionRegistry.ExtensionInfo findExtensionByNumber( - ExtensionRegistry registry, Descriptors.Descriptor containingType, - int fieldNumber) { + ExtensionRegistry registry, Descriptors.Descriptor containingType, int fieldNumber) { return registry.findImmutableExtensionByNumber(containingType, fieldNumber); } - public Object parseGroup(CodedInputStream input, - ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, - Message defaultInstance) throws IOException { + @Override + public Object parseGroup( + CodedInputStream input, + ExtensionRegistryLite registry, + Descriptors.FieldDescriptor field, + Message defaultInstance) + throws IOException { Message.Builder subBuilder = defaultInstance.newBuilderForType(); if (!field.isRepeated()) { @@ -625,9 +655,13 @@ class MessageReflection { return subBuilder.buildPartial(); } - public Object parseMessage(CodedInputStream input, - ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, - Message defaultInstance) throws IOException { + @Override + public Object parseMessage( + CodedInputStream input, + ExtensionRegistryLite registry, + Descriptors.FieldDescriptor field, + Message defaultInstance) + throws IOException { Message.Builder subBuilder = defaultInstance.newBuilderForType(); if (!field.isRepeated()) { @@ -640,9 +674,13 @@ class MessageReflection { return subBuilder.buildPartial(); } - public Object parseMessageFromBytes(ByteString bytes, - ExtensionRegistryLite registry, Descriptors.FieldDescriptor field, - Message defaultInstance) throws IOException { + @Override + public Object parseMessageFromBytes( + ByteString bytes, + ExtensionRegistryLite registry, + Descriptors.FieldDescriptor field, + Message defaultInstance) + throws IOException { Message.Builder subBuilder = defaultInstance.newBuilderForType(); if (!field.isRepeated()) { Message originalMessage = (Message) getField(field); @@ -654,14 +692,15 @@ class MessageReflection { return subBuilder.buildPartial(); } + @Override public MergeTarget newMergeTargetForField( Descriptors.FieldDescriptor descriptor, Message defaultInstance) { throw new UnsupportedOperationException( "newMergeTargetForField() called on FieldSet object"); } - public WireFormat.Utf8Validation - getUtf8Validation(Descriptors.FieldDescriptor descriptor) { + @Override + public WireFormat.Utf8Validation getUtf8Validation(Descriptors.FieldDescriptor descriptor) { if (descriptor.needsUtf8Check()) { return WireFormat.Utf8Validation.STRICT; } @@ -669,10 +708,12 @@ class MessageReflection { return WireFormat.Utf8Validation.LOOSE; } + @Override public Object finish() { throw new UnsupportedOperationException( "finish() called on FieldSet object"); } + } /** 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 d2f82ac5..81255ec2 100644 --- a/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java +++ b/java/core/src/main/java/com/google/protobuf/ProtobufArrayList.java @@ -38,7 +38,7 @@ import java.util.List; /** * Implements {@link ProtobufList} for non-primitive and {@link String} types. */ -class ProtobufArrayList extends AbstractProtobufList { +final class ProtobufArrayList extends AbstractProtobufList { private static final ProtobufArrayList EMPTY_LIST = new ProtobufArrayList(); static { @@ -51,17 +51,23 @@ class ProtobufArrayList extends AbstractProtobufList { } private final List list; - + ProtobufArrayList() { - list = new ArrayList(); + this(new ArrayList(DEFAULT_CAPACITY)); } - ProtobufArrayList(List toCopy) { - list = new ArrayList(toCopy); + private ProtobufArrayList(List list) { + this.list = list; } - - ProtobufArrayList(int capacity) { - list = new ArrayList(capacity); + + @Override + public ProtobufArrayList mutableCopyWithCapacity(int capacity) { + if (capacity < size()) { + throw new IllegalArgumentException(); + } + List newList = new ArrayList(capacity); + newList.addAll(list); + return new ProtobufArrayList(newList); } @Override diff --git a/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java index 0c8df989..a596d301 100644 --- a/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java +++ b/java/core/src/main/java/com/google/protobuf/ProtocolMessageEnum.java @@ -42,6 +42,7 @@ public interface ProtocolMessageEnum extends Internal.EnumLite { /** * Return the value's numeric value as defined in the .proto file. */ + @Override int getNumber(); /** diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java index f91cdbce..29f567dc 100644 --- a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java +++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java @@ -579,7 +579,7 @@ public class RepeatedFieldBuilder } } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void markDirty() { onChanged(); } @@ -621,10 +621,12 @@ public class RepeatedFieldBuilder this.builder = builder; } + @Override public int size() { return this.builder.getCount(); } + @Override public MType get(int index) { return builder.getMessage(index); } @@ -654,10 +656,12 @@ public class RepeatedFieldBuilder this.builder = builder; } + @Override public int size() { return this.builder.getCount(); } + @Override public BType get(int index) { return builder.getBuilder(index); } @@ -687,10 +691,12 @@ public class RepeatedFieldBuilder this.builder = builder; } + @Override public int size() { return this.builder.getCount(); } + @Override public IType get(int index) { return builder.getMessageOrBuilder(index); } diff --git a/java/core/src/main/java/com/google/protobuf/RpcUtil.java b/java/core/src/main/java/com/google/protobuf/RpcUtil.java index 694b8d13..f7d555ae 100644 --- a/java/core/src/main/java/com/google/protobuf/RpcUtil.java +++ b/java/core/src/main/java/com/google/protobuf/RpcUtil.java @@ -71,6 +71,7 @@ public final class RpcUtil { final Class originalClass, final Type defaultInstance) { return new RpcCallback() { + @Override public void run(final Message parameter) { Type typedParameter; try { @@ -107,8 +108,9 @@ public final class RpcUtil { return new RpcCallback() { private boolean alreadyCalled = false; + @Override public void run(final ParameterType parameter) { - synchronized(this) { + synchronized (this) { if (alreadyCalled) { throw new AlreadyCalledException(); } diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java index aba65e32..941b5def 100644 --- a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java +++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilder.java @@ -234,7 +234,7 @@ public class SingleFieldBuilder } } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void markDirty() { onChanged(); } diff --git a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java index dff19328..409fec10 100644 --- a/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java +++ b/java/core/src/main/java/com/google/protobuf/SmallSortedMap.java @@ -411,22 +411,22 @@ class SmallSortedMap, V> extends AbstractMap { this.value = value; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public K getKey() { return key; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public V getValue() { return value; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public int compareTo(Entry other) { return getKey().compareTo(other.getKey()); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public V setValue(V newValue) { checkMutable(); final V oldValue = this.value; @@ -535,13 +535,13 @@ class SmallSortedMap, V> extends AbstractMap { private boolean nextCalledBeforeRemove; private Iterator> lazyOverflowIterator; - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasNext() { return (pos + 1) < entryList.size() || getOverflowIterator().hasNext(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public Map.Entry next() { nextCalledBeforeRemove = true; // Always increment pos so that we know whether the last returned value @@ -552,7 +552,7 @@ class SmallSortedMap, V> extends AbstractMap { return getOverflowIterator().next(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void remove() { if (!nextCalledBeforeRemove) { throw new IllegalStateException("remove() was called before next()"); @@ -588,31 +588,83 @@ class SmallSortedMap, V> extends AbstractMap { */ private static class EmptySet { - private static final Iterator ITERATOR = new Iterator() { - //@Override (Java 1.6 override semantics, but we must support 1.5) - public boolean hasNext() { - return false; - } - //@Override (Java 1.6 override semantics, but we must support 1.5) - public Object next() { - throw new NoSuchElementException(); - } - //@Override (Java 1.6 override semantics, but we must support 1.5) - public void remove() { - throw new UnsupportedOperationException(); - } - }; + private static final Iterator ITERATOR = + new Iterator() { + @Override + public boolean hasNext() { + return false; + } + @Override + public Object next() { + throw new NoSuchElementException(); + } + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + }; - private static final Iterable ITERABLE = new Iterable() { - //@Override (Java 1.6 override semantics, but we must support 1.5) - public Iterator iterator() { - return ITERATOR; - } - }; + private static final Iterable ITERABLE = + new Iterable() { + @Override + public Iterator iterator() { + return ITERATOR; + } + }; @SuppressWarnings("unchecked") static Iterable iterable() { return (Iterable) ITERABLE; } } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (!(o instanceof SmallSortedMap)) { + return super.equals(o); + } + + SmallSortedMap other = (SmallSortedMap) o; + final int size = size(); + if (size != other.size()) { + return false; + } + + // Best effort try to avoid allocating an entry set. + final int numArrayEntries = getNumArrayEntries(); + if (numArrayEntries != other.getNumArrayEntries()) { + return entrySet().equals(other.entrySet()); + } + + for (int i = 0; i < numArrayEntries; i++) { + if (!getArrayEntryAt(i).equals(other.getArrayEntryAt(i))) { + return false; + } + } + + if (numArrayEntries != size) { + return overflowEntries.equals(other.overflowEntries); + } + + + return true; + } + + @Override + public int hashCode() { + int h = 0; + final int listSize = getNumArrayEntries(); + for (int i = 0; i < listSize; i++) { + h += entryList.get(i).hashCode(); + } + // Avoid the iterator allocation if possible. + if (getNumOverflowEntries() > 0) { + h += overflowEntries.hashCode(); + } + return h; + } } diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java index edf114fa..c1c328fc 100644 --- a/java/core/src/main/java/com/google/protobuf/TextFormat.java +++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java @@ -965,11 +965,13 @@ public final class TextFormat { */ public boolean consumeBoolean() throws ParseException { if (currentToken.equals("true") + || currentToken.equals("True") || currentToken.equals("t") || currentToken.equals("1")) { nextToken(); return true; } else if (currentToken.equals("false") + || currentToken.equals("False") || currentToken.equals("f") || currentToken.equals("0")) { nextToken(); diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java index 7cd2250e..c906420d 100644 --- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java +++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java @@ -76,6 +76,7 @@ public final class UnknownFieldSet implements MessageLite { public static UnknownFieldSet getDefaultInstance() { return defaultInstance; } + @Override public UnknownFieldSet getDefaultInstanceForType() { return defaultInstance; } @@ -126,6 +127,7 @@ public final class UnknownFieldSet implements MessageLite { } /** Serializes the set and writes it to {@code output}. */ + @Override public void writeTo(final CodedOutputStream output) throws IOException { for (final Map.Entry entry : fields.entrySet()) { entry.getValue().writeTo(entry.getKey(), output); @@ -146,6 +148,7 @@ public final class UnknownFieldSet implements MessageLite { * Serializes the message to a {@code ByteString} and returns it. This is * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}. */ + @Override public ByteString toByteString() { try { final ByteString.CodedBuilder out = @@ -163,6 +166,7 @@ public final class UnknownFieldSet implements MessageLite { * Serializes the message to a {@code byte} array and returns it. This is * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}. */ + @Override public byte[] toByteArray() { try { final byte[] result = new byte[getSerializedSize()]; @@ -181,12 +185,14 @@ public final class UnknownFieldSet implements MessageLite { * Serializes the message and writes it to {@code output}. This is just a * trivial wrapper around {@link #writeTo(CodedOutputStream)}. */ + @Override public void writeTo(final OutputStream output) throws IOException { final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); writeTo(codedOutput); codedOutput.flush(); } + @Override public void writeDelimitedTo(OutputStream output) throws IOException { final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output); codedOutput.writeRawVarint32(getSerializedSize()); @@ -195,6 +201,7 @@ public final class UnknownFieldSet implements MessageLite { } /** Get the number of bytes required to encode this set. */ + @Override public int getSerializedSize() { int result = 0; for (final Map.Entry entry : fields.entrySet()) { @@ -228,6 +235,7 @@ public final class UnknownFieldSet implements MessageLite { return result; } + @Override public boolean isInitialized() { // UnknownFieldSets do not have required fields, so they are always // initialized. @@ -258,10 +266,12 @@ public final class UnknownFieldSet implements MessageLite { return newBuilder().mergeFrom(input).build(); } + @Override public Builder newBuilderForType() { return newBuilder(); } + @Override public Builder toBuilder() { return newBuilder().mergeFrom(this); } @@ -329,6 +339,7 @@ public final class UnknownFieldSet implements MessageLite { * in undefined behavior and can cause a {@code NullPointerException} to be * thrown. */ + @Override public UnknownFieldSet build() { getFieldBuilder(0); // Force lastField to be built. final UnknownFieldSet result; @@ -341,6 +352,7 @@ public final class UnknownFieldSet implements MessageLite { return result; } + @Override public UnknownFieldSet buildPartial() { // No required fields, so this is the same as build(). return build(); @@ -353,6 +365,7 @@ public final class UnknownFieldSet implements MessageLite { new UnknownFieldSet(fields)); } + @Override public UnknownFieldSet getDefaultInstanceForType() { return UnknownFieldSet.getDefaultInstance(); } @@ -364,6 +377,7 @@ public final class UnknownFieldSet implements MessageLite { } /** Reset the builder to an empty set. */ + @Override public Builder clear() { reinitialize(); return this; @@ -487,6 +501,7 @@ public final class UnknownFieldSet implements MessageLite { * Parse an entire message from {@code input} and merge its fields into * this set. */ + @Override public Builder mergeFrom(final CodedInputStream input) throws IOException { while (true) { final int tag = input.readTag(); @@ -536,8 +551,8 @@ public final class UnknownFieldSet implements MessageLite { * set being built. This is just a small wrapper around * {@link #mergeFrom(CodedInputStream)}. */ - public Builder mergeFrom(final ByteString data) - throws InvalidProtocolBufferException { + @Override + public Builder mergeFrom(final ByteString data) throws InvalidProtocolBufferException { try { final CodedInputStream input = data.newCodedInput(); mergeFrom(input); @@ -557,8 +572,8 @@ public final class UnknownFieldSet implements MessageLite { * set being built. This is just a small wrapper around * {@link #mergeFrom(CodedInputStream)}. */ - public Builder mergeFrom(final byte[] data) - throws InvalidProtocolBufferException { + @Override + public Builder mergeFrom(final byte[] data) throws InvalidProtocolBufferException { try { final CodedInputStream input = CodedInputStream.newInstance(data); mergeFrom(input); @@ -578,6 +593,7 @@ public final class UnknownFieldSet implements MessageLite { * set being built. This is just a small wrapper around * {@link #mergeFrom(CodedInputStream)}. */ + @Override public Builder mergeFrom(final InputStream input) throws IOException { final CodedInputStream codedInput = CodedInputStream.newInstance(input); mergeFrom(codedInput); @@ -585,8 +601,8 @@ public final class UnknownFieldSet implements MessageLite { return this; } - public boolean mergeDelimitedFrom(InputStream input) - throws IOException { + @Override + public boolean mergeDelimitedFrom(InputStream input) throws IOException { final int firstByte = input.read(); if (firstByte == -1) { return false; @@ -597,30 +613,29 @@ public final class UnknownFieldSet implements MessageLite { return true; } - public boolean mergeDelimitedFrom( - InputStream input, - ExtensionRegistryLite extensionRegistry) throws IOException { + @Override + public boolean mergeDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException { // UnknownFieldSet has no extensions. return mergeDelimitedFrom(input); } - public Builder mergeFrom( - CodedInputStream input, - ExtensionRegistryLite extensionRegistry) throws IOException { + @Override + public Builder mergeFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException { // UnknownFieldSet has no extensions. return mergeFrom(input); } - public Builder mergeFrom( - ByteString data, - ExtensionRegistryLite extensionRegistry) + @Override + public Builder mergeFrom(ByteString data, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { // UnknownFieldSet has no extensions. return mergeFrom(data); } - public Builder mergeFrom(byte[] data, int off, int len) - throws InvalidProtocolBufferException { + @Override + public Builder mergeFrom(byte[] data, int off, int len) throws InvalidProtocolBufferException { try { final CodedInputStream input = CodedInputStream.newInstance(data, off, len); @@ -636,29 +651,37 @@ public final class UnknownFieldSet implements MessageLite { } } - public Builder mergeFrom( - byte[] data, - ExtensionRegistryLite extensionRegistry) + @Override + public Builder mergeFrom(byte[] data, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { // UnknownFieldSet has no extensions. return mergeFrom(data); } - public Builder mergeFrom( - byte[] data, int off, int len, - ExtensionRegistryLite extensionRegistry) + @Override + public Builder mergeFrom(byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { // UnknownFieldSet has no extensions. return mergeFrom(data, off, len); } - public Builder mergeFrom( - InputStream input, - ExtensionRegistryLite extensionRegistry) throws IOException { + @Override + public Builder mergeFrom(InputStream input, ExtensionRegistryLite extensionRegistry) + throws IOException { // UnknownFieldSet has no extensions. return mergeFrom(input); } + @Override + public Builder mergeFrom(MessageLite m) { + if (m instanceof UnknownFieldSet) { + return mergeFrom((UnknownFieldSet) m); + } + throw new IllegalArgumentException( + "mergeFrom(MessageLite) can only merge messages of the same type."); + } + + @Override public boolean isInitialized() { // UnknownFieldSets do not have required fields, so they are always // initialized. @@ -987,6 +1010,7 @@ public final class UnknownFieldSet implements MessageLite { * Parser to implement MessageLite interface. */ public static final class Parser extends AbstractParser { + @Override public UnknownFieldSet parsePartialFrom( CodedInputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { @@ -1004,6 +1028,7 @@ public final class UnknownFieldSet implements MessageLite { } private static final Parser PARSER = new Parser(); + @Override public final Parser getParserForType() { return PARSER; } diff --git a/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java index 5257c5a2..30e87911 100644 --- a/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java +++ b/java/core/src/main/java/com/google/protobuf/UnmodifiableLazyStringList.java @@ -68,42 +68,42 @@ public class UnmodifiableLazyStringList extends AbstractList return list.size(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public ByteString getByteString(int index) { return list.getByteString(index); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void add(ByteString element) { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void set(int index, ByteString element) { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean addAllByteString(Collection element) { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public byte[] getByteArray(int index) { return list.getByteArray(index); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void add(byte[] element) { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void set(int index, byte[] element) { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean addAllByteArray(Collection element) { throw new UnsupportedOperationException(); } @@ -113,47 +113,47 @@ public class UnmodifiableLazyStringList extends AbstractList return new ListIterator() { ListIterator iter = list.listIterator(index); - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasNext() { return iter.hasNext(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public String next() { return iter.next(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasPrevious() { return iter.hasPrevious(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public String previous() { return iter.previous(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public int nextIndex() { return iter.nextIndex(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public int previousIndex() { return iter.previousIndex(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void remove() { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void set(String o) { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void add(String o) { throw new UnsupportedOperationException(); } @@ -165,45 +165,45 @@ public class UnmodifiableLazyStringList extends AbstractList return new Iterator() { Iterator iter = list.iterator(); - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public boolean hasNext() { return iter.hasNext(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public String next() { return iter.next(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void remove() { throw new UnsupportedOperationException(); } }; } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public List getUnderlyingElements() { // The returned value is already unmodifiable. return list.getUnderlyingElements(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void mergeFrom(LazyStringList other) { throw new UnsupportedOperationException(); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public List asByteArrayList() { return Collections.unmodifiableList(list.asByteArrayList()); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public List asByteStringList() { return Collections.unmodifiableList(list.asByteStringList()); } - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public LazyStringList getUnmodifiableView() { return this; } diff --git a/java/core/src/main/java/com/google/protobuf/WireFormat.java b/java/core/src/main/java/com/google/protobuf/WireFormat.java index 8dbe1ae3..6a58b081 100644 --- a/java/core/src/main/java/com/google/protobuf/WireFormat.java +++ b/java/core/src/main/java/com/google/protobuf/WireFormat.java @@ -116,16 +116,24 @@ public final class WireFormat { FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ), BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ), STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED) { - public boolean isPackable() { return false; } + @Override + public boolean isPackable() { + return false; } }, GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ) { - public boolean isPackable() { return false; } + @Override + public boolean isPackable() { + return false; } }, MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED) { - public boolean isPackable() { return false; } + @Override + public boolean isPackable() { + return false; } }, BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED) { - public boolean isPackable() { return false; } + @Override + public boolean isPackable() { + return false; } }, UINT32 (JavaType.INT , WIRETYPE_VARINT ), ENUM (JavaType.ENUM , WIRETYPE_VARINT ), @@ -170,18 +178,21 @@ public final class WireFormat { enum Utf8Validation { /** Eagerly parses to String; silently accepts invalid UTF8 bytes. */ LOOSE { + @Override Object readString(CodedInputStream input) throws IOException { return input.readString(); } }, /** Eagerly parses to String; throws an IOException on invalid bytes. */ STRICT { + @Override Object readString(CodedInputStream input) throws IOException { return input.readStringRequireUtf8(); } }, /** Keep data as ByteString; validation/conversion to String is lazy. */ LAZY { + @Override Object readString(CodedInputStream input) throws IOException { return input.readBytes(); } diff --git a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java index 1e57b647..7dc9fc15 100644 --- a/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/AbstractMessageTest.java @@ -64,35 +64,44 @@ public class AbstractMessageTest extends TestCase { this.wrappedMessage = wrappedMessage; } + @Override public Descriptors.Descriptor getDescriptorForType() { return wrappedMessage.getDescriptorForType(); } + @Override public AbstractMessageWrapper getDefaultInstanceForType() { return new AbstractMessageWrapper( wrappedMessage.getDefaultInstanceForType()); } + @Override public Map getAllFields() { return wrappedMessage.getAllFields(); } + @Override public boolean hasField(Descriptors.FieldDescriptor field) { return wrappedMessage.hasField(field); } + @Override public Object getField(Descriptors.FieldDescriptor field) { return wrappedMessage.getField(field); } + @Override public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { return wrappedMessage.getRepeatedFieldCount(field); } - public Object getRepeatedField( - Descriptors.FieldDescriptor field, int index) { + @Override + public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) { return wrappedMessage.getRepeatedField(field, index); } + @Override public UnknownFieldSet getUnknownFields() { return wrappedMessage.getUnknownFields(); } + @Override public Builder newBuilderForType() { return new Builder(wrappedMessage.newBuilderForType()); } + @Override public Builder toBuilder() { return new Builder(wrappedMessage.toBuilder()); } @@ -104,65 +113,80 @@ public class AbstractMessageTest extends TestCase { this.wrappedBuilder = wrappedBuilder; } + @Override public AbstractMessageWrapper build() { return new AbstractMessageWrapper(wrappedBuilder.build()); } + @Override public AbstractMessageWrapper buildPartial() { return new AbstractMessageWrapper(wrappedBuilder.buildPartial()); } + @Override public Builder clone() { return new Builder(wrappedBuilder.clone()); } + @Override public boolean isInitialized() { return clone().buildPartial().isInitialized(); } + @Override public Descriptors.Descriptor getDescriptorForType() { return wrappedBuilder.getDescriptorForType(); } + @Override public AbstractMessageWrapper getDefaultInstanceForType() { return new AbstractMessageWrapper( wrappedBuilder.getDefaultInstanceForType()); } + @Override public Map getAllFields() { return wrappedBuilder.getAllFields(); } + @Override public Builder newBuilderForField(Descriptors.FieldDescriptor field) { return new Builder(wrappedBuilder.newBuilderForField(field)); } + @Override public boolean hasField(Descriptors.FieldDescriptor field) { return wrappedBuilder.hasField(field); } + @Override public Object getField(Descriptors.FieldDescriptor field) { return wrappedBuilder.getField(field); } + @Override public Builder setField(Descriptors.FieldDescriptor field, Object value) { wrappedBuilder.setField(field, value); return this; } + @Override public Builder clearField(Descriptors.FieldDescriptor field) { wrappedBuilder.clearField(field); return this; } + @Override public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { return wrappedBuilder.getRepeatedFieldCount(field); } - public Object getRepeatedField( - Descriptors.FieldDescriptor field, int index) { + @Override + public Object getRepeatedField(Descriptors.FieldDescriptor field, int index) { return wrappedBuilder.getRepeatedField(field, index); } - public Builder setRepeatedField(Descriptors.FieldDescriptor field, - int index, Object value) { + @Override + public Builder setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value) { wrappedBuilder.setRepeatedField(field, index, value); return this; } - public Builder addRepeatedField( - Descriptors.FieldDescriptor field, Object value) { + @Override + public Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value) { wrappedBuilder.addRepeatedField(field, value); return this; } + @Override public UnknownFieldSet getUnknownFields() { return wrappedBuilder.getUnknownFields(); } + @Override public Builder setUnknownFields(UnknownFieldSet unknownFields) { wrappedBuilder.setUnknownFields(unknownFields); return this; @@ -172,6 +196,7 @@ public class AbstractMessageTest extends TestCase { return wrappedBuilder.getFieldBuilder(field); } } + @Override public Parser getParserForType() { return wrappedMessage.getParserForType(); } diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java index b8ad1fe4..24b96c60 100644 --- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java @@ -73,20 +73,6 @@ public class BooleanArrayListTest extends TestCase { assertImmutable(list); } - public void testCopyConstructor() { - BooleanArrayList copy = new BooleanArrayList(TERTIARY_LIST); - assertEquals(TERTIARY_LIST, copy); - - copy = new BooleanArrayList(BooleanArrayList.emptyList()); - assertEquals(BooleanArrayList.emptyList(), copy); - - copy = new BooleanArrayList(asList(false, false, true)); - assertEquals(asList(false, false, true), copy); - - copy = new BooleanArrayList(Collections.emptyList()); - assertEquals(BooleanArrayList.emptyList(), copy); - } - public void testModificationWithIteration() { list.addAll(asList(true, false, false, true)); Iterator iterator = list.iterator(); diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java index a1d6f1be..ca940ced 100644 --- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java +++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java @@ -81,10 +81,12 @@ public class CodedInputStreamTest extends TestCase { this.blockSize = blockSize; } + @Override public int read(byte[] b) throws IOException { return super.read(b, 0, Math.min(b.length, blockSize)); } + @Override public int read(byte[] b, int off, int len) throws IOException { return super.read(b, off, Math.min(len, blockSize)); } diff --git a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java index 6018ea55..33aa4357 100644 --- a/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java +++ b/java/core/src/test/java/com/google/protobuf/CodedOutputStreamTest.java @@ -30,6 +30,7 @@ package com.google.protobuf; +import com.google.protobuf.CodedOutputStream.OutOfSpaceException; import protobuf_unittest.UnittestProto.SparseEnumMessage; import protobuf_unittest.UnittestProto.TestAllTypes; import protobuf_unittest.UnittestProto.TestPackedTypes; @@ -50,118 +51,180 @@ import java.util.List; * @author kenton@google.com Kenton Varda */ public class CodedOutputStreamTest extends TestCase { - /** - * Helper to construct a byte array from a bunch of bytes. The inputs are - * actually ints so that I can use hex notation and not get stupid errors - * about precision. - */ - private byte[] bytes(int... bytesAsInts) { - byte[] bytes = new byte[bytesAsInts.length]; - for (int i = 0; i < bytesAsInts.length; i++) { - bytes[i] = (byte) bytesAsInts[i]; - } - return bytes; + private interface Coder { + CodedOutputStream stream(); + + byte[] toByteArray(); + + OutputType getOutputType(); } - /** Arrays.asList() does not work with arrays of primitives. :( */ - private List toList(byte[] bytes) { - List result = new ArrayList(); - for (byte b : bytes) { - result.add(b); + private static final class OutputStreamCoder implements Coder { + private final CodedOutputStream stream; + private final ByteArrayOutputStream output; + + OutputStreamCoder(int size) { + output = new ByteArrayOutputStream(); + stream = CodedOutputStream.newInstance(output, size); + } + + @Override + public CodedOutputStream stream() { + return stream; + } + + @Override + public byte[] toByteArray() { + return output.toByteArray(); + } + + @Override + public OutputType getOutputType() { + return OutputType.STREAM; } - return result; } - private void assertEqualBytes(byte[] a, byte[] b) { - assertEquals(toList(a), toList(b)); + private static final class ArrayCoder implements Coder { + private final CodedOutputStream stream; + private final byte[] bytes; + + ArrayCoder(int size) { + bytes = new byte[size]; + stream = CodedOutputStream.newInstance(bytes); + } + + @Override + public CodedOutputStream stream() { + return stream; + } + + @Override + public byte[] toByteArray() { + return Arrays.copyOf(bytes, stream.getTotalBytesWritten()); + } + + @Override + public OutputType getOutputType() { + return OutputType.ARRAY; + } } - /** - * Writes the given value using writeRawVarint32() and writeRawVarint64() and - * checks that the result matches the given bytes. - */ - private void assertWriteVarint(byte[] data, long value) throws Exception { - // Only test 32-bit write if the value fits into an int. - if (value == (int) value) { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); - output.writeRawVarint32((int) value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); + private static final class NioHeapCoder implements Coder { + private final CodedOutputStream stream; + private final ByteBuffer buffer; + private final int initialPosition; - // Also try computing size. - assertEquals(data.length, - CodedOutputStream.computeRawVarint32Size((int) value)); + NioHeapCoder(int size) { + this(size, 0); } - { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); - output.writeRawVarint64(value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); - - // Also try computing size. - assertEquals(data.length, - CodedOutputStream.computeRawVarint64Size(value)); + NioHeapCoder(int size, int initialPosition) { + this.initialPosition = initialPosition; + buffer = ByteBuffer.allocate(size); + buffer.position(initialPosition); + stream = CodedOutputStream.newInstance(buffer); } - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { - // Only test 32-bit write if the value fits into an int. - if (value == (int) value) { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = - CodedOutputStream.newInstance(rawOutput, blockSize); - output.writeRawVarint32((int) value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); + @Override + public CodedOutputStream stream() { + return stream; + } + + @Override + public byte[] toByteArray() { + ByteBuffer dup = buffer.duplicate(); + dup.position(initialPosition); + dup.limit(buffer.position()); + + byte[] bytes = new byte[dup.remaining()]; + dup.get(bytes); + return bytes; + } + + @Override + public OutputType getOutputType() { + return OutputType.NIO_HEAP; + } + } + + private static final class NioDirectCoder implements Coder { + private final int initialPosition; + private final CodedOutputStream stream; + private final ByteBuffer buffer; + + NioDirectCoder(int size) { + this(size, 0); + } + + NioDirectCoder(int size, int initialPosition) { + this.initialPosition = initialPosition; + buffer = ByteBuffer.allocateDirect(size); + buffer.position(initialPosition); + stream = CodedOutputStream.newInstance(buffer); + } + + @Override + public CodedOutputStream stream() { + return stream; + } + + @Override + public byte[] toByteArray() { + ByteBuffer dup = buffer.duplicate(); + dup.position(initialPosition); + dup.limit(buffer.position()); + + byte[] bytes = new byte[dup.remaining()]; + dup.get(bytes); + return bytes; + } + + @Override + public OutputType getOutputType() { + return OutputType.NIO_DIRECT; + } + } + + private enum OutputType { + ARRAY() { + @Override + Coder newCoder(int size) { + return new ArrayCoder(size); } - - { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = - CodedOutputStream.newInstance(rawOutput, blockSize); - output.writeRawVarint64(value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); + }, + NIO_HEAP() { + @Override + Coder newCoder(int size) { + return new NioHeapCoder(size); } - } - } + }, + NIO_DIRECT() { + @Override + Coder newCoder(int size) { + return new NioDirectCoder(size); + } + }, + STREAM() { + @Override + Coder newCoder(int size) { + return new OutputStreamCoder(size); + } + }; - private void assertVarintRoundTrip(long value) throws Exception { - { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); - output.writeRawVarint64(value); - output.flush(); - byte[] bytes = rawOutput.toByteArray(); - assertEquals(bytes.length, CodedOutputStream.computeRawVarint64Size(value)); - CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes)); - assertEquals(value, input.readRawVarint64()); - } - - if (value == (int) value) { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); - output.writeRawVarint32((int) value); - output.flush(); - byte[] bytes = rawOutput.toByteArray(); - assertEquals(bytes.length, CodedOutputStream.computeRawVarint32Size((int) value)); - CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes)); - assertEquals(value, input.readRawVarint32()); - } + abstract Coder newCoder(int size); } /** Checks that invariants are maintained for varint round trip input and output. */ public void testVarintRoundTrips() throws Exception { - assertVarintRoundTrip(0L); - for (int bits = 0; bits < 64; bits++) { - long value = 1L << bits; - assertVarintRoundTrip(value); - assertVarintRoundTrip(value + 1); - assertVarintRoundTrip(value - 1); - assertVarintRoundTrip(-value); + for (OutputType outputType : OutputType.values()) { + assertVarintRoundTrip(outputType, 0L); + for (int bits = 0; bits < 64; bits++) { + long value = 1L << bits; + assertVarintRoundTrip(outputType, value); + assertVarintRoundTrip(outputType, value + 1); + assertVarintRoundTrip(outputType, value - 1); + assertVarintRoundTrip(outputType, -value); + } } } @@ -173,70 +236,25 @@ public class CodedOutputStreamTest extends TestCase { // 14882 assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); // 2961488830 - assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x0bL << 28)); + assertWriteVarint( + bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28)); // 64-bit // 7256456126 - assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), - (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | - (0x1bL << 28)); + assertWriteVarint( + bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), + (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28)); // 41256202580718336 assertWriteVarint( - bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), - (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | - (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); + bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), + (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | (0x43L << 28) | (0x49L << 35) + | (0x24L << 42) | (0x49L << 49)); // 11964378330978735131 assertWriteVarint( - bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), - (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | - (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | - (0x05L << 49) | (0x26L << 56) | (0x01L << 63)); - } - - /** - * Parses the given bytes using writeRawLittleEndian32() and checks - * that the result matches the given value. - */ - private void assertWriteLittleEndian32(byte[] data, int value) - throws Exception { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); - output.writeRawLittleEndian32(value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { - rawOutput = new ByteArrayOutputStream(); - output = CodedOutputStream.newInstance(rawOutput, blockSize); - output.writeRawLittleEndian32(value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); - } - } - - /** - * Parses the given bytes using writeRawLittleEndian64() and checks - * that the result matches the given value. - */ - private void assertWriteLittleEndian64(byte[] data, long value) - throws Exception { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); - output.writeRawLittleEndian64(value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); - - // Try different block sizes. - for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { - rawOutput = new ByteArrayOutputStream(); - output = CodedOutputStream.newInstance(rawOutput, blockSize); - output.writeRawLittleEndian64(value); - output.flush(); - assertEqualBytes(data, rawOutput.toByteArray()); - } + bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), + (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | (0x3bL << 28) | (0x56L << 35) + | (0x00L << 42) | (0x05L << 49) | (0x26L << 56) | (0x01L << 63)); } /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */ @@ -245,141 +263,138 @@ public class CodedOutputStreamTest extends TestCase { assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); assertWriteLittleEndian64( - bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), - 0x123456789abcdef0L); + bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef0L); assertWriteLittleEndian64( - bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), - 0x9abcdef012345678L); + bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678L); } /** Test encodeZigZag32() and encodeZigZag64(). */ public void testEncodeZigZag() throws Exception { - assertEquals(0, CodedOutputStream.encodeZigZag32( 0)); + assertEquals(0, CodedOutputStream.encodeZigZag32(0)); assertEquals(1, CodedOutputStream.encodeZigZag32(-1)); - assertEquals(2, CodedOutputStream.encodeZigZag32( 1)); + assertEquals(2, CodedOutputStream.encodeZigZag32(1)); assertEquals(3, CodedOutputStream.encodeZigZag32(-2)); assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF)); assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000)); assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF)); assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000)); - assertEquals(0, CodedOutputStream.encodeZigZag64( 0)); + assertEquals(0, CodedOutputStream.encodeZigZag64(0)); assertEquals(1, CodedOutputStream.encodeZigZag64(-1)); - assertEquals(2, CodedOutputStream.encodeZigZag64( 1)); + assertEquals(2, CodedOutputStream.encodeZigZag64(1)); assertEquals(3, CodedOutputStream.encodeZigZag64(-2)); - assertEquals(0x000000007FFFFFFEL, - CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL)); - assertEquals(0x000000007FFFFFFFL, - CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L)); - assertEquals(0x00000000FFFFFFFEL, - CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL)); - assertEquals(0x00000000FFFFFFFFL, - CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L)); - assertEquals(0xFFFFFFFFFFFFFFFEL, - CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL)); - assertEquals(0xFFFFFFFFFFFFFFFFL, - CodedOutputStream.encodeZigZag64(0x8000000000000000L)); + assertEquals(0x000000007FFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL)); + assertEquals(0x000000007FFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L)); + assertEquals(0x00000000FFFFFFFEL, CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL)); + assertEquals(0x00000000FFFFFFFFL, CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L)); + assertEquals(0xFFFFFFFFFFFFFFFEL, CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL)); + assertEquals(0xFFFFFFFFFFFFFFFFL, CodedOutputStream.encodeZigZag64(0x8000000000000000L)); // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) // were chosen semi-randomly via keyboard bashing. - assertEquals(0, - CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0))); - assertEquals(1, - CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1))); - assertEquals(-1, - CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1))); - assertEquals(14927, - CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927))); - assertEquals(-3612, - CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612))); + assertEquals(0, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0))); + assertEquals(1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1))); + assertEquals(-1, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1))); + assertEquals(14927, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927))); + assertEquals(-3612, CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612))); - assertEquals(0, - CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0))); - assertEquals(1, - CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1))); - assertEquals(-1, - CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1))); - assertEquals(14927, - CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927))); - assertEquals(-3612, - CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612))); + assertEquals(0, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0))); + assertEquals(1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1))); + assertEquals(-1, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1))); + assertEquals(14927, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927))); + assertEquals(-3612, CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612))); - assertEquals(856912304801416L, - CodedOutputStream.encodeZigZag64( - CodedInputStream.decodeZigZag64( - 856912304801416L))); - assertEquals(-75123905439571256L, - CodedOutputStream.encodeZigZag64( - CodedInputStream.decodeZigZag64( - -75123905439571256L))); + assertEquals( + 856912304801416L, + CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(856912304801416L))); + assertEquals( + -75123905439571256L, + CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-75123905439571256L))); } /** Tests writing a whole message with every field type. */ public void testWriteWholeMessage() throws Exception { + final byte[] expectedBytes = TestUtil.getGoldenMessage().toByteArray(); TestAllTypes message = TestUtil.getAllSet(); - byte[] rawBytes = message.toByteArray(); - assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes); + for (OutputType outputType : OutputType.values()) { + Coder coder = outputType.newCoder(message.getSerializedSize()); + message.writeTo(coder.stream()); + coder.stream().flush(); + byte[] rawBytes = coder.toByteArray(); + assertEqualBytes(outputType, expectedBytes, rawBytes); + } // Try different block sizes. for (int blockSize = 1; blockSize < 256; blockSize *= 2) { - ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); - CodedOutputStream output = - CodedOutputStream.newInstance(rawOutput, blockSize); - message.writeTo(output); - output.flush(); - assertEqualBytes(rawBytes, rawOutput.toByteArray()); + Coder coder = OutputType.STREAM.newCoder(blockSize); + message.writeTo(coder.stream()); + coder.stream().flush(); + assertEqualBytes(OutputType.STREAM, expectedBytes, coder.toByteArray()); } } - /** Tests writing a whole message with every packed field type. Ensures the - * wire format of packed fields is compatible with C++. */ + /** + * Tests writing a whole message with every packed field type. Ensures the + * wire format of packed fields is compatible with C++. + */ public void testWriteWholePackedFieldsMessage() throws Exception { + byte[] expectedBytes = TestUtil.getGoldenPackedFieldsMessage().toByteArray(); TestPackedTypes message = TestUtil.getPackedSet(); - byte[] rawBytes = message.toByteArray(); - assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(), - rawBytes); + for (OutputType outputType : OutputType.values()) { + Coder coder = outputType.newCoder(message.getSerializedSize()); + message.writeTo(coder.stream()); + coder.stream().flush(); + byte[] rawBytes = coder.toByteArray(); + assertEqualBytes(outputType, expectedBytes, rawBytes); + } } - /** Test writing a message containing a negative enum value. This used to + /** + * Test writing a message containing a negative enum value. This used to * fail because the size was not properly computed as a sign-extended varint. */ public void testWriteMessageWithNegativeEnumValue() throws Exception { - SparseEnumMessage message = SparseEnumMessage.newBuilder() - .setSparseEnum(TestSparseEnum.SPARSE_E) .build(); + SparseEnumMessage message = + SparseEnumMessage.newBuilder().setSparseEnum(TestSparseEnum.SPARSE_E).build(); assertTrue(message.getSparseEnum().getNumber() < 0); - byte[] rawBytes = message.toByteArray(); - SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes); - assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum()); + for (OutputType outputType : OutputType.values()) { + Coder coder = outputType.newCoder(message.getSerializedSize()); + message.writeTo(coder.stream()); + coder.stream().flush(); + byte[] rawBytes = coder.toByteArray(); + SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes); + assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum()); + } } /** Test getTotalBytesWritten() */ public void testGetTotalBytesWritten() throws Exception { - final int BUFFER_SIZE = 4 * 1024; - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(BUFFER_SIZE); - CodedOutputStream codedStream = CodedOutputStream.newInstance(outputStream); + Coder coder = OutputType.STREAM.newCoder(4 * 1024); + + // Write some some bytes (more than the buffer can hold) and verify that totalWritten + // is correct. byte[] value = "abcde".getBytes(Internal.UTF_8); for (int i = 0; i < 1024; ++i) { - codedStream.writeRawBytes(value, 0, value.length); + coder.stream().writeRawBytes(value, 0, value.length); } + assertEquals(value.length * 1024, coder.stream().getTotalBytesWritten()); + + // Now write an encoded string. String string = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"; // Ensure we take the slower fast path. - assertTrue(CodedOutputStream.computeRawVarint32Size(string.length()) - != CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR)); - - codedStream.writeStringNoTag(string); + assertTrue(CodedOutputStream.computeUInt32SizeNoTag(string.length()) + != CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR)); + + coder.stream().writeStringNoTag(string); int stringSize = CodedOutputStream.computeStringSizeNoTag(string); - - // Make sure we have written more bytes than the buffer could hold. This is - // to make the test complete. - assertTrue(codedStream.getTotalBytesWritten() > BUFFER_SIZE); - + // Verify that the total bytes written is correct - assertEquals((value.length * 1024) + stringSize, codedStream.getTotalBytesWritten()); + assertEquals((value.length * 1024) + stringSize, coder.stream().getTotalBytesWritten()); } - + // TODO(dweis): Write a comprehensive test suite for CodedOutputStream that covers more than just // this case. public void testWriteStringNoTag_fastpath() throws Exception { @@ -390,14 +405,16 @@ public class CodedOutputStreamTest extends TestCase { string += threeBytesPer; } // These checks ensure we will tickle the slower fast path. - assertEquals(1, CodedOutputStream.computeRawVarint32Size(string.length())); + assertEquals(1, CodedOutputStream.computeUInt32SizeNoTag(string.length())); assertEquals( - 2, CodedOutputStream.computeRawVarint32Size(string.length() * Utf8.MAX_BYTES_PER_CHAR)); + 2, CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_BYTES_PER_CHAR)); assertEquals(bufferSize, string.length() * Utf8.MAX_BYTES_PER_CHAR); - - CodedOutputStream output = - CodedOutputStream.newInstance(ByteBuffer.allocate(bufferSize), bufferSize); - output.writeStringNoTag(string); + + for (OutputType outputType : OutputType.values()) { + Coder coder = outputType.newCoder(bufferSize + 2); + coder.stream().writeStringNoTag(string); + coder.stream().flush(); + } } public void testWriteToByteBuffer() throws Exception { @@ -464,83 +481,296 @@ public class CodedOutputStreamTest extends TestCase { byte[] destination = new byte[4]; CodedOutputStream codedStream = CodedOutputStream.newInstance(destination); codedStream.writeByteArrayNoTag(fullArray, 2, 2); - assertEqualBytes(bytes(0x02, 0x33, 0x44, 0x00), destination); + assertEqualBytes(OutputType.ARRAY, bytes(0x02, 0x33, 0x44, 0x00), destination); assertEquals(3, codedStream.getTotalBytesWritten()); } - + + public void testSerializeUtf8_MultipleSmallWrites() throws Exception { + final String source = "abcdefghijklmnopqrstuvwxyz"; + + // Generate the expected output if the source string is written 2 bytes at a time. + ByteArrayOutputStream expectedBytesStream = new ByteArrayOutputStream(); + for (int pos = 0; pos < source.length(); pos += 2) { + String substr = source.substring(pos, pos + 2); + expectedBytesStream.write(2); + expectedBytesStream.write(substr.getBytes(Internal.UTF_8)); + } + final byte[] expectedBytes = expectedBytesStream.toByteArray(); + + // For each output type, write the source string 2 bytes at a time and verify the output. + for (OutputType outputType : OutputType.values()) { + Coder coder = outputType.newCoder(expectedBytes.length); + for (int pos = 0; pos < source.length(); pos += 2) { + String substr = source.substring(pos, pos + 2); + coder.stream().writeStringNoTag(substr); + } + coder.stream().flush(); + assertEqualBytes(outputType, expectedBytes, coder.toByteArray()); + } + } + public void testSerializeInvalidUtf8() throws Exception { - String[] invalidStrings = new String[] { - newString(Character.MIN_HIGH_SURROGATE), - "foobar" + newString(Character.MIN_HIGH_SURROGATE), - newString(Character.MIN_LOW_SURROGATE), + String[] invalidStrings = new String[] {newString(Character.MIN_HIGH_SURROGATE), + "foobar" + newString(Character.MIN_HIGH_SURROGATE), newString(Character.MIN_LOW_SURROGATE), "foobar" + newString(Character.MIN_LOW_SURROGATE), - newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE) - }; - + newString(Character.MIN_HIGH_SURROGATE, Character.MIN_HIGH_SURROGATE)}; + CodedOutputStream outputWithStream = CodedOutputStream.newInstance(new ByteArrayOutputStream()); CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[10000]); + CodedOutputStream outputWithByteBuffer = + CodedOutputStream.newInstance(ByteBuffer.allocate(10000)); for (String s : invalidStrings) { // TODO(dweis): These should all fail; instead they are corrupting data. CodedOutputStream.computeStringSizeNoTag(s); outputWithStream.writeStringNoTag(s); outputWithArray.writeStringNoTag(s); + outputWithByteBuffer.writeStringNoTag(s); } } - - private static String newString(char... chars) { - return new String(chars); + + // TODO(nathanmittler): This test can be deleted once we properly throw IOException while + // encoding invalid UTF-8 strings. + public void testSerializeInvalidUtf8FollowedByOutOfSpace() throws Exception { + final int notEnoughBytes = 4; + CodedOutputStream outputWithArray = CodedOutputStream.newInstance(new byte[notEnoughBytes]); + CodedOutputStream outputWithByteBuffer = + CodedOutputStream.newInstance(ByteBuffer.allocate(notEnoughBytes)); + + String invalidString = newString(Character.MIN_HIGH_SURROGATE, 'f', 'o', 'o', 'b', 'a', 'r'); + try { + outputWithArray.writeStringNoTag(invalidString); + fail("Expected OutOfSpaceException"); + } catch (OutOfSpaceException e) { + assertTrue(e.getCause() instanceof IndexOutOfBoundsException); + } + try { + outputWithByteBuffer.writeStringNoTag(invalidString); + fail("Expected OutOfSpaceException"); + } catch (OutOfSpaceException e) { + assertTrue(e.getCause() instanceof IndexOutOfBoundsException); + } } /** Regression test for https://github.com/google/protobuf/issues/292 */ public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() throws Exception { String testCase = "Foooooooo"; - assertEquals(CodedOutputStream.computeRawVarint32Size(testCase.length()), - CodedOutputStream.computeRawVarint32Size(testCase.length() * 3)); + assertEquals( + CodedOutputStream.computeUInt32SizeNoTag(testCase.length()), + CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3)); assertEquals(11, CodedOutputStream.computeStringSize(1, testCase)); // Tag is one byte, varint describing string length is 1 byte, string length is 9 bytes. // An array of size 1 will cause a failure when trying to write the varint. - for (int i = 0; i < 11; i++) { - CodedOutputStream output = CodedOutputStream.newInstance(new byte[i]); - try { - output.writeString(1, testCase); - fail("Should have thrown an out of space exception"); - } catch (CodedOutputStream.OutOfSpaceException expected) {} + for (OutputType outputType : + new OutputType[] {OutputType.ARRAY, OutputType.NIO_HEAP, OutputType.NIO_DIRECT}) { + for (int i = 0; i < 11; i++) { + Coder coder = outputType.newCoder(i); + try { + coder.stream().writeString(1, testCase); + fail("Should have thrown an out of space exception"); + } catch (CodedOutputStream.OutOfSpaceException expected) { + } + } } } - + public void testDifferentStringLengths() throws Exception { // Test string serialization roundtrip using strings of the following lengths, // with ASCII and Unicode characters requiring different UTF-8 byte counts per // char, hence causing the length delimiter varint to sometimes require more // bytes for the Unicode strings than the ASCII string of the same length. int[] lengths = new int[] { - 0, - 1, - (1 << 4) - 1, // 1 byte for ASCII and Unicode - (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode - (1 << 11) - 1, // 2 bytes for ASCII and Unicode - (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode - (1 << 17) - 1, // 3 bytes for ASCII and Unicode + 0, + 1, + (1 << 4) - 1, // 1 byte for ASCII and Unicode + (1 << 7) - 1, // 1 byte for ASCII, 2 bytes for Unicode + (1 << 11) - 1, // 2 bytes for ASCII and Unicode + (1 << 14) - 1, // 2 bytes for ASCII, 3 bytes for Unicode + (1 << 17) - 1, + // 3 bytes for ASCII and Unicode }; - for (int i : lengths) { - testEncodingOfString('q', i); // 1 byte per char - testEncodingOfString('\u07FF', i); // 2 bytes per char - testEncodingOfString('\u0981', i); // 3 bytes per char + for (OutputType outputType : OutputType.values()) { + for (int i : lengths) { + testEncodingOfString(outputType, 'q', i); // 1 byte per char + testEncodingOfString(outputType, '\u07FF', i); // 2 bytes per char + testEncodingOfString(outputType, '\u0981', i); // 3 bytes per char + } } } - private void testEncodingOfString(char c, int length) throws Exception { - String fullString = fullString(c, length); - TestAllTypes testAllTypes = TestAllTypes.newBuilder() - .setOptionalString(fullString) - .build(); - assertEquals( - fullString, TestAllTypes.parseFrom(testAllTypes.toByteArray()).getOptionalString()); + public void testNioEncodersWithInitialOffsets() throws Exception { + String value = "abc"; + for (Coder coder : new Coder[] {new NioHeapCoder(10, 2), new NioDirectCoder(10, 2)}) { + coder.stream().writeStringNoTag(value); + coder.stream().flush(); + assertEqualBytes(coder.getOutputType(), new byte[]{3, 'a', 'b', 'c'}, coder.toByteArray()); + } } - private String fullString(char c, int length) { + /** + * Parses the given bytes using writeRawLittleEndian32() and checks + * that the result matches the given value. + */ + private static void assertWriteLittleEndian32(byte[] data, int value) throws Exception { + for (OutputType outputType : OutputType.values()) { + Coder coder = outputType.newCoder(data.length); + coder.stream().writeFixed32NoTag(value); + coder.stream().flush(); + assertEqualBytes(outputType, data, coder.toByteArray()); + } + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + Coder coder = OutputType.STREAM.newCoder(blockSize); + coder.stream().writeFixed32NoTag(value); + coder.stream().flush(); + assertEqualBytes(OutputType.STREAM, data, coder.toByteArray()); + } + } + + /** + * Parses the given bytes using writeRawLittleEndian64() and checks + * that the result matches the given value. + */ + private static void assertWriteLittleEndian64(byte[] data, long value) throws Exception { + for (OutputType outputType : OutputType.values()) { + Coder coder = outputType.newCoder(data.length); + coder.stream().writeFixed64NoTag(value); + coder.stream().flush(); + assertEqualBytes(outputType, data, coder.toByteArray()); + } + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + Coder coder = OutputType.STREAM.newCoder(blockSize); + coder.stream().writeFixed64NoTag(value); + coder.stream().flush(); + assertEqualBytes(OutputType.STREAM, data, coder.toByteArray()); + } + } + + private static String newString(char... chars) { + return new String(chars); + } + + private static void testEncodingOfString(OutputType outputType, char c, int length) + throws Exception { + String fullString = fullString(c, length); + TestAllTypes testAllTypes = TestAllTypes.newBuilder().setOptionalString(fullString).build(); + Coder coder = outputType.newCoder(testAllTypes.getSerializedSize()); + testAllTypes.writeTo(coder.stream()); + coder.stream().flush(); + assertEquals( + "OuputType: " + outputType, + fullString, + TestAllTypes.parseFrom(coder.toByteArray()).getOptionalString()); + } + + private static String fullString(char c, int length) { char[] result = new char[length]; Arrays.fill(result, c); return new String(result); } + + /** + * Helper to construct a byte array from a bunch of bytes. The inputs are + * actually ints so that I can use hex notation and not get stupid errors + * about precision. + */ + private static byte[] bytes(int... bytesAsInts) { + byte[] bytes = new byte[bytesAsInts.length]; + for (int i = 0; i < bytesAsInts.length; i++) { + bytes[i] = (byte) bytesAsInts[i]; + } + return bytes; + } + + /** Arrays.asList() does not work with arrays of primitives. :( */ + private static List toList(byte[] bytes) { + List result = new ArrayList(); + for (byte b : bytes) { + result.add(b); + } + return result; + } + + private static void assertEqualBytes(OutputType outputType, byte[] a, byte[] b) { + assertEquals(outputType.name(), toList(a), toList(b)); + } + + /** + * Writes the given value using writeRawVarint32() and writeRawVarint64() and + * checks that the result matches the given bytes. + */ + private static void assertWriteVarint(byte[] data, long value) throws Exception { + for (OutputType outputType : OutputType.values()) { + // Only test 32-bit write if the value fits into an int. + if (value == (int) value) { + Coder coder = outputType.newCoder(10); + coder.stream().writeUInt32NoTag((int) value); + coder.stream().flush(); + assertEqualBytes(outputType, data, coder.toByteArray()); + + // Also try computing size. + assertEquals(data.length, CodedOutputStream.computeUInt32SizeNoTag((int) value)); + } + + { + Coder coder = outputType.newCoder(10); + coder.stream().writeUInt64NoTag(value); + coder.stream().flush(); + assertEqualBytes(outputType, data, coder.toByteArray()); + + // Also try computing size. + assertEquals(data.length, CodedOutputStream.computeUInt64SizeNoTag(value)); + } + } + + // Try different block sizes. + for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { + // Only test 32-bit write if the value fits into an int. + if (value == (int) value) { + Coder coder = OutputType.STREAM.newCoder(blockSize); + coder.stream().writeUInt64NoTag((int) value); + coder.stream().flush(); + assertEqualBytes(OutputType.STREAM, data, coder.toByteArray()); + + ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); + CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, blockSize); + output.writeUInt32NoTag((int) value); + output.flush(); + assertEqualBytes(OutputType.STREAM, data, rawOutput.toByteArray()); + } + + { + Coder coder = OutputType.STREAM.newCoder(blockSize); + coder.stream().writeUInt64NoTag(value); + coder.stream().flush(); + assertEqualBytes(OutputType.STREAM, data, coder.toByteArray()); + } + } + } + + private static void assertVarintRoundTrip(OutputType outputType, long value) throws Exception { + { + Coder coder = outputType.newCoder(10); + coder.stream().writeUInt64NoTag(value); + coder.stream().flush(); + byte[] bytes = coder.toByteArray(); + assertEquals( + outputType.name(), bytes.length, CodedOutputStream.computeUInt64SizeNoTag(value)); + CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes)); + assertEquals(outputType.name(), value, input.readRawVarint64()); + } + + if (value == (int) value) { + Coder coder = outputType.newCoder(10); + coder.stream().writeUInt32NoTag((int) value); + coder.stream().flush(); + byte[] bytes = coder.toByteArray(); + assertEquals( + outputType.name(), bytes.length, CodedOutputStream.computeUInt32SizeNoTag((int) value)); + CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(bytes)); + assertEquals(outputType.name(), value, input.readRawVarint32()); + } + } } diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java index d3deaa07..85b418c4 100644 --- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java @@ -73,20 +73,6 @@ public class DoubleArrayListTest extends TestCase { assertImmutable(list); } - public void testCopyConstructor() { - DoubleArrayList copy = new DoubleArrayList(TERTIARY_LIST); - assertEquals(TERTIARY_LIST, copy); - - copy = new DoubleArrayList(DoubleArrayList.emptyList()); - assertEquals(DoubleArrayList.emptyList(), copy); - - copy = new DoubleArrayList(asList(1D, 2D, 3D)); - assertEquals(asList(1D, 2D, 3D), copy); - - copy = new DoubleArrayList(Collections.emptyList()); - assertEquals(DoubleArrayList.emptyList(), copy); - } - public void testModificationWithIteration() { list.addAll(asList(1D, 2D, 3D, 4D)); Iterator iterator = list.iterator(); diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java index a5e65424..88a75743 100644 --- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java @@ -73,20 +73,6 @@ public class FloatArrayListTest extends TestCase { assertImmutable(list); } - public void testCopyConstructor() { - FloatArrayList copy = new FloatArrayList(TERTIARY_LIST); - assertEquals(TERTIARY_LIST, copy); - - copy = new FloatArrayList(FloatArrayList.emptyList()); - assertEquals(FloatArrayList.emptyList(), copy); - - copy = new FloatArrayList(asList(1F, 2F, 3F)); - assertEquals(asList(1F, 2F, 3F), copy); - - copy = new FloatArrayList(Collections.emptyList()); - assertEquals(FloatArrayList.emptyList(), copy); - } - public void testModificationWithIteration() { list.addAll(asList(1F, 2F, 3F, 4F)); Iterator iterator = list.iterator(); diff --git a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java index a92ba374..b7eaebf5 100644 --- a/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java +++ b/java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java @@ -41,7 +41,7 @@ package com.google.protobuf; */ public class ForceFieldBuildersPreRun implements Runnable { - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void run() { GeneratedMessage.enableAlwaysUseFieldBuildersForTesting(); } diff --git a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java index 8cd1f38d..a9b8b638 100644 --- a/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java +++ b/java/core/src/test/java/com/google/protobuf/GeneratedMessageTest.java @@ -723,7 +723,7 @@ public class GeneratedMessageTest extends TestCase { public void testLiteExtensionMessageOrBuilder() throws Exception { TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder(); - TestUtil.setAllExtensions(builder); + TestUtilLite.setAllExtensions(builder); TestUtil.assertAllExtensionsSet(builder); TestAllExtensionsLite message = builder.build(); @@ -732,8 +732,8 @@ public class GeneratedMessageTest extends TestCase { public void testLiteExtensionRepeatedSetters() throws Exception { TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder(); - TestUtil.setAllExtensions(builder); - TestUtil.modifyRepeatedExtensions(builder); + TestUtilLite.setAllExtensions(builder); + TestUtilLite.modifyRepeatedExtensions(builder); TestUtil.assertRepeatedExtensionsModified(builder); TestAllExtensionsLite message = builder.build(); @@ -760,7 +760,7 @@ public class GeneratedMessageTest extends TestCase { } public void testLiteExtensionCopy() throws Exception { - TestAllExtensionsLite original = TestUtil.getAllLiteExtensionsSet(); + TestAllExtensionsLite original = TestUtilLite.getAllLiteExtensionsSet(); TestAllExtensionsLite copy = TestAllExtensionsLite.newBuilder(original).build(); TestUtil.assertAllExtensionsSet(copy); diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java index 3733eb30..efb8f3e2 100644 --- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java @@ -72,20 +72,6 @@ public class IntArrayListTest extends TestCase { list.makeImmutable(); assertImmutable(list); } - - public void testCopyConstructor() { - IntArrayList copy = new IntArrayList(TERTIARY_LIST); - assertEquals(TERTIARY_LIST, copy); - - copy = new IntArrayList(IntArrayList.emptyList()); - assertEquals(IntArrayList.emptyList(), copy); - - copy = new IntArrayList(asList(1, 2, 3)); - assertEquals(asList(1, 2, 3), copy); - - copy = new IntArrayList(Collections.emptyList()); - assertEquals(IntArrayList.emptyList(), copy); - } public void testModificationWithIteration() { list.addAll(asList(1, 2, 3, 4)); diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java index 9e503cc3..88c3e0b2 100644 --- a/java/core/src/test/java/com/google/protobuf/LiteTest.java +++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java @@ -33,17 +33,25 @@ package com.google.protobuf; import static java.util.Collections.emptyList; import static java.util.Collections.singletonList; +import com.google.protobuf.UnittestImportLite.ImportEnumLite; +import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite; import com.google.protobuf.UnittestLite; import com.google.protobuf.UnittestLite.ForeignEnumLite; import com.google.protobuf.UnittestLite.ForeignMessageLite; import com.google.protobuf.UnittestLite.TestAllExtensionsLite; import com.google.protobuf.UnittestLite.TestAllTypesLite; +import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedEnum; import com.google.protobuf.UnittestLite.TestAllTypesLite.NestedMessage; import com.google.protobuf.UnittestLite.TestAllTypesLite.OneofFieldCase; import com.google.protobuf.UnittestLite.TestAllTypesLite.OptionalGroup; import com.google.protobuf.UnittestLite.TestAllTypesLite.RepeatedGroup; import com.google.protobuf.UnittestLite.TestAllTypesLiteOrBuilder; import com.google.protobuf.UnittestLite.TestNestedExtensionLite; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Bar; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.BarPrime; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.Foo; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestOneofEquals; +import protobuf_unittest.lite_equals_and_hash.LiteEqualsAndHash.TestRecursiveOneof; import junit.framework.TestCase; @@ -59,6 +67,7 @@ import java.io.ObjectOutputStream; * @author kenton@google.com Kenton Varda */ public class LiteTest extends TestCase { + @Override public void setUp() throws Exception { // Test that nested extensions are initialized correctly even if the outer // class has not been accessed directly. This was once a bug with lite @@ -302,11 +311,9 @@ public class LiteTest extends TestCase { assertEquals( ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage()); - // LITE_RUNTIME doesn't implement equals so we compare on a property and - // ensure the property isn't set on foreignMessage. - assertEquals(3, builder.getOptionalForeignMessage().getC()); + assertEquals(foreignMessageBuilder.build(), builder.getOptionalForeignMessage()); messageAfterBuild = builder.build(); - assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC()); + assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage()); assertEquals( ForeignMessageLite.getDefaultInstance(), message.getOptionalForeignMessage()); @@ -314,7 +321,7 @@ public class LiteTest extends TestCase { assertEquals( ForeignMessageLite.getDefaultInstance(), builder.getOptionalForeignMessage()); - assertEquals(3, messageAfterBuild.getOptionalForeignMessage().getC()); + assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getOptionalForeignMessage()); message = builder.build(); OptionalGroup optionalGroup = OptionalGroup.newBuilder() @@ -339,17 +346,15 @@ public class LiteTest extends TestCase { builder.setOptionalGroup(optionalGroupBuilder); assertEquals( OptionalGroup.getDefaultInstance(), message.getOptionalGroup()); - // LITE_RUNTIME doesn't implement equals so we compare on a property and - // ensure the property isn't set on optionalGroup. - assertEquals(3, builder.getOptionalGroup().getA()); + assertEquals(optionalGroupBuilder.build(), builder.getOptionalGroup()); messageAfterBuild = builder.build(); - assertEquals(3, messageAfterBuild.getOptionalGroup().getA()); + assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup()); assertEquals( OptionalGroup.getDefaultInstance(), message.getOptionalGroup()); builder.clearOptionalGroup(); assertEquals( OptionalGroup.getDefaultInstance(), builder.getOptionalGroup()); - assertEquals(3, messageAfterBuild.getOptionalGroup().getA()); + assertEquals(optionalGroupBuilder.build(), messageAfterBuild.getOptionalGroup()); message = builder.build(); builder.setOptionalInt32(1); @@ -400,17 +405,16 @@ public class LiteTest extends TestCase { assertEquals( NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage()); - // LITE_RUNTIME doesn't implement equals so we compare on a property. - assertEquals(3, builder.getOptionalLazyMessage().getBb()); + assertEquals(nestedMessageBuilder.build(), builder.getOptionalLazyMessage()); messageAfterBuild = builder.build(); - assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb()); + assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage()); assertEquals( NestedMessage.getDefaultInstance(), message.getOptionalLazyMessage()); builder.clearOptionalLazyMessage(); assertEquals( NestedMessage.getDefaultInstance(), builder.getOptionalLazyMessage()); - assertEquals(3, messageAfterBuild.getOptionalLazyMessage().getBb()); + assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getOptionalLazyMessage()); message = builder.build(); builder.setOptionalSfixed32(1); @@ -1100,8 +1104,7 @@ public class LiteTest extends TestCase { assertEquals(0, message.getRepeatedForeignMessageCount()); builder.setRepeatedForeignMessage( 0, ForeignMessageLite.getDefaultInstance()); - // LITE_RUNTIME doesn't implement equals so we compare on a property. - assertEquals(3, messageAfterBuild.getRepeatedForeignMessage(0).getC()); + assertEquals(foreignMessageBuilder.build(), messageAfterBuild.getRepeatedForeignMessage(0)); assertEquals( ForeignMessageLite.getDefaultInstance(), builder.getRepeatedForeignMessage(0)); @@ -1114,8 +1117,7 @@ public class LiteTest extends TestCase { builder.setRepeatedForeignMessage(0, foreignMessageBuilder); assertEquals( foreignMessage, messageAfterBuild.getRepeatedForeignMessage(0)); - // LITE_RUNTIME doesn't implement equals so we compare on a property. - assertEquals(3, builder.getRepeatedForeignMessage(0).getC()); + assertEquals(foreignMessageBuilder.build(), builder.getRepeatedForeignMessage(0)); builder.clearRepeatedForeignMessage(); message = builder.build(); @@ -1148,9 +1150,7 @@ public class LiteTest extends TestCase { messageAfterBuild = builder.build(); assertEquals(0, message.getRepeatedGroupCount()); builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance()); - // LITE_RUNTIME doesn't implement equals so we compare on a property and - // ensure the property isn't set on repeatedGroup. - assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA()); + assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0)); assertEquals( RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0)); builder.clearRepeatedGroup(); @@ -1160,9 +1160,7 @@ public class LiteTest extends TestCase { messageAfterBuild = builder.build(); assertEquals(0, message.getRepeatedGroupCount()); builder.setRepeatedGroup(0, RepeatedGroup.getDefaultInstance()); - // LITE_RUNTIME doesn't implement equals so we compare on a property and - // ensure the property isn't set on repeatedGroup. - assertEquals(3, messageAfterBuild.getRepeatedGroup(0).getA()); + assertEquals(repeatedGroupBuilder.build(), messageAfterBuild.getRepeatedGroup(0)); assertEquals( RepeatedGroup.getDefaultInstance(), builder.getRepeatedGroup(0)); builder.clearRepeatedGroup(); @@ -1210,9 +1208,7 @@ public class LiteTest extends TestCase { messageAfterBuild = builder.build(); assertEquals(0, message.getRepeatedLazyMessageCount()); builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance()); - // LITE_RUNTIME doesn't implement equals so we compare on a property and - // ensure the property isn't set on repeatedGroup. - assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb()); + assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0)); assertEquals( NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0)); builder.clearRepeatedLazyMessage(); @@ -1222,9 +1218,7 @@ public class LiteTest extends TestCase { messageAfterBuild = builder.build(); assertEquals(0, message.getRepeatedLazyMessageCount()); builder.setRepeatedLazyMessage(0, NestedMessage.getDefaultInstance()); - // LITE_RUNTIME doesn't implement equals so we compare on a property and - // ensure the property isn't set on repeatedGroup. - assertEquals(3, messageAfterBuild.getRepeatedLazyMessage(0).getBb()); + assertEquals(nestedMessageBuilder.build(), messageAfterBuild.getRepeatedLazyMessage(0)); assertEquals( NestedMessage.getDefaultInstance(), builder.getRepeatedLazyMessage(0)); builder.clearRepeatedLazyMessage(); @@ -1456,7 +1450,7 @@ public class LiteTest extends TestCase { .setOptionalFloat(2.72f) .setOptionalDouble(3.14) .build(); - assertToStringEquals("optional_float: 2.72\noptional_double: 3.14", proto); + assertToStringEquals("optional_double: 3.14\noptional_float: 2.72", proto); } public void testToStringStringFields() throws Exception { @@ -1511,7 +1505,7 @@ public class LiteTest extends TestCase { .setC(3)) .build(); assertToStringEquals( - "optional_foreign_message {\n c: 3\n}\noptional_foreign_enum: FOREIGN_LITE_BAR", + "optional_foreign_enum: FOREIGN_LITE_BAR\noptional_foreign_message {\n c: 3\n}", proto); } @@ -1546,6 +1540,27 @@ public class LiteTest extends TestCase { "1: 123\n18: \"\\b\\a\"\n21: 3\n44: \"spam\"\n44: \"eggs\"", messageWithUnknownFields); } + + public void testToStringLazyMessage() throws Exception { + TestAllTypesLite message = TestAllTypesLite.newBuilder() + .setOptionalLazyMessage(NestedMessage.newBuilder().setBb(1).build()) + .build(); + assertToStringEquals("optional_lazy_message {\n bb: 1\n}", message); + } + + public void testToStringGroup() throws Exception { + TestAllTypesLite message = TestAllTypesLite.newBuilder() + .setOptionalGroup(OptionalGroup.newBuilder().setA(1).build()) + .build(); + assertToStringEquals("optional_group {\n a: 1\n}", message); + } + + public void testToStringOneof() throws Exception { + TestAllTypesLite message = TestAllTypesLite.newBuilder() + .setOneofString("hello") + .build(); + assertToStringEquals("oneof_string: \"hello\"", message); + } // Asserts that the toString() representation of the message matches the expected. This verifies // the first line starts with a comment; but, does not factor in said comment as part of the @@ -1598,4 +1613,617 @@ public class LiteTest extends TestCase { assertEquals(11, message.getOneofLazyNestedMessage().getBb()); assertEquals(22L, message.getOneofLazyNestedMessage().getCc()); } + + public void testMergeFromStream_repeatedField() throws Exception { + TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder() + .addRepeatedString("hello"); + builder.mergeFrom(CodedInputStream.newInstance(builder.build().toByteArray())); + + assertEquals(2, builder.getRepeatedStringCount()); + } + + public void testMergeFromStream_invalidBytes() throws Exception { + TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder() + .setDefaultBool(true); + try { + builder.mergeFrom(CodedInputStream.newInstance("Invalid bytes".getBytes(Internal.UTF_8))); + fail(); + } catch (InvalidProtocolBufferException expected) {} + } + + public void testMergeFrom_sanity() throws Exception { + TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build(); + byte[] bytes = one.toByteArray(); + TestAllTypesLite two = TestAllTypesLite.parseFrom(bytes); + + one = one.toBuilder().mergeFrom(one).build(); + two = two.toBuilder().mergeFrom(bytes).build(); + assertEquals(one, two); + assertEquals(two, one); + assertEquals(one.hashCode(), two.hashCode()); + } + + public void testEquals_notEqual() throws Exception { + TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build(); + byte[] bytes = one.toByteArray(); + TestAllTypesLite two = one.toBuilder().mergeFrom(one).mergeFrom(bytes).build(); + + assertFalse(one.equals(two)); + assertFalse(two.equals(one)); + + assertFalse(one.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(one)); + + TestAllTypesLite oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultBool(true) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultCord("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultCordBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultDouble(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultFixed32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultFixed64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultFloat(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultImportEnum(ImportEnumLite.IMPORT_LITE_BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultInt32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultInt64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultNestedEnum(NestedEnum.BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultSfixed32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultSfixed64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultSint32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultSint64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultString("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultStringBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultStringPiece("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultStringPieceBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultUint32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setDefaultUint64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedBool(true) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedCord("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedCordBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedDouble(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedFixed32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedFixed64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedFloat(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedImportEnum(ImportEnumLite.IMPORT_LITE_BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedInt32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedInt64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedNestedEnum(NestedEnum.BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedSfixed32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedSfixed64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedSint32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedSint64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedString("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedStringBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedStringPiece("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedStringPieceBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedUint32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedUint64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalBool(true) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalCord("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalCordBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalDouble(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalFixed32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalFixed64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalFloat(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalImportEnum(ImportEnumLite.IMPORT_LITE_BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalInt32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalInt64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalNestedEnum(NestedEnum.BAR) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalSfixed32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalSfixed64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalSint32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalSint64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalString("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalStringBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalStringPiece("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalStringPieceBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalUint32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalUint64(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOneofBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOneofLazyNestedMessage(NestedMessage.getDefaultInstance()) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOneofNestedMessage(NestedMessage.getDefaultInstance()) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOneofString("") + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOneofStringBytes(ByteString.EMPTY) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOneofUint32(0) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalForeignMessage(ForeignMessageLite.getDefaultInstance()) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalGroup(OptionalGroup.getDefaultInstance()) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalPublicImportMessage(PublicImportMessageLite.getDefaultInstance()) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + + oneFieldSet = TestAllTypesLite.newBuilder() + .setOptionalLazyMessage(NestedMessage.getDefaultInstance()) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + oneFieldSet = TestAllTypesLite.newBuilder() + .addRepeatedLazyMessage(NestedMessage.getDefaultInstance()) + .build(); + assertFalse(oneFieldSet.equals(TestAllTypesLite.getDefaultInstance())); + assertFalse(TestAllTypesLite.getDefaultInstance().equals(oneFieldSet)); + } + + public void testEquals() throws Exception { + // Check that two identical objs are equal. + Foo foo1a = Foo.newBuilder() + .setValue(1) + .addBar(Bar.newBuilder().setName("foo1")) + .build(); + Foo foo1b = Foo.newBuilder() + .setValue(1) + .addBar(Bar.newBuilder().setName("foo1")) + .build(); + Foo foo2 = Foo.newBuilder() + .setValue(1) + .addBar(Bar.newBuilder().setName("foo2")) + .build(); + + // Check that equals is doing value rather than object equality. + assertEquals(foo1a, foo1b); + assertEquals(foo1a.hashCode(), foo1b.hashCode()); + + // Check that a diffeent object is not equal. + assertFalse(foo1a.equals(foo2)); + + // Check that two objects which have different types but the same field values are not + // considered to be equal. + Bar bar = Bar.newBuilder().setName("bar").build(); + BarPrime barPrime = BarPrime.newBuilder().setName("bar").build(); + assertFalse(bar.equals(barPrime)); + } + + public void testOneofEquals() throws Exception { + TestOneofEquals.Builder builder = TestOneofEquals.newBuilder(); + TestOneofEquals message1 = builder.build(); + // Set message2's name field to default value. The two messages should be different when we + // check with the oneof case. + builder.setName(""); + TestOneofEquals message2 = builder.build(); + assertFalse(message1.equals(message2)); + } + + public void testEquals_sanity() throws Exception { + TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build(); + TestAllTypesLite two = TestAllTypesLite.parseFrom(one.toByteArray()); + assertEquals(one, two); + assertEquals(one.hashCode(), two.hashCode()); + + assertEquals( + one.toBuilder().mergeFrom(two).build(), + two.toBuilder().mergeFrom(two.toByteArray()).build()); + } + + public void testEqualsAndHashCodeWithUnknownFields() throws InvalidProtocolBufferException { + Foo fooWithOnlyValue = Foo.newBuilder() + .setValue(1) + .build(); + + Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder() + .setValue(1) + .setExtension(Bar.fooExt, Bar.newBuilder() + .setName("name") + .build()) + .build(); + + Foo fooWithValueAndUnknownFields = Foo.parseFrom(fooWithValueAndExtension.toByteArray()); + + assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndUnknownFields); + assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields); + } + + // Test to ensure we avoid a class cast exception with oneofs. + public void testEquals_oneOfMessages() { + TestAllTypesLite mine = TestAllTypesLite.newBuilder() + .setOneofString("Hello") + .build(); + + TestAllTypesLite other = TestAllTypesLite.newBuilder() + .setOneofNestedMessage(NestedMessage.getDefaultInstance()) + .build(); + + assertFalse(mine.equals(other)); + assertFalse(other.equals(mine)); + } + + private void assertEqualsAndHashCodeAreFalse(Object o1, Object o2) { + assertFalse(o1.equals(o2)); + assertFalse(o1.hashCode() == o2.hashCode()); + } + + public void testRecursiveHashcode() { + // This tests that we don't infinite loop. + TestRecursiveOneof.getDefaultInstance().hashCode(); + } } diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java index 1bd094f7..0a8f9ed2 100644 --- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java @@ -73,20 +73,6 @@ public class LongArrayListTest extends TestCase { assertImmutable(list); } - public void testCopyConstructor() { - LongArrayList copy = new LongArrayList(TERTIARY_LIST); - assertEquals(TERTIARY_LIST, copy); - - copy = new LongArrayList(LongArrayList.emptyList()); - assertEquals(LongArrayList.emptyList(), copy); - - copy = new LongArrayList(asList(1L, 2L, 3L)); - assertEquals(asList(1L, 2L, 3L), copy); - - copy = new LongArrayList(Collections.emptyList()); - assertEquals(LongArrayList.emptyList(), copy); - } - public void testModificationWithIteration() { list.addAll(asList(1L, 2L, 3L, 4L)); Iterator iterator = list.iterator(); diff --git a/java/core/src/test/java/com/google/protobuf/ParserTest.java b/java/core/src/test/java/com/google/protobuf/ParserTest.java index 9d4b6b94..30842d2c 100644 --- a/java/core/src/test/java/com/google/protobuf/ParserTest.java +++ b/java/core/src/test/java/com/google/protobuf/ParserTest.java @@ -179,16 +179,16 @@ public class ParserTest extends TestCase { public void testParseExtensions() throws Exception { assertRoundTripEquals(TestUtil.getAllExtensionsSet(), TestUtil.getExtensionRegistry()); - assertRoundTripEquals(TestUtil.getAllLiteExtensionsSet(), - TestUtil.getExtensionRegistryLite()); + assertRoundTripEquals( + TestUtilLite.getAllLiteExtensionsSet(), TestUtilLite.getExtensionRegistryLite()); } public void testParsePacked() throws Exception { assertRoundTripEquals(TestUtil.getPackedSet()); assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry()); - assertRoundTripEquals(TestUtil.getLitePackedExtensionsSet(), - TestUtil.getExtensionRegistryLite()); + assertRoundTripEquals( + TestUtilLite.getLitePackedExtensionsSet(), TestUtilLite.getExtensionRegistryLite()); } public void testParseDelimitedTo() throws Exception { @@ -198,8 +198,7 @@ public class ParserTest extends TestCase { normalMessage.writeDelimitedTo(output); // Write MessageLite with packed extension fields. - TestPackedExtensionsLite packedMessage = - TestUtil.getLitePackedExtensionsSet(); + TestPackedExtensionsLite packedMessage = TestUtilLite.getLitePackedExtensionsSet(); packedMessage.writeDelimitedTo(output); InputStream input = new ByteArrayInputStream(output.toByteArray()); @@ -208,8 +207,9 @@ public class ParserTest extends TestCase { normalMessage.getParserForType().parseDelimitedFrom(input)); assertMessageEquals( packedMessage, - packedMessage.getParserForType().parseDelimitedFrom( - input, TestUtil.getExtensionRegistryLite())); + packedMessage + .getParserForType() + .parseDelimitedFrom(input, TestUtilLite.getExtensionRegistryLite())); } public void testParseUnknownFields() throws Exception { diff --git a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java index 245c3dee..3f45e226 100644 --- a/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java +++ b/java/core/src/test/java/com/google/protobuf/ProtobufArrayListTest.java @@ -63,20 +63,6 @@ public class ProtobufArrayListTest extends TestCase { assertImmutable(ProtobufArrayList.emptyList()); } - public void testCopyConstructor() { - ProtobufArrayList copy = new ProtobufArrayList(TERTIARY_LIST); - assertEquals(TERTIARY_LIST, copy); - - copy = new ProtobufArrayList(IntArrayList.emptyList()); - assertEquals(ProtobufArrayList.emptyList(), copy); - - copy = new ProtobufArrayList(asList(1, 2, 3)); - assertEquals(asList(1, 2, 3), copy); - - copy = new ProtobufArrayList(Collections.emptyList()); - assertEquals(ProtobufArrayList.emptyList(), copy); - } - public void testModificationWithIteration() { list.addAll(asList(1, 2, 3, 4)); Iterator iterator = list.iterator(); diff --git a/java/core/src/test/java/com/google/protobuf/ServiceTest.java b/java/core/src/test/java/com/google/protobuf/ServiceTest.java index 7f3439d0..b902737d 100644 --- a/java/core/src/test/java/com/google/protobuf/ServiceTest.java +++ b/java/core/src/test/java/com/google/protobuf/ServiceTest.java @@ -175,12 +175,14 @@ public class ServiceTest extends TestCase { MethodDescriptor fooMethod = ServiceWithNoOuter.getDescriptor().findMethodByName("Foo"); MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance(); - RpcCallback callback = new RpcCallback() { - public void run(Message parameter) { - // No reason this should be run. - fail(); - } - }; + RpcCallback callback = + new RpcCallback() { + @Override + public void run(Message parameter) { + // No reason this should be run. + fail(); + } + }; RpcCallback specializedCallback = RpcUtil.specializeCallback(callback); @@ -290,7 +292,9 @@ public class ServiceTest extends TestCase { public boolean isCalled() { return called; } public void reset() { called = false; } - public void run(Type message) { called = true; } + @Override + public void run(Type message) { + called = true; } } /** Implementation of the wrapsCallback() argument matcher. */ @@ -301,6 +305,7 @@ public class ServiceTest extends TestCase { this.callback = callback; } + @Override @SuppressWarnings("unchecked") public boolean matches(Object actual) { if (!(actual instanceof RpcCallback)) { @@ -313,6 +318,7 @@ public class ServiceTest extends TestCase { return callback.isCalled(); } + @Override public void appendTo(StringBuffer buffer) { buffer.append("wrapsCallback(mockCallback)"); } diff --git a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java index 366086d3..e96ecd65 100644 --- a/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java +++ b/java/core/src/test/java/com/google/protobuf/SmallSortedMapTest.java @@ -56,14 +56,17 @@ public class SmallSortedMapTest extends TestCase { this.value = value; } + @Override public K getKey() { return key; } + @Override public V getValue() { return value; } + @Override public V setValue(V value) { V oldValue = this.value; this.value = value; diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java index 53d65428..08b2a76d 100644 --- a/java/core/src/test/java/com/google/protobuf/TestUtil.java +++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java @@ -30,8 +30,6 @@ package com.google.protobuf; -import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite; -import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite; import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite; import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite; import static com.google.protobuf.UnittestLite.defaultCordExtensionLite; @@ -216,12 +214,7 @@ import static protobuf_unittest.UnittestProto.repeatedUint32Extension; import static protobuf_unittest.UnittestProto.repeatedUint64Extension; import com.google.protobuf.UnittestImportLite.ImportEnumLite; -import com.google.protobuf.UnittestImportLite.ImportMessageLite; -import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite; -import com.google.protobuf.UnittestLite; import com.google.protobuf.UnittestLite.ForeignEnumLite; -import com.google.protobuf.UnittestLite.ForeignMessageLite; -import com.google.protobuf.UnittestLite.TestAllExtensionsLite; import com.google.protobuf.UnittestLite.TestAllExtensionsLiteOrBuilder; import com.google.protobuf.UnittestLite.TestAllTypesLite; import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; @@ -286,16 +279,6 @@ public final class TestUtil { return builder; } - /** - * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by - * {@link #setAllFields(TestAllTypesLite.Builder)}. - */ - public static TestAllTypesLite.Builder getAllLiteSetBuilder() { - TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder(); - setAllFields(builder); - return builder; - } - /** * Get a {@code TestAllExtensions} with all fields set as they would be by * {@link #setAllExtensions(TestAllExtensions.Builder)}. @@ -306,12 +289,6 @@ public final class TestUtil { return builder.build(); } - public static TestAllExtensionsLite getAllLiteExtensionsSet() { - TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder(); - setAllExtensions(builder); - return builder.build(); - } - public static TestPackedTypes getPackedSet() { TestPackedTypes.Builder builder = TestPackedTypes.newBuilder(); setPackedFields(builder); @@ -330,157 +307,6 @@ public final class TestUtil { return builder.build(); } - public static TestPackedExtensionsLite getLitePackedExtensionsSet() { - TestPackedExtensionsLite.Builder builder = - TestPackedExtensionsLite.newBuilder(); - setPackedExtensions(builder); - return builder.build(); - } - - /** - * Set every field of {@code builder} to the values expected by - * {@code assertAllFieldsSet()}. - */ - public static void setAllFields(TestAllTypesLite.Builder builder) { - builder.setOptionalInt32 (101); - builder.setOptionalInt64 (102); - builder.setOptionalUint32 (103); - builder.setOptionalUint64 (104); - builder.setOptionalSint32 (105); - builder.setOptionalSint64 (106); - builder.setOptionalFixed32 (107); - builder.setOptionalFixed64 (108); - builder.setOptionalSfixed32(109); - builder.setOptionalSfixed64(110); - builder.setOptionalFloat (111); - builder.setOptionalDouble (112); - builder.setOptionalBool (true); - builder.setOptionalString ("115"); - builder.setOptionalBytes (toBytes("116")); - - builder.setOptionalGroup( - TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build()); - builder.setOptionalNestedMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build()); - builder.setOptionalForeignMessage( - ForeignMessageLite.newBuilder().setC(119).build()); - builder.setOptionalImportMessage( - ImportMessageLite.newBuilder().setD(120).build()); - builder.setOptionalPublicImportMessage( - PublicImportMessageLite.newBuilder().setE(126).build()); - builder.setOptionalLazyMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build()); - - builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ); - builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ); - builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ); - - builder.setOptionalStringPiece("124"); - builder.setOptionalCord("125"); - - // ----------------------------------------------------------------- - - builder.addRepeatedInt32 (201); - builder.addRepeatedInt64 (202); - builder.addRepeatedUint32 (203); - builder.addRepeatedUint64 (204); - builder.addRepeatedSint32 (205); - builder.addRepeatedSint64 (206); - builder.addRepeatedFixed32 (207); - builder.addRepeatedFixed64 (208); - builder.addRepeatedSfixed32(209); - builder.addRepeatedSfixed64(210); - builder.addRepeatedFloat (211); - builder.addRepeatedDouble (212); - builder.addRepeatedBool (true); - builder.addRepeatedString ("215"); - builder.addRepeatedBytes (toBytes("216")); - - builder.addRepeatedGroup( - TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build()); - builder.addRepeatedNestedMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build()); - builder.addRepeatedForeignMessage( - ForeignMessageLite.newBuilder().setC(219).build()); - builder.addRepeatedImportMessage( - ImportMessageLite.newBuilder().setD(220).build()); - builder.addRepeatedLazyMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build()); - - builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR); - builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR); - builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR); - - builder.addRepeatedStringPiece("224"); - builder.addRepeatedCord("225"); - - // Add a second one of each field. - builder.addRepeatedInt32 (301); - builder.addRepeatedInt64 (302); - builder.addRepeatedUint32 (303); - builder.addRepeatedUint64 (304); - builder.addRepeatedSint32 (305); - builder.addRepeatedSint64 (306); - builder.addRepeatedFixed32 (307); - builder.addRepeatedFixed64 (308); - builder.addRepeatedSfixed32(309); - builder.addRepeatedSfixed64(310); - builder.addRepeatedFloat (311); - builder.addRepeatedDouble (312); - builder.addRepeatedBool (false); - builder.addRepeatedString ("315"); - builder.addRepeatedBytes (toBytes("316")); - - builder.addRepeatedGroup( - TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build()); - builder.addRepeatedNestedMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build()); - builder.addRepeatedForeignMessage( - ForeignMessageLite.newBuilder().setC(319).build()); - builder.addRepeatedImportMessage( - ImportMessageLite.newBuilder().setD(320).build()); - builder.addRepeatedLazyMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build()); - - builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ); - builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ); - builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ); - - builder.addRepeatedStringPiece("324"); - builder.addRepeatedCord("325"); - - // ----------------------------------------------------------------- - - builder.setDefaultInt32 (401); - builder.setDefaultInt64 (402); - builder.setDefaultUint32 (403); - builder.setDefaultUint64 (404); - builder.setDefaultSint32 (405); - builder.setDefaultSint64 (406); - builder.setDefaultFixed32 (407); - builder.setDefaultFixed64 (408); - builder.setDefaultSfixed32(409); - builder.setDefaultSfixed64(410); - builder.setDefaultFloat (411); - builder.setDefaultDouble (412); - builder.setDefaultBool (false); - builder.setDefaultString ("415"); - builder.setDefaultBytes (toBytes("416")); - - builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO); - builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO); - builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO); - - builder.setDefaultStringPiece("424"); - builder.setDefaultCord("425"); - - builder.setOneofUint32(601); - builder.setOneofNestedMessage( - TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build()); - builder.setOneofString("603"); - builder.setOneofBytes(toBytes("604")); - } - /** * Set every field of {@code message} to the values expected by * {@code assertAllFieldsSet()}. @@ -1370,23 +1196,13 @@ public final class TestUtil { return registry.getUnmodifiable(); } - public static ExtensionRegistryLite getExtensionRegistryLite() { - ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); - registerAllExtensionsLite(registry); - return registry.getUnmodifiable(); - } - /** * Register all of {@code TestAllExtensions}'s extensions with the * given {@link ExtensionRegistry}. */ public static void registerAllExtensions(ExtensionRegistry registry) { UnittestProto.registerAllExtensions(registry); - registerAllExtensionsLite(registry); - } - - public static void registerAllExtensionsLite(ExtensionRegistryLite registry) { - UnittestLite.registerAllExtensions(registry); + TestUtilLite.registerAllExtensionsLite(registry); } /** @@ -2179,195 +1995,6 @@ public final class TestUtil { // =================================================================== // Lite extensions - /** - * Set every field of {@code message} to the values expected by - * {@code assertAllExtensionsSet()}. - */ - public static void setAllExtensions(TestAllExtensionsLite.Builder message) { - message.setExtension(optionalInt32ExtensionLite , 101); - message.setExtension(optionalInt64ExtensionLite , 102L); - message.setExtension(optionalUint32ExtensionLite , 103); - message.setExtension(optionalUint64ExtensionLite , 104L); - message.setExtension(optionalSint32ExtensionLite , 105); - message.setExtension(optionalSint64ExtensionLite , 106L); - message.setExtension(optionalFixed32ExtensionLite , 107); - message.setExtension(optionalFixed64ExtensionLite , 108L); - message.setExtension(optionalSfixed32ExtensionLite, 109); - message.setExtension(optionalSfixed64ExtensionLite, 110L); - message.setExtension(optionalFloatExtensionLite , 111F); - message.setExtension(optionalDoubleExtensionLite , 112D); - message.setExtension(optionalBoolExtensionLite , true); - message.setExtension(optionalStringExtensionLite , "115"); - message.setExtension(optionalBytesExtensionLite , toBytes("116")); - - message.setExtension(optionalGroupExtensionLite, - OptionalGroup_extension_lite.newBuilder().setA(117).build()); - message.setExtension(optionalNestedMessageExtensionLite, - TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build()); - message.setExtension(optionalForeignMessageExtensionLite, - ForeignMessageLite.newBuilder().setC(119).build()); - message.setExtension(optionalImportMessageExtensionLite, - ImportMessageLite.newBuilder().setD(120).build()); - message.setExtension(optionalPublicImportMessageExtensionLite, - PublicImportMessageLite.newBuilder().setE(126).build()); - message.setExtension(optionalLazyMessageExtensionLite, - TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build()); - - message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ); - message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ); - message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ); - - message.setExtension(optionalStringPieceExtensionLite, "124"); - message.setExtension(optionalCordExtensionLite, "125"); - - // ----------------------------------------------------------------- - - message.addExtension(repeatedInt32ExtensionLite , 201); - message.addExtension(repeatedInt64ExtensionLite , 202L); - message.addExtension(repeatedUint32ExtensionLite , 203); - message.addExtension(repeatedUint64ExtensionLite , 204L); - message.addExtension(repeatedSint32ExtensionLite , 205); - message.addExtension(repeatedSint64ExtensionLite , 206L); - message.addExtension(repeatedFixed32ExtensionLite , 207); - message.addExtension(repeatedFixed64ExtensionLite , 208L); - message.addExtension(repeatedSfixed32ExtensionLite, 209); - message.addExtension(repeatedSfixed64ExtensionLite, 210L); - message.addExtension(repeatedFloatExtensionLite , 211F); - message.addExtension(repeatedDoubleExtensionLite , 212D); - message.addExtension(repeatedBoolExtensionLite , true); - message.addExtension(repeatedStringExtensionLite , "215"); - message.addExtension(repeatedBytesExtensionLite , toBytes("216")); - - message.addExtension(repeatedGroupExtensionLite, - RepeatedGroup_extension_lite.newBuilder().setA(217).build()); - message.addExtension(repeatedNestedMessageExtensionLite, - TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build()); - message.addExtension(repeatedForeignMessageExtensionLite, - ForeignMessageLite.newBuilder().setC(219).build()); - message.addExtension(repeatedImportMessageExtensionLite, - ImportMessageLite.newBuilder().setD(220).build()); - message.addExtension(repeatedLazyMessageExtensionLite, - TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build()); - - message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR); - message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR); - message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR); - - message.addExtension(repeatedStringPieceExtensionLite, "224"); - message.addExtension(repeatedCordExtensionLite, "225"); - - // Add a second one of each field. - message.addExtension(repeatedInt32ExtensionLite , 301); - message.addExtension(repeatedInt64ExtensionLite , 302L); - message.addExtension(repeatedUint32ExtensionLite , 303); - message.addExtension(repeatedUint64ExtensionLite , 304L); - message.addExtension(repeatedSint32ExtensionLite , 305); - message.addExtension(repeatedSint64ExtensionLite , 306L); - message.addExtension(repeatedFixed32ExtensionLite , 307); - message.addExtension(repeatedFixed64ExtensionLite , 308L); - message.addExtension(repeatedSfixed32ExtensionLite, 309); - message.addExtension(repeatedSfixed64ExtensionLite, 310L); - message.addExtension(repeatedFloatExtensionLite , 311F); - message.addExtension(repeatedDoubleExtensionLite , 312D); - message.addExtension(repeatedBoolExtensionLite , false); - message.addExtension(repeatedStringExtensionLite , "315"); - message.addExtension(repeatedBytesExtensionLite , toBytes("316")); - - message.addExtension(repeatedGroupExtensionLite, - RepeatedGroup_extension_lite.newBuilder().setA(317).build()); - message.addExtension(repeatedNestedMessageExtensionLite, - TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build()); - message.addExtension(repeatedForeignMessageExtensionLite, - ForeignMessageLite.newBuilder().setC(319).build()); - message.addExtension(repeatedImportMessageExtensionLite, - ImportMessageLite.newBuilder().setD(320).build()); - message.addExtension(repeatedLazyMessageExtensionLite, - TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build()); - - message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ); - message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ); - message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ); - - message.addExtension(repeatedStringPieceExtensionLite, "324"); - message.addExtension(repeatedCordExtensionLite, "325"); - - // ----------------------------------------------------------------- - - message.setExtension(defaultInt32ExtensionLite , 401); - message.setExtension(defaultInt64ExtensionLite , 402L); - message.setExtension(defaultUint32ExtensionLite , 403); - message.setExtension(defaultUint64ExtensionLite , 404L); - message.setExtension(defaultSint32ExtensionLite , 405); - message.setExtension(defaultSint64ExtensionLite , 406L); - message.setExtension(defaultFixed32ExtensionLite , 407); - message.setExtension(defaultFixed64ExtensionLite , 408L); - message.setExtension(defaultSfixed32ExtensionLite, 409); - message.setExtension(defaultSfixed64ExtensionLite, 410L); - message.setExtension(defaultFloatExtensionLite , 411F); - message.setExtension(defaultDoubleExtensionLite , 412D); - message.setExtension(defaultBoolExtensionLite , false); - message.setExtension(defaultStringExtensionLite , "415"); - message.setExtension(defaultBytesExtensionLite , toBytes("416")); - - message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO); - message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO); - message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO); - - message.setExtension(defaultStringPieceExtensionLite, "424"); - message.setExtension(defaultCordExtensionLite, "425"); - - message.setExtension(oneofUint32ExtensionLite, 601); - message.setExtension(oneofNestedMessageExtensionLite, - TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build()); - message.setExtension(oneofStringExtensionLite, "603"); - message.setExtension(oneofBytesExtensionLite, toBytes("604")); - } - - // ------------------------------------------------------------------- - - /** - * Modify the repeated extensions of {@code message} to contain the values - * expected by {@code assertRepeatedExtensionsModified()}. - */ - public static void modifyRepeatedExtensions( - TestAllExtensionsLite.Builder message) { - message.setExtension(repeatedInt32ExtensionLite , 1, 501); - message.setExtension(repeatedInt64ExtensionLite , 1, 502L); - message.setExtension(repeatedUint32ExtensionLite , 1, 503); - message.setExtension(repeatedUint64ExtensionLite , 1, 504L); - message.setExtension(repeatedSint32ExtensionLite , 1, 505); - message.setExtension(repeatedSint64ExtensionLite , 1, 506L); - message.setExtension(repeatedFixed32ExtensionLite , 1, 507); - message.setExtension(repeatedFixed64ExtensionLite , 1, 508L); - message.setExtension(repeatedSfixed32ExtensionLite, 1, 509); - message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L); - message.setExtension(repeatedFloatExtensionLite , 1, 511F); - message.setExtension(repeatedDoubleExtensionLite , 1, 512D); - message.setExtension(repeatedBoolExtensionLite , 1, true); - message.setExtension(repeatedStringExtensionLite , 1, "515"); - message.setExtension(repeatedBytesExtensionLite , 1, toBytes("516")); - - message.setExtension(repeatedGroupExtensionLite, 1, - RepeatedGroup_extension_lite.newBuilder().setA(517).build()); - message.setExtension(repeatedNestedMessageExtensionLite, 1, - TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build()); - message.setExtension(repeatedForeignMessageExtensionLite, 1, - ForeignMessageLite.newBuilder().setC(519).build()); - message.setExtension(repeatedImportMessageExtensionLite, 1, - ImportMessageLite.newBuilder().setD(520).build()); - message.setExtension(repeatedLazyMessageExtensionLite, 1, - TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build()); - - message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO); - message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO); - message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO); - - message.setExtension(repeatedStringPieceExtensionLite, 1, "524"); - message.setExtension(repeatedCordExtensionLite, 1, "525"); - } - - // ------------------------------------------------------------------- - /** * Assert (using {@code junit.framework.Assert}} that all extensions of * {@code message} are set to the values assigned by {@code setAllExtensions}. @@ -2867,38 +2494,6 @@ public final class TestUtil { assertEqualsExactType("525", message.getExtension(repeatedCordExtensionLite, 1)); } - public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) { - message.addExtension(packedInt32ExtensionLite , 601); - message.addExtension(packedInt64ExtensionLite , 602L); - message.addExtension(packedUint32ExtensionLite , 603); - message.addExtension(packedUint64ExtensionLite , 604L); - message.addExtension(packedSint32ExtensionLite , 605); - message.addExtension(packedSint64ExtensionLite , 606L); - message.addExtension(packedFixed32ExtensionLite , 607); - message.addExtension(packedFixed64ExtensionLite , 608L); - message.addExtension(packedSfixed32ExtensionLite, 609); - message.addExtension(packedSfixed64ExtensionLite, 610L); - message.addExtension(packedFloatExtensionLite , 611F); - message.addExtension(packedDoubleExtensionLite , 612D); - message.addExtension(packedBoolExtensionLite , true); - message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR); - // Add a second one of each field. - message.addExtension(packedInt32ExtensionLite , 701); - message.addExtension(packedInt64ExtensionLite , 702L); - message.addExtension(packedUint32ExtensionLite , 703); - message.addExtension(packedUint64ExtensionLite , 704L); - message.addExtension(packedSint32ExtensionLite , 705); - message.addExtension(packedSint64ExtensionLite , 706L); - message.addExtension(packedFixed32ExtensionLite , 707); - message.addExtension(packedFixed64ExtensionLite , 708L); - message.addExtension(packedSfixed32ExtensionLite, 709); - message.addExtension(packedSfixed64ExtensionLite, 710L); - message.addExtension(packedFloatExtensionLite , 711F); - message.addExtension(packedDoubleExtensionLite , 712D); - message.addExtension(packedBoolExtensionLite , false); - message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ); - } - public static void assertPackedExtensionsSet(TestPackedExtensionsLite message) { Assert.assertEquals(2, message.getExtensionCount(packedInt32ExtensionLite )); Assert.assertEquals(2, message.getExtensionCount(packedInt64ExtensionLite )); @@ -4250,7 +3845,7 @@ public final class TestUtil { private int invalidations; - //@Override (Java 1.6 override semantics, but we must support 1.5) + @Override public void markDirty() { invalidations++; } diff --git a/java/core/src/test/java/com/google/protobuf/TestUtilLite.java b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java new file mode 100644 index 00000000..8f33fa14 --- /dev/null +++ b/java/core/src/test/java/com/google/protobuf/TestUtilLite.java @@ -0,0 +1,559 @@ +// 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. + +package com.google.protobuf; + +import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite; +import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite; +import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite; +import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite; +import static com.google.protobuf.UnittestLite.defaultCordExtensionLite; +import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite; +import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite; +import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite; +import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultStringExtensionLite; +import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite; +import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite; +import static com.google.protobuf.UnittestLite.oneofBytesExtensionLite; +import static com.google.protobuf.UnittestLite.oneofNestedMessageExtensionLite; +import static com.google.protobuf.UnittestLite.oneofStringExtensionLite; +import static com.google.protobuf.UnittestLite.oneofUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite; +import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite; +import static com.google.protobuf.UnittestLite.optionalCordExtensionLite; +import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite; +import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite; +import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite; +import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite; +import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalLazyMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalPublicImportMessageExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalStringExtensionLite; +import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite; +import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedBoolExtensionLite; +import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.packedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedFloatExtensionLite; +import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedLazyMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite; +import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite; + +import com.google.protobuf.UnittestImportLite.ImportEnumLite; +import com.google.protobuf.UnittestImportLite.ImportMessageLite; +import com.google.protobuf.UnittestImportPublicLite.PublicImportMessageLite; +import com.google.protobuf.UnittestLite.ForeignEnumLite; +import com.google.protobuf.UnittestLite.ForeignMessageLite; +import com.google.protobuf.UnittestLite.TestAllExtensionsLite; +import com.google.protobuf.UnittestLite.TestAllTypesLite; +import com.google.protobuf.UnittestLite.TestPackedExtensionsLite; + +/** + * Contains methods for setting fields of {@code TestAllTypesLite}, {@code TestAllExtensionsLite}, + * and {@code TestPackedExtensionsLite}. This is analogous to the functionality in TestUtil.java but + * does not depend on the presence of any non-lite protos. + * + *

This code is not to be used outside of {@code com.google.protobuf} and + * subpackages. + */ +public final class TestUtilLite { + private TestUtilLite() {} + + /** Helper to convert a String to ByteString. */ + static ByteString toBytes(String str) { + return ByteString.copyFrom(str.getBytes(Internal.UTF_8)); + } + + /** + * Get a {@code TestAllTypesLite.Builder} with all fields set as they would be by + * {@link #setAllFields(TestAllTypesLite.Builder)}. + */ + public static TestAllTypesLite.Builder getAllLiteSetBuilder() { + TestAllTypesLite.Builder builder = TestAllTypesLite.newBuilder(); + setAllFields(builder); + return builder; + } + + /** + * Get a {@code TestAllExtensionsLite} with all fields set as they would be by + * {@link #setAllExtensions(TestAllExtensionsLite.Builder)}. + */ + public static TestAllExtensionsLite getAllLiteExtensionsSet() { + TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder(); + setAllExtensions(builder); + return builder.build(); + } + + public static TestPackedExtensionsLite getLitePackedExtensionsSet() { + TestPackedExtensionsLite.Builder builder = TestPackedExtensionsLite.newBuilder(); + setPackedExtensions(builder); + return builder.build(); + } + + /** + * Set every field of {@code builder} to the values expected by + * {@code assertAllFieldsSet()}. + */ + public static void setAllFields(TestAllTypesLite.Builder builder) { + builder.setOptionalInt32 (101); + builder.setOptionalInt64 (102); + builder.setOptionalUint32 (103); + builder.setOptionalUint64 (104); + builder.setOptionalSint32 (105); + builder.setOptionalSint64 (106); + builder.setOptionalFixed32 (107); + builder.setOptionalFixed64 (108); + builder.setOptionalSfixed32(109); + builder.setOptionalSfixed64(110); + builder.setOptionalFloat (111); + builder.setOptionalDouble (112); + builder.setOptionalBool (true); + builder.setOptionalString ("115"); + builder.setOptionalBytes (toBytes("116")); + + builder.setOptionalGroup( + TestAllTypesLite.OptionalGroup.newBuilder().setA(117).build()); + builder.setOptionalNestedMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build()); + builder.setOptionalForeignMessage( + ForeignMessageLite.newBuilder().setC(119).build()); + builder.setOptionalImportMessage( + ImportMessageLite.newBuilder().setD(120).build()); + builder.setOptionalPublicImportMessage( + PublicImportMessageLite.newBuilder().setE(126).build()); + builder.setOptionalLazyMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build()); + + builder.setOptionalNestedEnum (TestAllTypesLite.NestedEnum.BAZ); + builder.setOptionalForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ); + builder.setOptionalImportEnum (ImportEnumLite.IMPORT_LITE_BAZ); + + builder.setOptionalStringPiece("124"); + builder.setOptionalCord("125"); + + // ----------------------------------------------------------------- + + builder.addRepeatedInt32 (201); + builder.addRepeatedInt64 (202); + builder.addRepeatedUint32 (203); + builder.addRepeatedUint64 (204); + builder.addRepeatedSint32 (205); + builder.addRepeatedSint64 (206); + builder.addRepeatedFixed32 (207); + builder.addRepeatedFixed64 (208); + builder.addRepeatedSfixed32(209); + builder.addRepeatedSfixed64(210); + builder.addRepeatedFloat (211); + builder.addRepeatedDouble (212); + builder.addRepeatedBool (true); + builder.addRepeatedString ("215"); + builder.addRepeatedBytes (toBytes("216")); + + builder.addRepeatedGroup( + TestAllTypesLite.RepeatedGroup.newBuilder().setA(217).build()); + builder.addRepeatedNestedMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build()); + builder.addRepeatedForeignMessage( + ForeignMessageLite.newBuilder().setC(219).build()); + builder.addRepeatedImportMessage( + ImportMessageLite.newBuilder().setD(220).build()); + builder.addRepeatedLazyMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build()); + + builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAR); + builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAR); + builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAR); + + builder.addRepeatedStringPiece("224"); + builder.addRepeatedCord("225"); + + // Add a second one of each field. + builder.addRepeatedInt32 (301); + builder.addRepeatedInt64 (302); + builder.addRepeatedUint32 (303); + builder.addRepeatedUint64 (304); + builder.addRepeatedSint32 (305); + builder.addRepeatedSint64 (306); + builder.addRepeatedFixed32 (307); + builder.addRepeatedFixed64 (308); + builder.addRepeatedSfixed32(309); + builder.addRepeatedSfixed64(310); + builder.addRepeatedFloat (311); + builder.addRepeatedDouble (312); + builder.addRepeatedBool (false); + builder.addRepeatedString ("315"); + builder.addRepeatedBytes (toBytes("316")); + + builder.addRepeatedGroup( + TestAllTypesLite.RepeatedGroup.newBuilder().setA(317).build()); + builder.addRepeatedNestedMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build()); + builder.addRepeatedForeignMessage( + ForeignMessageLite.newBuilder().setC(319).build()); + builder.addRepeatedImportMessage( + ImportMessageLite.newBuilder().setD(320).build()); + builder.addRepeatedLazyMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build()); + + builder.addRepeatedNestedEnum (TestAllTypesLite.NestedEnum.BAZ); + builder.addRepeatedForeignEnum(ForeignEnumLite.FOREIGN_LITE_BAZ); + builder.addRepeatedImportEnum (ImportEnumLite.IMPORT_LITE_BAZ); + + builder.addRepeatedStringPiece("324"); + builder.addRepeatedCord("325"); + + // ----------------------------------------------------------------- + + builder.setDefaultInt32 (401); + builder.setDefaultInt64 (402); + builder.setDefaultUint32 (403); + builder.setDefaultUint64 (404); + builder.setDefaultSint32 (405); + builder.setDefaultSint64 (406); + builder.setDefaultFixed32 (407); + builder.setDefaultFixed64 (408); + builder.setDefaultSfixed32(409); + builder.setDefaultSfixed64(410); + builder.setDefaultFloat (411); + builder.setDefaultDouble (412); + builder.setDefaultBool (false); + builder.setDefaultString ("415"); + builder.setDefaultBytes (toBytes("416")); + + builder.setDefaultNestedEnum (TestAllTypesLite.NestedEnum.FOO); + builder.setDefaultForeignEnum(ForeignEnumLite.FOREIGN_LITE_FOO); + builder.setDefaultImportEnum (ImportEnumLite.IMPORT_LITE_FOO); + + builder.setDefaultStringPiece("424"); + builder.setDefaultCord("425"); + + builder.setOneofUint32(601); + builder.setOneofNestedMessage( + TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build()); + builder.setOneofString("603"); + builder.setOneofBytes(toBytes("604")); + } + + /** + * Get an unmodifiable {@link ExtensionRegistryLite} containing all the + * extensions of {@code TestAllExtensionsLite}. + */ + public static ExtensionRegistryLite getExtensionRegistryLite() { + ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance(); + registerAllExtensionsLite(registry); + return registry.getUnmodifiable(); + } + + /** + * Register all of {@code TestAllExtensionsLite}'s extensions with the + * given {@link ExtensionRegistryLite}. + */ + public static void registerAllExtensionsLite(ExtensionRegistryLite registry) { + UnittestLite.registerAllExtensions(registry); + } + + // =================================================================== + // Lite extensions + + /** + * Set every field of {@code message} to the values expected by + * {@code assertAllExtensionsSet()}. + */ + public static void setAllExtensions(TestAllExtensionsLite.Builder message) { + message.setExtension(optionalInt32ExtensionLite , 101); + message.setExtension(optionalInt64ExtensionLite , 102L); + message.setExtension(optionalUint32ExtensionLite , 103); + message.setExtension(optionalUint64ExtensionLite , 104L); + message.setExtension(optionalSint32ExtensionLite , 105); + message.setExtension(optionalSint64ExtensionLite , 106L); + message.setExtension(optionalFixed32ExtensionLite , 107); + message.setExtension(optionalFixed64ExtensionLite , 108L); + message.setExtension(optionalSfixed32ExtensionLite, 109); + message.setExtension(optionalSfixed64ExtensionLite, 110L); + message.setExtension(optionalFloatExtensionLite , 111F); + message.setExtension(optionalDoubleExtensionLite , 112D); + message.setExtension(optionalBoolExtensionLite , true); + message.setExtension(optionalStringExtensionLite , "115"); + message.setExtension(optionalBytesExtensionLite , toBytes("116")); + + message.setExtension(optionalGroupExtensionLite, + OptionalGroup_extension_lite.newBuilder().setA(117).build()); + message.setExtension(optionalNestedMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build()); + message.setExtension(optionalForeignMessageExtensionLite, + ForeignMessageLite.newBuilder().setC(119).build()); + message.setExtension(optionalImportMessageExtensionLite, + ImportMessageLite.newBuilder().setD(120).build()); + message.setExtension(optionalPublicImportMessageExtensionLite, + PublicImportMessageLite.newBuilder().setE(126).build()); + message.setExtension(optionalLazyMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(127).build()); + + message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ); + message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ); + message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ); + + message.setExtension(optionalStringPieceExtensionLite, "124"); + message.setExtension(optionalCordExtensionLite, "125"); + + // ----------------------------------------------------------------- + + message.addExtension(repeatedInt32ExtensionLite , 201); + message.addExtension(repeatedInt64ExtensionLite , 202L); + message.addExtension(repeatedUint32ExtensionLite , 203); + message.addExtension(repeatedUint64ExtensionLite , 204L); + message.addExtension(repeatedSint32ExtensionLite , 205); + message.addExtension(repeatedSint64ExtensionLite , 206L); + message.addExtension(repeatedFixed32ExtensionLite , 207); + message.addExtension(repeatedFixed64ExtensionLite , 208L); + message.addExtension(repeatedSfixed32ExtensionLite, 209); + message.addExtension(repeatedSfixed64ExtensionLite, 210L); + message.addExtension(repeatedFloatExtensionLite , 211F); + message.addExtension(repeatedDoubleExtensionLite , 212D); + message.addExtension(repeatedBoolExtensionLite , true); + message.addExtension(repeatedStringExtensionLite , "215"); + message.addExtension(repeatedBytesExtensionLite , toBytes("216")); + + message.addExtension(repeatedGroupExtensionLite, + RepeatedGroup_extension_lite.newBuilder().setA(217).build()); + message.addExtension(repeatedNestedMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build()); + message.addExtension(repeatedForeignMessageExtensionLite, + ForeignMessageLite.newBuilder().setC(219).build()); + message.addExtension(repeatedImportMessageExtensionLite, + ImportMessageLite.newBuilder().setD(220).build()); + message.addExtension(repeatedLazyMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(227).build()); + + message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR); + message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR); + message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR); + + message.addExtension(repeatedStringPieceExtensionLite, "224"); + message.addExtension(repeatedCordExtensionLite, "225"); + + // Add a second one of each field. + message.addExtension(repeatedInt32ExtensionLite , 301); + message.addExtension(repeatedInt64ExtensionLite , 302L); + message.addExtension(repeatedUint32ExtensionLite , 303); + message.addExtension(repeatedUint64ExtensionLite , 304L); + message.addExtension(repeatedSint32ExtensionLite , 305); + message.addExtension(repeatedSint64ExtensionLite , 306L); + message.addExtension(repeatedFixed32ExtensionLite , 307); + message.addExtension(repeatedFixed64ExtensionLite , 308L); + message.addExtension(repeatedSfixed32ExtensionLite, 309); + message.addExtension(repeatedSfixed64ExtensionLite, 310L); + message.addExtension(repeatedFloatExtensionLite , 311F); + message.addExtension(repeatedDoubleExtensionLite , 312D); + message.addExtension(repeatedBoolExtensionLite , false); + message.addExtension(repeatedStringExtensionLite , "315"); + message.addExtension(repeatedBytesExtensionLite , toBytes("316")); + + message.addExtension(repeatedGroupExtensionLite, + RepeatedGroup_extension_lite.newBuilder().setA(317).build()); + message.addExtension(repeatedNestedMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build()); + message.addExtension(repeatedForeignMessageExtensionLite, + ForeignMessageLite.newBuilder().setC(319).build()); + message.addExtension(repeatedImportMessageExtensionLite, + ImportMessageLite.newBuilder().setD(320).build()); + message.addExtension(repeatedLazyMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(327).build()); + + message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ); + message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ); + message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ); + + message.addExtension(repeatedStringPieceExtensionLite, "324"); + message.addExtension(repeatedCordExtensionLite, "325"); + + // ----------------------------------------------------------------- + + message.setExtension(defaultInt32ExtensionLite , 401); + message.setExtension(defaultInt64ExtensionLite , 402L); + message.setExtension(defaultUint32ExtensionLite , 403); + message.setExtension(defaultUint64ExtensionLite , 404L); + message.setExtension(defaultSint32ExtensionLite , 405); + message.setExtension(defaultSint64ExtensionLite , 406L); + message.setExtension(defaultFixed32ExtensionLite , 407); + message.setExtension(defaultFixed64ExtensionLite , 408L); + message.setExtension(defaultSfixed32ExtensionLite, 409); + message.setExtension(defaultSfixed64ExtensionLite, 410L); + message.setExtension(defaultFloatExtensionLite , 411F); + message.setExtension(defaultDoubleExtensionLite , 412D); + message.setExtension(defaultBoolExtensionLite , false); + message.setExtension(defaultStringExtensionLite , "415"); + message.setExtension(defaultBytesExtensionLite , toBytes("416")); + + message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO); + message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO); + message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO); + + message.setExtension(defaultStringPieceExtensionLite, "424"); + message.setExtension(defaultCordExtensionLite, "425"); + + message.setExtension(oneofUint32ExtensionLite, 601); + message.setExtension(oneofNestedMessageExtensionLite, + TestAllTypesLite.NestedMessage.newBuilder().setBb(602).build()); + message.setExtension(oneofStringExtensionLite, "603"); + message.setExtension(oneofBytesExtensionLite, toBytes("604")); + } + + // ------------------------------------------------------------------- + + /** + * Modify the repeated extensions of {@code message} to contain the values + * expected by {@code assertRepeatedExtensionsModified()}. + */ + public static void modifyRepeatedExtensions( + TestAllExtensionsLite.Builder message) { + message.setExtension(repeatedInt32ExtensionLite , 1, 501); + message.setExtension(repeatedInt64ExtensionLite , 1, 502L); + message.setExtension(repeatedUint32ExtensionLite , 1, 503); + message.setExtension(repeatedUint64ExtensionLite , 1, 504L); + message.setExtension(repeatedSint32ExtensionLite , 1, 505); + message.setExtension(repeatedSint64ExtensionLite , 1, 506L); + message.setExtension(repeatedFixed32ExtensionLite , 1, 507); + message.setExtension(repeatedFixed64ExtensionLite , 1, 508L); + message.setExtension(repeatedSfixed32ExtensionLite, 1, 509); + message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L); + message.setExtension(repeatedFloatExtensionLite , 1, 511F); + message.setExtension(repeatedDoubleExtensionLite , 1, 512D); + message.setExtension(repeatedBoolExtensionLite , 1, true); + message.setExtension(repeatedStringExtensionLite , 1, "515"); + message.setExtension(repeatedBytesExtensionLite , 1, toBytes("516")); + + message.setExtension(repeatedGroupExtensionLite, 1, + RepeatedGroup_extension_lite.newBuilder().setA(517).build()); + message.setExtension(repeatedNestedMessageExtensionLite, 1, + TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build()); + message.setExtension(repeatedForeignMessageExtensionLite, 1, + ForeignMessageLite.newBuilder().setC(519).build()); + message.setExtension(repeatedImportMessageExtensionLite, 1, + ImportMessageLite.newBuilder().setD(520).build()); + message.setExtension(repeatedLazyMessageExtensionLite, 1, + TestAllTypesLite.NestedMessage.newBuilder().setBb(527).build()); + + message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO); + message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO); + message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO); + + message.setExtension(repeatedStringPieceExtensionLite, 1, "524"); + message.setExtension(repeatedCordExtensionLite, 1, "525"); + } + + public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) { + message.addExtension(packedInt32ExtensionLite , 601); + message.addExtension(packedInt64ExtensionLite , 602L); + message.addExtension(packedUint32ExtensionLite , 603); + message.addExtension(packedUint64ExtensionLite , 604L); + message.addExtension(packedSint32ExtensionLite , 605); + message.addExtension(packedSint64ExtensionLite , 606L); + message.addExtension(packedFixed32ExtensionLite , 607); + message.addExtension(packedFixed64ExtensionLite , 608L); + message.addExtension(packedSfixed32ExtensionLite, 609); + message.addExtension(packedSfixed64ExtensionLite, 610L); + message.addExtension(packedFloatExtensionLite , 611F); + message.addExtension(packedDoubleExtensionLite , 612D); + message.addExtension(packedBoolExtensionLite , true); + message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR); + // Add a second one of each field. + message.addExtension(packedInt32ExtensionLite , 701); + message.addExtension(packedInt64ExtensionLite , 702L); + message.addExtension(packedUint32ExtensionLite , 703); + message.addExtension(packedUint64ExtensionLite , 704L); + message.addExtension(packedSint32ExtensionLite , 705); + message.addExtension(packedSint64ExtensionLite , 706L); + message.addExtension(packedFixed32ExtensionLite , 707); + message.addExtension(packedFixed64ExtensionLite , 708L); + message.addExtension(packedSfixed32ExtensionLite, 709); + message.addExtension(packedSfixed64ExtensionLite, 710L); + message.addExtension(packedFloatExtensionLite , 711F); + message.addExtension(packedDoubleExtensionLite , 712D); + message.addExtension(packedBoolExtensionLite , false); + message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ); + } +} 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 3f47d924..63c17cd0 100644 --- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java @@ -775,11 +775,14 @@ public class TextFormatTest extends TestCase { public void testParseBoolean() throws Exception { String goodText = "repeated_bool: t repeated_bool : 0\n" + - "repeated_bool :f repeated_bool:1"; + "repeated_bool :f repeated_bool:1\n" + + "repeated_bool: False repeated_bool: True"; String goodTextCanonical = "repeated_bool: true\n" + "repeated_bool: false\n" + "repeated_bool: false\n" + + "repeated_bool: true\n" + + "repeated_bool: false\n" + "repeated_bool: true\n"; TestAllTypes.Builder builder = TestAllTypes.newBuilder(); TextFormat.merge(goodText, builder); diff --git a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java index 8c9dcafe..32380f70 100644 --- a/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java +++ b/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java @@ -50,6 +50,7 @@ import java.util.Map; * @author kenton@google.com (Kenton Varda) */ public class UnknownFieldSetTest extends TestCase { + @Override public void setUp() throws Exception { descriptor = TestAllTypes.getDescriptor(); allFields = TestUtil.getAllSet(); diff --git a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java index b3aabb8f..e66b371c 100644 --- a/java/core/src/test/java/com/google/protobuf/WireFormatTest.java +++ b/java/core/src/test/java/com/google/protobuf/WireFormatTest.java @@ -132,7 +132,7 @@ public class WireFormatTest extends TestCase { // so if we serialize a TestAllExtensions then parse it as TestAllTypes // it should work. - TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet(); + TestAllExtensionsLite message = TestUtilLite.getAllLiteExtensionsSet(); ByteString rawBytes = message.toByteString(); assertEquals(rawBytes.size(), message.getSerializedSize()); @@ -144,7 +144,7 @@ public class WireFormatTest extends TestCase { public void testSerializePackedExtensionsLite() throws Exception { // TestPackedTypes and TestPackedExtensions should have compatible wire // formats; check that they serialize to the same string. - TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet(); + TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet(); ByteString rawBytes = message.toByteString(); TestPackedTypes message2 = TestUtil.getPackedSet(); @@ -190,7 +190,7 @@ public class WireFormatTest extends TestCase { TestAllTypes message = TestUtil.getAllSet(); ByteString rawBytes = message.toByteString(); - ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite(); + ExtensionRegistryLite registry_lite = TestUtilLite.getExtensionRegistryLite(); TestAllExtensionsLite message2 = TestAllExtensionsLite.parseFrom(rawBytes, registry_lite); @@ -208,10 +208,10 @@ public class WireFormatTest extends TestCase { public void testParsePackedExtensionsLite() throws Exception { // Ensure that packed extensions can be properly parsed. - TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet(); + TestPackedExtensionsLite message = TestUtilLite.getLitePackedExtensionsSet(); ByteString rawBytes = message.toByteString(); - ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite(); + ExtensionRegistryLite registry = TestUtilLite.getExtensionRegistryLite(); TestPackedExtensionsLite message2 = TestPackedExtensionsLite.parseFrom(rawBytes, registry); diff --git a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto index f75484de..6eef42c5 100644 --- a/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto +++ b/java/core/src/test/proto/com/google/protobuf/lite_equals_and_hash.proto @@ -34,9 +34,6 @@ syntax = "proto2"; package protobuf_unittest.lite_equals_and_hash; -// This proto definition is used to test that java_generate_equals_and_hash -// works correctly with the LITE_RUNTIME. -option java_generate_equals_and_hash = true; option optimize_for = LITE_RUNTIME; message TestOneofEquals { diff --git a/java/lite/generate-sources-build.xml b/java/lite/generate-sources-build.xml new file mode 100644 index 00000000..89c21c13 --- /dev/null +++ b/java/lite/generate-sources-build.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/java/lite/generate-test-sources-build.xml b/java/lite/generate-test-sources-build.xml new file mode 100644 index 00000000..cdd1ee89 --- /dev/null +++ b/java/lite/generate-test-sources-build.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/lite/pom.xml b/java/lite/pom.xml index 70c7d047..23cb4f78 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -50,7 +50,7 @@ generate-sources - + @@ -64,7 +64,7 @@ generate-test-sources - + @@ -78,8 +78,8 @@ maven-compiler-plugin - ${generated.sources.dir} - ${generated.testsources.dir} + ${generated.sources.lite.dir} + ${generated.testsources.lite.dir} **/AbstractMessageLite.java **/AbstractParser.java diff --git a/java/pom.xml b/java/pom.xml index 787bc534..e8dc5ded 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -33,6 +33,8 @@ src/test/proto ${project.build.directory}/generated-sources ${project.build.directory}/generated-test-sources + ${project.build.directory}/generated-sources-lite + ${project.build.directory}/generated-test-sources-lite diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java new file mode 100644 index 00000000..03c0d579 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java @@ -0,0 +1,553 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Descriptors.EnumValueDescriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.OneofDescriptor; +import com.google.protobuf.Internal.EnumLite; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * A partial implementation of the {@link Message} interface which implements + * as many methods of that interface as possible in terms of other methods. + * + * @author kenton@google.com Kenton Varda + */ +public abstract class AbstractMessage + // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType. + extends AbstractMessageLite + implements Message { + + @Override + public boolean isInitialized() { + return MessageReflection.isInitialized(this); + } + + + @Override + public List findInitializationErrors() { + return MessageReflection.findMissingFields(this); + } + + @Override + public String getInitializationErrorString() { + return MessageReflection.delimitWithCommas(findInitializationErrors()); + } + + /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ + @Override + public boolean hasOneof(OneofDescriptor oneof) { + throw new UnsupportedOperationException("hasOneof() is not implemented."); + } + + /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ + @Override + public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { + throw new UnsupportedOperationException( + "getOneofFieldDescriptor() is not implemented."); + } + + @Override + public final String toString() { + return TextFormat.printToString(this); + } + + @Override + public void writeTo(final CodedOutputStream output) throws IOException { + MessageReflection.writeMessageTo(this, getAllFields(), output, false); + } + + protected int memoizedSize = -1; + + @Override + public int getSerializedSize() { + int size = memoizedSize; + if (size != -1) { + return size; + } + + memoizedSize = MessageReflection.getSerializedSize(this, getAllFields()); + return memoizedSize; + } + + @Override + public boolean equals(final Object other) { + if (other == this) { + return true; + } + if (!(other instanceof Message)) { + return false; + } + final Message otherMessage = (Message) other; + if (getDescriptorForType() != otherMessage.getDescriptorForType()) { + return false; + } + return compareFields(getAllFields(), otherMessage.getAllFields()) && + getUnknownFields().equals(otherMessage.getUnknownFields()); + } + + @Override + public int hashCode() { + int hash = memoizedHashCode; + if (hash == 0) { + hash = 41; + hash = (19 * hash) + getDescriptorForType().hashCode(); + hash = hashFields(hash, getAllFields()); + hash = (29 * hash) + getUnknownFields().hashCode(); + memoizedHashCode = hash; + } + return hash; + } + + private static ByteString toByteString(Object value) { + if (value instanceof byte[]) { + return ByteString.copyFrom((byte[]) value); + } else { + return (ByteString) value; + } + } + + /** + * Compares two bytes fields. The parameters must be either a byte array or a + * ByteString object. They can be of different type though. + */ + private static boolean compareBytes(Object a, Object b) { + if (a instanceof byte[] && b instanceof byte[]) { + return Arrays.equals((byte[])a, (byte[])b); + } + return toByteString(a).equals(toByteString(b)); + } + + /** + * Converts a list of MapEntry messages into a Map used for equals() and + * hashCode(). + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static Map convertMapEntryListToMap(List list) { + if (list.isEmpty()) { + return Collections.emptyMap(); + } + Map result = new HashMap(); + Iterator iterator = list.iterator(); + Message entry = (Message) iterator.next(); + Descriptors.Descriptor descriptor = entry.getDescriptorForType(); + Descriptors.FieldDescriptor key = descriptor.findFieldByName("key"); + Descriptors.FieldDescriptor value = descriptor.findFieldByName("value"); + Object fieldValue = entry.getField(value); + if (fieldValue instanceof EnumValueDescriptor) { + fieldValue = ((EnumValueDescriptor) fieldValue).getNumber(); + } + result.put(entry.getField(key), fieldValue); + while (iterator.hasNext()) { + entry = (Message) iterator.next(); + fieldValue = entry.getField(value); + if (fieldValue instanceof EnumValueDescriptor) { + fieldValue = ((EnumValueDescriptor) fieldValue).getNumber(); + } + result.put(entry.getField(key), fieldValue); + } + return result; + } + + /** + * Compares two map fields. The parameters must be a list of MapEntry + * messages. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static boolean compareMapField(Object a, Object b) { + Map ma = convertMapEntryListToMap((List) a); + Map mb = convertMapEntryListToMap((List) b); + return MapFieldLite.equals(ma, mb); + } + + /** + * Compares two set of fields. + * This method is used to implement {@link AbstractMessage#equals(Object)} + * and {@link AbstractMutableMessage#equals(Object)}. It takes special care + * of bytes fields because immutable messages and mutable messages use + * different Java type to reprensent a bytes field and this method should be + * able to compare immutable messages, mutable messages and also an immutable + * message to a mutable message. + */ + static boolean compareFields(Map a, + Map b) { + if (a.size() != b.size()) { + return false; + } + for (FieldDescriptor descriptor : a.keySet()) { + if (!b.containsKey(descriptor)) { + return false; + } + Object value1 = a.get(descriptor); + Object value2 = b.get(descriptor); + if (descriptor.getType() == FieldDescriptor.Type.BYTES) { + if (descriptor.isRepeated()) { + List list1 = (List) value1; + List list2 = (List) value2; + if (list1.size() != list2.size()) { + return false; + } + for (int i = 0; i < list1.size(); i++) { + if (!compareBytes(list1.get(i), list2.get(i))) { + return false; + } + } + } else { + // Compares a singular bytes field. + if (!compareBytes(value1, value2)) { + return false; + } + } + } else if (descriptor.isMapField()) { + if (!compareMapField(value1, value2)) { + return false; + } + } else { + // Compare non-bytes fields. + if (!value1.equals(value2)) { + return false; + } + } + } + return true; + } + + /** + * Calculates the hash code of a map field. {@code value} must be a list of + * MapEntry messages. + */ + @SuppressWarnings("unchecked") + private static int hashMapField(Object value) { + return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value)); + } + + /** Get a hash code for given fields and values, using the given seed. */ + @SuppressWarnings("unchecked") + protected static int hashFields(int hash, Map map) { + for (Map.Entry entry : map.entrySet()) { + FieldDescriptor field = entry.getKey(); + Object value = entry.getValue(); + hash = (37 * hash) + field.getNumber(); + if (field.isMapField()) { + hash = (53 * hash) + hashMapField(value); + } else if (field.getType() != FieldDescriptor.Type.ENUM){ + hash = (53 * hash) + value.hashCode(); + } else if (field.isRepeated()) { + List list = (List) value; + hash = (53 * hash) + Internal.hashEnumList(list); + } else { + hash = (53 * hash) + Internal.hashEnum((EnumLite) value); + } + } + return hash; + } + + /** + * Package private helper method for AbstractParser to create + * UninitializedMessageException with missing field information. + */ + @Override + UninitializedMessageException newUninitializedMessageException() { + return Builder.newUninitializedMessageException(this); + } + + // ================================================================= + + /** + * A partial implementation of the {@link Message.Builder} interface which + * implements as many methods of that interface as possible in terms of + * other methods. + */ + @SuppressWarnings("unchecked") + public static abstract class Builder> + extends AbstractMessageLite.Builder + implements Message.Builder { + // The compiler produces an error if this is not declared explicitly. + @Override + public abstract BuilderType clone(); + + /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ + @Override + public boolean hasOneof(OneofDescriptor oneof) { + throw new UnsupportedOperationException("hasOneof() is not implemented."); + } + + /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ + @Override + public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { + throw new UnsupportedOperationException( + "getOneofFieldDescriptor() is not implemented."); + } + + /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ + @Override + public BuilderType clearOneof(OneofDescriptor oneof) { + throw new UnsupportedOperationException("clearOneof() is not implemented."); + } + + @Override + public BuilderType clear() { + for (final Map.Entry entry : + getAllFields().entrySet()) { + clearField(entry.getKey()); + } + return (BuilderType) this; + } + + @Override + public List findInitializationErrors() { + return MessageReflection.findMissingFields(this); + } + + @Override + public String getInitializationErrorString() { + return MessageReflection.delimitWithCommas(findInitializationErrors()); + } + + @Override + protected BuilderType internalMergeFrom(AbstractMessageLite other) { + return mergeFrom((Message) other); + } + + @Override + public BuilderType mergeFrom(final Message other) { + if (other.getDescriptorForType() != getDescriptorForType()) { + throw new IllegalArgumentException( + "mergeFrom(Message) can only merge messages of the same type."); + } + + // Note: We don't attempt to verify that other's fields have valid + // types. Doing so would be a losing battle. We'd have to verify + // all sub-messages as well, and we'd have to make copies of all of + // them to insure that they don't change after verification (since + // the Message interface itself cannot enforce immutability of + // implementations). + // TODO(kenton): Provide a function somewhere called makeDeepCopy() + // which allows people to make secure deep copies of messages. + + for (final Map.Entry entry : + other.getAllFields().entrySet()) { + final FieldDescriptor field = entry.getKey(); + if (field.isRepeated()) { + for (final Object element : (List)entry.getValue()) { + addRepeatedField(field, element); + } + } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { + final Message existingValue = (Message)getField(field); + if (existingValue == existingValue.getDefaultInstanceForType()) { + setField(field, entry.getValue()); + } else { + setField(field, + existingValue.newBuilderForType() + .mergeFrom(existingValue) + .mergeFrom((Message)entry.getValue()) + .build()); + } + } else { + setField(field, entry.getValue()); + } + } + + mergeUnknownFields(other.getUnknownFields()); + + return (BuilderType) this; + } + + @Override + public BuilderType mergeFrom(final CodedInputStream input) + throws IOException { + return mergeFrom(input, ExtensionRegistry.getEmptyRegistry()); + } + + @Override + public BuilderType mergeFrom( + final CodedInputStream input, + final ExtensionRegistryLite extensionRegistry) + throws IOException { + final UnknownFieldSet.Builder unknownFields = + UnknownFieldSet.newBuilder(getUnknownFields()); + while (true) { + final int tag = input.readTag(); + if (tag == 0) { + break; + } + + MessageReflection.BuilderAdapter builderAdapter = + new MessageReflection.BuilderAdapter(this); + if (!MessageReflection.mergeFieldFrom(input, unknownFields, + extensionRegistry, + getDescriptorForType(), + builderAdapter, + tag)) { + // end group tag + break; + } + } + setUnknownFields(unknownFields.build()); + return (BuilderType) this; + } + + @Override + public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { + setUnknownFields( + UnknownFieldSet.newBuilder(getUnknownFields()) + .mergeFrom(unknownFields) + .build()); + return (BuilderType) this; + } + + @Override + public Message.Builder getFieldBuilder(final FieldDescriptor field) { + throw new UnsupportedOperationException( + "getFieldBuilder() called on an unsupported message type."); + } + + @Override + public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) { + throw new UnsupportedOperationException( + "getRepeatedFieldBuilder() called on an unsupported message type."); + } + + @Override + public String toString() { + return TextFormat.printToString(this); + } + + /** + * Construct an UninitializedMessageException reporting missing fields in + * the given message. + */ + protected static UninitializedMessageException + newUninitializedMessageException(Message message) { + return new UninitializedMessageException( + MessageReflection.findMissingFields(message)); + } + + // =============================================================== + // The following definitions seem to be required in order to make javac + // not produce weird errors like: + // + // java/com/google/protobuf/DynamicMessage.java:203: types + // com.google.protobuf.AbstractMessage.Builder< + // com.google.protobuf.DynamicMessage.Builder> and + // com.google.protobuf.AbstractMessage.Builder< + // com.google.protobuf.DynamicMessage.Builder> are incompatible; both + // define mergeFrom(com.google.protobuf.ByteString), but with unrelated + // return types. + // + // Strangely, these lines are only needed if javac is invoked separately + // on AbstractMessage.java and AbstractMessageLite.java. If javac is + // invoked on both simultaneously, it works. (Or maybe the important + // point is whether or not DynamicMessage.java is compiled together with + // AbstractMessageLite.java -- not sure.) I suspect this is a compiler + // bug. + + @Override + public BuilderType mergeFrom(final ByteString data) + throws InvalidProtocolBufferException { + return (BuilderType) super.mergeFrom(data); + } + + @Override + public BuilderType mergeFrom( + final ByteString data, + final ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return (BuilderType) super.mergeFrom(data, extensionRegistry); + } + + @Override + public BuilderType mergeFrom(final byte[] data) + throws InvalidProtocolBufferException { + return (BuilderType) super.mergeFrom(data); + } + + @Override + public BuilderType mergeFrom( + final byte[] data, final int off, final int len) + throws InvalidProtocolBufferException { + return (BuilderType) super.mergeFrom(data, off, len); + } + + @Override + public BuilderType mergeFrom( + final byte[] data, + final ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return (BuilderType) super.mergeFrom(data, extensionRegistry); + } + + @Override + public BuilderType mergeFrom( + final byte[] data, final int off, final int len, + final ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry); + } + + @Override + public BuilderType mergeFrom(final InputStream input) + throws IOException { + return (BuilderType) super.mergeFrom(input); + } + + @Override + public BuilderType mergeFrom( + final InputStream input, + final ExtensionRegistryLite extensionRegistry) + throws IOException { + return (BuilderType) super.mergeFrom(input, extensionRegistry); + } + + @Override + public boolean mergeDelimitedFrom(final InputStream input) + throws IOException { + return super.mergeDelimitedFrom(input); + } + + @Override + public boolean mergeDelimitedFrom( + final InputStream input, + final ExtensionRegistryLite extensionRegistry) + throws IOException { + return super.mergeDelimitedFrom(input, extensionRegistry); + } + } +} diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java new file mode 100644 index 00000000..43736dd1 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java @@ -0,0 +1,386 @@ +// 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. + +package com.google.protobuf; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collection; + +/** + * A partial implementation of the {@link MessageLite} interface which + * implements as many methods of that interface as possible in terms of other + * methods. + * + * @author kenton@google.com Kenton Varda + */ +public abstract class AbstractMessageLite< + MessageType extends AbstractMessageLite, + BuilderType extends AbstractMessageLite.Builder> + implements MessageLite { + protected int memoizedHashCode = 0; + + @Override + public ByteString toByteString() { + try { + final ByteString.CodedBuilder out = + ByteString.newCodedBuilder(getSerializedSize()); + writeTo(out.getCodedOutput()); + return out.build(); + } catch (IOException e) { + throw new RuntimeException( + "Serializing to a ByteString threw an IOException (should " + + "never happen).", e); + } + } + + @Override + public byte[] toByteArray() { + try { + final byte[] result = new byte[getSerializedSize()]; + final CodedOutputStream output = CodedOutputStream.newInstance(result); + writeTo(output); + output.checkNoSpaceLeft(); + return result; + } catch (IOException e) { + throw new RuntimeException( + "Serializing to a byte array threw an IOException " + + "(should never happen).", e); + } + } + + @Override + public void writeTo(final OutputStream output) throws IOException { + final int bufferSize = + CodedOutputStream.computePreferredBufferSize(getSerializedSize()); + final CodedOutputStream codedOutput = + CodedOutputStream.newInstance(output, bufferSize); + writeTo(codedOutput); + codedOutput.flush(); + } + + @Override + public void writeDelimitedTo(final OutputStream output) throws IOException { + final int serialized = getSerializedSize(); + final int bufferSize = CodedOutputStream.computePreferredBufferSize( + CodedOutputStream.computeRawVarint32Size(serialized) + serialized); + final CodedOutputStream codedOutput = + CodedOutputStream.newInstance(output, bufferSize); + codedOutput.writeRawVarint32(serialized); + writeTo(codedOutput); + codedOutput.flush(); + } + + + /** + * Package private helper method for AbstractParser to create + * UninitializedMessageException. + */ + UninitializedMessageException newUninitializedMessageException() { + return new UninitializedMessageException(this); + } + + protected static void checkByteStringIsUtf8(ByteString byteString) + throws IllegalArgumentException { + if (!byteString.isValidUtf8()) { + throw new IllegalArgumentException("Byte string is not UTF-8."); + } + } + + protected static void addAll(final Iterable values, + final Collection list) { + Builder.addAll(values, list); + } + + /** + * A partial implementation of the {@link Message.Builder} interface which + * implements as many methods of that interface as possible in terms of + * other methods. + */ + @SuppressWarnings("unchecked") + public abstract static class Builder< + MessageType extends AbstractMessageLite, + BuilderType extends Builder> + implements MessageLite.Builder { + // The compiler produces an error if this is not declared explicitly. + @Override + public abstract BuilderType clone(); + + @Override + public BuilderType mergeFrom(final CodedInputStream input) throws IOException { + return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry()); + } + + // Re-defined here for return type covariance. + @Override + public abstract BuilderType mergeFrom( + final CodedInputStream input, final ExtensionRegistryLite extensionRegistry) + throws IOException; + + @Override + public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException { + try { + final CodedInputStream input = data.newCodedInput(); + mergeFrom(input); + input.checkLastTagWas(0); + return (BuilderType) this; + } catch (InvalidProtocolBufferException e) { + throw e; + } catch (IOException e) { + throw new RuntimeException( + "Reading from a ByteString threw an IOException (should " + + "never happen).", e); + } + } + + @Override + public BuilderType mergeFrom( + final ByteString data, final ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + try { + final CodedInputStream input = data.newCodedInput(); + mergeFrom(input, extensionRegistry); + input.checkLastTagWas(0); + return (BuilderType) this; + } catch (InvalidProtocolBufferException e) { + throw e; + } catch (IOException e) { + throw new RuntimeException( + "Reading from a ByteString threw an IOException (should " + + "never happen).", e); + } + } + + @Override + public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException { + return mergeFrom(data, 0, data.length); + } + + @Override + public BuilderType mergeFrom(final byte[] data, final int off, final int len) + throws InvalidProtocolBufferException { + try { + final CodedInputStream input = + CodedInputStream.newInstance(data, off, len); + mergeFrom(input); + input.checkLastTagWas(0); + return (BuilderType) this; + } catch (InvalidProtocolBufferException e) { + throw e; + } catch (IOException e) { + throw new RuntimeException( + "Reading from a byte array threw an IOException (should " + + "never happen).", e); + } + } + + @Override + public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return mergeFrom(data, 0, data.length, extensionRegistry); + } + + @Override + public BuilderType mergeFrom( + final byte[] data, + final int off, + final int len, + final ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + try { + final CodedInputStream input = + CodedInputStream.newInstance(data, off, len); + mergeFrom(input, extensionRegistry); + input.checkLastTagWas(0); + return (BuilderType) this; + } catch (InvalidProtocolBufferException e) { + throw e; + } catch (IOException e) { + throw new RuntimeException( + "Reading from a byte array threw an IOException (should " + + "never happen).", e); + } + } + + @Override + public BuilderType mergeFrom(final InputStream input) throws IOException { + final CodedInputStream codedInput = CodedInputStream.newInstance(input); + mergeFrom(codedInput); + codedInput.checkLastTagWas(0); + return (BuilderType) this; + } + + @Override + public BuilderType mergeFrom( + final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { + final CodedInputStream codedInput = CodedInputStream.newInstance(input); + mergeFrom(codedInput, extensionRegistry); + codedInput.checkLastTagWas(0); + return (BuilderType) this; + } + + /** + * An InputStream implementations which reads from some other InputStream + * but is limited to a particular number of bytes. Used by + * mergeDelimitedFrom(). This is intentionally package-private so that + * UnknownFieldSet can share it. + */ + static final class LimitedInputStream extends FilterInputStream { + private int limit; + + LimitedInputStream(InputStream in, int limit) { + super(in); + this.limit = limit; + } + + @Override + public int available() throws IOException { + return Math.min(super.available(), limit); + } + + @Override + public int read() throws IOException { + if (limit <= 0) { + return -1; + } + final int result = super.read(); + if (result >= 0) { + --limit; + } + return result; + } + + @Override + public int read(final byte[] b, final int off, int len) + throws IOException { + if (limit <= 0) { + return -1; + } + len = Math.min(len, limit); + final int result = super.read(b, off, len); + if (result >= 0) { + limit -= result; + } + return result; + } + + @Override + public long skip(final long n) throws IOException { + final long result = super.skip(Math.min(n, limit)); + if (result >= 0) { + limit -= result; + } + return result; + } + } + + @Override + public boolean mergeDelimitedFrom( + final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { + final int firstByte = input.read(); + if (firstByte == -1) { + return false; + } + final int size = CodedInputStream.readRawVarint32(firstByte, input); + final InputStream limitedInput = new LimitedInputStream(input, size); + mergeFrom(limitedInput, extensionRegistry); + return true; + } + + @Override + public boolean mergeDelimitedFrom(final InputStream input) throws IOException { + return mergeDelimitedFrom(input, + ExtensionRegistryLite.getEmptyRegistry()); + } + + @Override + @SuppressWarnings("unchecked") // isInstance takes care of this + public BuilderType mergeFrom(final MessageLite other) { + if (!getDefaultInstanceForType().getClass().isInstance(other)) { + throw new IllegalArgumentException( + "mergeFrom(MessageLite) can only merge messages of the same type."); + } + + return internalMergeFrom((MessageType) other); + } + + protected abstract BuilderType internalMergeFrom(MessageType message); + + /** + * Construct an UninitializedMessageException reporting missing fields in + * the given message. + */ + protected static UninitializedMessageException + newUninitializedMessageException(MessageLite message) { + return new UninitializedMessageException(message); + } + + /** + * Adds the {@code values} to the {@code list}. This is a helper method + * used by generated code. Users should ignore it. + * + * @throws NullPointerException if {@code values} or any of the elements of + * {@code values} is null. When that happens, some elements of + * {@code values} may have already been added to the result {@code list}. + */ + protected static void addAll(final Iterable values, + final Collection list) { + if (values == null) { + throw new NullPointerException(); + } + if (values instanceof LazyStringList) { + // For StringOrByteStringLists, check the underlying elements to avoid + // forcing conversions of ByteStrings to Strings. + checkForNullValues(((LazyStringList) values).getUnderlyingElements()); + list.addAll((Collection) values); + } else if (values instanceof Collection) { + checkForNullValues(values); + list.addAll((Collection) values); + } else { + for (final T value : values) { + if (value == null) { + throw new NullPointerException(); + } + list.add(value); + } + } + } + + private static void checkForNullValues(final Iterable values) { + for (final Object value : values) { + if (value == null) { + throw new NullPointerException(); + } + } + } + } +} diff --git a/java/src/main/java/com/google/protobuf/AbstractParser.java b/java/src/main/java/com/google/protobuf/AbstractParser.java new file mode 100644 index 00000000..66b0ee3b --- /dev/null +++ b/java/src/main/java/com/google/protobuf/AbstractParser.java @@ -0,0 +1,258 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A partial implementation of the {@link Parser} interface which implements + * as many methods of that interface as possible in terms of other methods. + * + * Note: This class implements all the convenience methods in the + * {@link Parser} interface. See {@link Parser} for related javadocs. + * Subclasses need to implement + * {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)} + * + * @author liujisi@google.com (Pherl Liu) + */ +public abstract class AbstractParser + implements Parser { + /** + * Creates an UninitializedMessageException for MessageType. + */ + private UninitializedMessageException + newUninitializedMessageException(MessageType message) { + if (message instanceof AbstractMessageLite) { + return ((AbstractMessageLite) message).newUninitializedMessageException(); + } + return new UninitializedMessageException(message); + } + + /** + * Helper method to check if message is initialized. + * + * @throws InvalidProtocolBufferException if it is not initialized. + * @return The message to check. + */ + private MessageType checkMessageInitialized(MessageType message) + throws InvalidProtocolBufferException { + if (message != null && !message.isInitialized()) { + throw newUninitializedMessageException(message) + .asInvalidProtocolBufferException() + .setUnfinishedMessage(message); + } + return message; + } + + private static final ExtensionRegistryLite EMPTY_REGISTRY + = ExtensionRegistryLite.getEmptyRegistry(); + + @Override + public MessageType parsePartialFrom(CodedInputStream input) + throws InvalidProtocolBufferException { + return parsePartialFrom(input, EMPTY_REGISTRY); + } + + @Override + public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialFrom(input, extensionRegistry)); + } + + @Override + public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException { + return parseFrom(input, EMPTY_REGISTRY); + } + + @Override + public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + MessageType message; + try { + CodedInputStream input = data.newCodedInput(); + message = parsePartialFrom(input, extensionRegistry); + try { + input.checkLastTagWas(0); + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(message); + } + return message; + } catch (InvalidProtocolBufferException e) { + throw e; + } + } + + @Override + public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException { + return parsePartialFrom(data, EMPTY_REGISTRY); + } + + @Override + public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized(parsePartialFrom(data, extensionRegistry)); + } + + @Override + public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException { + return parseFrom(data, EMPTY_REGISTRY); + } + + @Override + public MessageType parsePartialFrom( + byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + try { + CodedInputStream input = CodedInputStream.newInstance(data, off, len); + MessageType message = parsePartialFrom(input, extensionRegistry); + try { + input.checkLastTagWas(0); + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(message); + } + return message; + } catch (InvalidProtocolBufferException e) { + throw e; + } + } + + @Override + public MessageType parsePartialFrom(byte[] data, int off, int len) + throws InvalidProtocolBufferException { + return parsePartialFrom(data, off, len, EMPTY_REGISTRY); + } + + @Override + public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return parsePartialFrom(data, 0, data.length, extensionRegistry); + } + + @Override + public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException { + return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY); + } + + @Override + public MessageType parseFrom( + byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialFrom(data, off, len, extensionRegistry)); + } + + @Override + public MessageType parseFrom(byte[] data, int off, int len) + throws InvalidProtocolBufferException { + return parseFrom(data, off, len, EMPTY_REGISTRY); + } + + @Override + public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return parseFrom(data, 0, data.length, extensionRegistry); + } + + @Override + public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException { + return parseFrom(data, EMPTY_REGISTRY); + } + + @Override + public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + CodedInputStream codedInput = CodedInputStream.newInstance(input); + MessageType message = parsePartialFrom(codedInput, extensionRegistry); + try { + codedInput.checkLastTagWas(0); + } catch (InvalidProtocolBufferException e) { + throw e.setUnfinishedMessage(message); + } + return message; + } + + @Override + public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException { + return parsePartialFrom(input, EMPTY_REGISTRY); + } + + @Override + public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialFrom(input, extensionRegistry)); + } + + @Override + public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException { + return parseFrom(input, EMPTY_REGISTRY); + } + + @Override + public MessageType parsePartialDelimitedFrom( + InputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + int size; + try { + int firstByte = input.read(); + if (firstByte == -1) { + return null; + } + size = CodedInputStream.readRawVarint32(firstByte, input); + } catch (IOException e) { + throw new InvalidProtocolBufferException(e.getMessage()); + } + InputStream limitedInput = new LimitedInputStream(input, size); + return parsePartialFrom(limitedInput, extensionRegistry); + } + + @Override + public MessageType parsePartialDelimitedFrom(InputStream input) + throws InvalidProtocolBufferException { + return parsePartialDelimitedFrom(input, EMPTY_REGISTRY); + } + + @Override + public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) + throws InvalidProtocolBufferException { + return checkMessageInitialized( + parsePartialDelimitedFrom(input, extensionRegistry)); + } + + @Override + public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException { + return parseDelimitedFrom(input, EMPTY_REGISTRY); + } +} diff --git a/java/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/src/main/java/com/google/protobuf/AbstractProtobufList.java new file mode 100644 index 00000000..b17db6e0 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/AbstractProtobufList.java @@ -0,0 +1,180 @@ +// 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. + +package com.google.protobuf; + +import com.google.protobuf.Internal.ProtobufList; + +import java.util.AbstractList; +import java.util.Collection; +import java.util.List; +import java.util.RandomAccess; + +/** + * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate + * methods must check if the list is mutable before proceeding. Subclasses must invoke + * {@link #ensureIsMutable()} manually when overriding those methods. + *

+ * This implementation assumes all subclasses are array based, supporting random access. + */ +abstract class AbstractProtobufList extends AbstractList implements ProtobufList { + + protected static final int DEFAULT_CAPACITY = 10; + + /** + * Whether or not this list is modifiable. + */ + private boolean isMutable; + + /** + * Constructs a mutable list by default. + */ + AbstractProtobufList() { + isMutable = true; + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (!(o instanceof List)) { + return false; + } + // Handle lists that do not support RandomAccess as efficiently as possible by using an iterator + // based approach in our super class. Otherwise our index based approach will avoid those + // allocations. + if (!(o instanceof RandomAccess)) { + return super.equals(o); + } + + List other = (List) o; + final int size = size(); + if (size != other.size()) { + return false; + } + for (int i = 0; i < size; i++) { + if (!get(i).equals(other.get(i))) { + return false; + } + } + return true; + } + + @Override + public int hashCode() { + final int size = size(); + int hashCode = 1; + for (int i = 0; i < size; i++) { + hashCode = (31 * hashCode) + get(i).hashCode(); + } + return hashCode; + } + + @Override + public boolean add(E e) { + ensureIsMutable(); + return super.add(e); + } + + @Override + public void add(int index, E element) { + ensureIsMutable(); + super.add(index, element); + } + + @Override + public boolean addAll(Collection c) { + ensureIsMutable(); + return super.addAll(c); + } + + @Override + public boolean addAll(int index, Collection c) { + ensureIsMutable(); + return super.addAll(index, c); + } + + @Override + public void clear() { + ensureIsMutable(); + super.clear(); + } + + @Override + public boolean isModifiable() { + return isMutable; + } + + @Override + public final void makeImmutable() { + isMutable = false; + } + + @Override + public E remove(int index) { + ensureIsMutable(); + return super.remove(index); + } + + @Override + public boolean remove(Object o) { + ensureIsMutable(); + return super.remove(o); + } + + @Override + public boolean removeAll(Collection c) { + ensureIsMutable(); + return super.removeAll(c); + } + + @Override + public boolean retainAll(Collection c) { + ensureIsMutable(); + return super.retainAll(c); + } + + @Override + public E set(int index, E element) { + ensureIsMutable(); + return super.set(index, element); + } + + /** + * Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are + * responsible for invoking this method on mutate operations. + */ + protected void ensureIsMutable() { + if (!isMutable) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java new file mode 100644 index 00000000..d535efb9 --- /dev/null +++ b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java @@ -0,0 +1,51 @@ +// 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. + +package com.google.protobuf; + +/** + *

Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel} + * is the blocking equivalent to {@link RpcChannel}. + * + * @author kenton@google.com Kenton Varda + * @author cpovirk@google.com Chris Povirk + */ +public interface BlockingRpcChannel { + /** + * Call the given method of the remote service and blocks until it returns. + * {@code callBlockingMethod()} is the blocking equivalent to + * {@link RpcChannel#callMethod}. + */ + Message callBlockingMethod( + Descriptors.MethodDescriptor method, + RpcController controller, + Message request, + Message responsePrototype) throws ServiceException; +} diff --git a/java/src/main/java/com/google/protobuf/BlockingService.java b/java/src/main/java/com/google/protobuf/BlockingService.java new file mode 100644 index 00000000..d01f0b8f --- /dev/null +++ b/java/src/main/java/com/google/protobuf/BlockingService.java @@ -0,0 +1,64 @@ +// 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. + +package com.google.protobuf; + +/** + * Blocking equivalent to {@link Service}. + * + * @author kenton@google.com Kenton Varda + * @author cpovirk@google.com Chris Povirk + */ +public interface BlockingService { + /** + * Equivalent to {@link Service#getDescriptorForType}. + */ + Descriptors.ServiceDescriptor getDescriptorForType(); + + /** + * Equivalent to {@link Service#callMethod}, except that + * {@code callBlockingMethod()} returns the result of the RPC or throws a + * {@link ServiceException} if there is a failure, rather than passing the + * information to a callback. + */ + Message callBlockingMethod(Descriptors.MethodDescriptor method, + RpcController controller, + Message request) throws ServiceException; + + /** + * Equivalent to {@link Service#getRequestPrototype}. + */ + Message getRequestPrototype(Descriptors.MethodDescriptor method); + + /** + * Equivalent to {@link Service#getResponsePrototype}. + */ + Message getResponsePrototype(Descriptors.MethodDescriptor method); +} diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java index d6a2f6fa..668d65ab 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java @@ -264,7 +264,11 @@ class FieldMaskTree { } } } else { - destination.setField(field, source.getField(field)); + if (source.hasField(field) || !options.replacePrimitiveFields()) { + destination.setField(field, source.getField(field)); + } else { + destination.clearField(field); + } } } } diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java index 0b3060a7..96961521 100644 --- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java +++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java @@ -211,14 +211,19 @@ public class FieldMaskUtil { public static FieldMask normalize(FieldMask mask) { return new FieldMaskTree(mask).toFieldMask(); } - + /** - * Creates an union of two FieldMasks. + * Creates a union of two or more FieldMasks. */ - public static FieldMask union(FieldMask mask1, FieldMask mask2) { - return new FieldMaskTree(mask1).mergeFromFieldMask(mask2).toFieldMask(); + public static FieldMask union( + FieldMask firstMask, FieldMask secondMask, FieldMask... otherMasks) { + FieldMaskTree maskTree = new FieldMaskTree(firstMask).mergeFromFieldMask(secondMask); + for (FieldMask mask : otherMasks) { + maskTree.mergeFromFieldMask(mask); + } + return maskTree.toFieldMask(); } - + /** * Calculates the intersection of two FieldMasks. */ @@ -237,6 +242,9 @@ public class FieldMaskUtil { public static final class MergeOptions { private boolean replaceMessageFields = false; private boolean replaceRepeatedFields = false; + // TODO(b/28277137): change the default behavior to always replace primitive fields after + // fixing all failing TAP tests. + private boolean replacePrimitiveFields = false; /** * Whether to replace message fields (i.e., discard existing content in @@ -257,7 +265,23 @@ public class FieldMaskUtil { public boolean replaceRepeatedFields() { return replaceRepeatedFields; } - + + /** + * Whether to replace primitive (non-repeated and non-message) fields in + * destination message fields with the source primitive fields (i.e., if the + * field is set in the source, the value is copied to the + * destination; if the field is unset in the source, the field is cleared + * from the destination) when merging. + * + *

Default behavior is to always set the value of the source primitive + * field to the destination primitive field, and if the source field is + * unset, the default value of the source field is copied to the + * destination. + */ + public boolean replacePrimitiveFields() { + return replacePrimitiveFields; + } + public void setReplaceMessageFields(boolean value) { replaceMessageFields = value; } @@ -265,10 +289,15 @@ public class FieldMaskUtil { public void setReplaceRepeatedFields(boolean value) { replaceRepeatedFields = value; } + + public void setReplacePrimitiveFields(boolean value) { + replacePrimitiveFields = value; + } } - + /** - * Merges fields specified by a FieldMask from one message to another. + * Merges fields specified by a FieldMask from one message to another with the + * specified merge options. */ public static void merge(FieldMask mask, Message source, Message.Builder destination, MergeOptions options) { diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java index 618e0072..3ee0fc6e 100644 --- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskTreeTest.java @@ -237,5 +237,25 @@ public class FieldMaskTreeTest extends TestCase { builder.getPayloadBuilder().setOptionalUint32(2000); new FieldMaskTree().addFieldPath("payload").merge(clearedSource, builder, options); assertEquals(false, builder.hasPayload()); + + // Test merging unset primitive fields. + builder = source.toBuilder(); + builder.getPayloadBuilder().clearOptionalInt32(); + NestedTestAllTypes sourceWithPayloadInt32Unset = builder.build(); + builder = source.toBuilder(); + new FieldMaskTree() + .addFieldPath("payload.optional_int32") + .merge(sourceWithPayloadInt32Unset, builder, options); + assertEquals(true, builder.getPayload().hasOptionalInt32()); + assertEquals(0, builder.getPayload().getOptionalInt32()); + + // Change to clear unset primitive fields. + options.setReplacePrimitiveFields(true); + builder = source.toBuilder(); + new FieldMaskTree() + .addFieldPath("payload.optional_int32") + .merge(sourceWithPayloadInt32Unset, builder, options); + assertEquals(true, builder.hasPayload()); + assertEquals(false, builder.getPayload().hasOptionalInt32()); } } diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java index a312fc33..194f7b9c 100644 --- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java +++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java @@ -152,6 +152,15 @@ public class FieldMaskUtilTest extends TestCase { FieldMask result = FieldMaskUtil.union(mask1, mask2); assertEquals("bar,foo", FieldMaskUtil.toString(result)); } + + public void testUnion_usingVarArgs() throws Exception { + FieldMask mask1 = FieldMaskUtil.fromString("foo"); + FieldMask mask2 = FieldMaskUtil.fromString("foo.bar,bar.quz"); + FieldMask mask3 = FieldMaskUtil.fromString("bar.quz"); + FieldMask mask4 = FieldMaskUtil.fromString("bar"); + FieldMask result = FieldMaskUtil.union(mask1, mask2, mask3, mask4); + assertEquals("bar,foo", FieldMaskUtil.toString(result)); + } public void testIntersection() throws Exception { // Only test a simple case here and expect diff --git a/js/binary/utils.js b/js/binary/utils.js index 875ff955..51405553 100644 --- a/js/binary/utils.js +++ b/js/binary/utils.js @@ -567,6 +567,56 @@ jspb.utils.hash64ArrayToDecimalStrings = function(hashes, signed) { }; +/** + * Converts a signed or unsigned decimal string into its hash string + * representation. + * @param {string} dec + * @return {string} + */ +jspb.utils.decimalStringToHash64 = function(dec) { + goog.asserts.assert(dec.length > 0); + + // Check for minus sign. + var minus = false; + if (dec[0] === '-') { + minus = true; + dec = dec.slice(1); + } + + // Store result as a byte array. + var resultBytes = [0, 0, 0, 0, 0, 0, 0, 0]; + + // Set result to m*result + c. + function muladd(m, c) { + for (var i = 0; i < 8 && (m !== 1 || c > 0); i++) { + var r = m * resultBytes[i] + c; + resultBytes[i] = r & 0xFF; + c = r >>> 8; + } + } + + // Negate the result bits. + function neg() { + for (var i = 0; i < 8; i++) { + resultBytes[i] = (~resultBytes[i]) & 0xFF; + } + } + + // For each decimal digit, set result to 10*result + digit. + for (var i = 0; i < dec.length; i++) { + muladd(10, jspb.utils.DIGITS.indexOf(dec[i])); + } + + // If there's a minus sign, convert into two's complement. + if (minus) { + neg(); + muladd(1, 1); + } + + return String.fromCharCode.apply(null, resultBytes); +}; + + /** * Converts an 8-character hash string into its hexadecimal representation. * @param {string} hash diff --git a/js/binary/utils_test.js b/js/binary/utils_test.js index 518d7597..d27e5ea2 100644 --- a/js/binary/utils_test.js +++ b/js/binary/utils_test.js @@ -197,6 +197,41 @@ describe('binaryUtilsTest', function() { assertEquals('123456789123456789', result[2]); }); + /* + * Going from decimal strings to hash strings should be lossless. + */ + it('testDecimalToHashConversion', function() { + var result; + var convert = jspb.utils.decimalStringToHash64; + + result = convert('0'); + assertEquals(String.fromCharCode.apply(null, + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]), result); + + result = convert('-1'); + assertEquals(String.fromCharCode.apply(null, + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result); + + result = convert('18446744073709551615'); + assertEquals(String.fromCharCode.apply(null, + [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]), result); + + result = convert('9223372036854775808'); + assertEquals(String.fromCharCode.apply(null, + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result); + + result = convert('-9223372036854775808'); + assertEquals(String.fromCharCode.apply(null, + [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80]), result); + + result = convert('123456789123456789'); + assertEquals(String.fromCharCode.apply(null, + [0x15, 0x5F, 0xD0, 0xAC, 0x4B, 0x9B, 0xB6, 0x01]), result); + + result = convert('-123456789123456789'); + assertEquals(String.fromCharCode.apply(null, + [0xEB, 0xA0, 0x2F, 0x53, 0xB4, 0x64, 0x49, 0xFE]), result); + }); /** * Going from hash strings to hex strings should be lossless. diff --git a/objectivec/google/google/protobuf/Any.pbobjc.h b/objectivec/google/google/protobuf/Any.pbobjc.h new file mode 100644 index 00000000..4002a989 --- /dev/null +++ b/objectivec/google/google/protobuf/Any.pbobjc.h @@ -0,0 +1,134 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/any.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBAnyRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBAnyRoot : GPBRootObject +@end + +#pragma mark - GPBAny + +typedef GPB_ENUM(GPBAny_FieldNumber) { + GPBAny_FieldNumber_TypeURL = 1, + GPBAny_FieldNumber_Value = 2, +}; + +/// `Any` contains an arbitrary serialized protocol buffer message along with a +/// URL that describes the type of the serialized message. +/// +/// Protobuf library provides support to pack/unpack Any values in the form +/// of utility functions or additional generated methods of the Any type. +/// +/// Example 1: Pack and unpack a message in C++. +/// +/// Foo foo = ...; +/// Any any; +/// any.PackFrom(foo); +/// ... +/// if (any.UnpackTo(&foo)) { +/// ... +/// } +/// +/// Example 2: Pack and unpack a message in Java. +/// +/// Foo foo = ...; +/// Any any = Any.pack(foo); +/// ... +/// if (any.is(Foo.class)) { +/// foo = any.unpack(Foo.class); +/// } +/// +/// The pack methods provided by protobuf library will by default use +/// 'type.googleapis.com/full.type.name' as the type URL and the unpack +/// methods only use the fully qualified type name after the last '/' +/// in the type URL, for example "foo.bar.com/x/y.z" will yield type +/// name "y.z". +/// +/// +/// JSON +/// ==== +/// The JSON representation of an `Any` value uses the regular +/// representation of the deserialized, embedded message, with an +/// additional field `\@type` which contains the type URL. Example: +/// +/// package google.profile; +/// message Person { +/// string first_name = 1; +/// string last_name = 2; +/// } +/// +/// { +/// "\@type": "type.googleapis.com/google.profile.Person", +/// "firstName": , +/// "lastName": +/// } +/// +/// If the embedded message type is well-known and has a custom JSON +/// representation, that representation will be embedded adding a field +/// `value` which holds the custom JSON in addition to the `\@type` +/// field. Example (for message [google.protobuf.Duration][]): +/// +/// { +/// "\@type": "type.googleapis.com/google.protobuf.Duration", +/// "value": "1.212s" +/// } +@interface GPBAny : GPBMessage + +/// A URL/resource name whose content describes the type of the +/// serialized protocol buffer message. +/// +/// For URLs which use the schema `http`, `https`, or no schema, the +/// following restrictions and interpretations apply: +/// +/// * If no schema is provided, `https` is assumed. +/// * The last segment of the URL's path must represent the fully +/// qualified name of the type (as in `path/google.protobuf.Duration`). +/// The name should be in a canonical form (e.g., leading "." is +/// not accepted). +/// * An HTTP GET on the URL must yield a [google.protobuf.Type][] +/// value in binary format, or produce an error. +/// * Applications are allowed to cache lookup results based on the +/// URL, or have them precompiled into a binary to avoid any +/// lookup. Therefore, binary compatibility needs to be preserved +/// on changes to types. (Use versioned type names to manage +/// breaking changes.) +/// +/// Schemas other than `http`, `https` (or the empty schema) might be +/// used with implementation specific semantics. +@property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL; + +/// Must be a valid serialized protocol buffer of the above specified type. +@property(nonatomic, readwrite, copy, null_resettable) NSData *value; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Any.pbobjc.m b/objectivec/google/google/protobuf/Any.pbobjc.m new file mode 100644 index 00000000..6a1bf894 --- /dev/null +++ b/objectivec/google/google/protobuf/Any.pbobjc.m @@ -0,0 +1,93 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/any.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Any.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBAnyRoot + +@implementation GPBAnyRoot + +@end + +#pragma mark - GPBAnyRoot_FileDescriptor + +static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBAny + +@implementation GPBAny + +@dynamic typeURL; +@dynamic value; + +typedef struct GPBAny__storage_ { + uint32_t _has_storage_[1]; + NSString *typeURL; + NSData *value; +} GPBAny__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "typeURL", + .dataTypeSpecific.className = NULL, + .number = GPBAny_FieldNumber_TypeURL, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBAny__storage_, typeURL), + .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, + .dataType = GPBDataTypeString, + }, + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBAny_FieldNumber_Value, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBAny__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBAny class] + rootClass:[GPBAnyRoot class] + file:GPBAnyRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBAny__storage_) + flags:0]; +#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + static const char *extraTextFormatInfo = + "\001\001\004\241!!\000"; + [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; +#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Api.pbobjc.h b/objectivec/google/google/protobuf/Api.pbobjc.h new file mode 100644 index 00000000..d66df629 --- /dev/null +++ b/objectivec/google/google/protobuf/Api.pbobjc.h @@ -0,0 +1,262 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/api.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +@class GPBMethod; +@class GPBMixin; +@class GPBOption; +@class GPBSourceContext; +GPB_ENUM_FWD_DECLARE(GPBSyntax); + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBApiRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBApiRoot : GPBRootObject +@end + +#pragma mark - GPBApi + +typedef GPB_ENUM(GPBApi_FieldNumber) { + GPBApi_FieldNumber_Name = 1, + GPBApi_FieldNumber_MethodsArray = 2, + GPBApi_FieldNumber_OptionsArray = 3, + GPBApi_FieldNumber_Version = 4, + GPBApi_FieldNumber_SourceContext = 5, + GPBApi_FieldNumber_MixinsArray = 6, + GPBApi_FieldNumber_Syntax = 7, +}; + +/// Api is a light-weight descriptor for a protocol buffer service. +@interface GPBApi : GPBMessage + +/// The fully qualified name of this api, including package name +/// followed by the api's simple name. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// The methods of this api, in unspecified order. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *methodsArray; +/// The number of items in @c methodsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger methodsArray_Count; + +/// Any metadata attached to the API. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; +/// The number of items in @c optionsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger optionsArray_Count; + +/// A version string for this api. If specified, must have the form +/// `major-version.minor-version`, as in `1.10`. If the minor version +/// is omitted, it defaults to zero. If the entire version field is +/// empty, the major version is derived from the package name, as +/// outlined below. If the field is not empty, the version in the +/// package name will be verified to be consistent with what is +/// provided here. +/// +/// The versioning schema uses [semantic +/// versioning](http://semver.org) where the major version number +/// indicates a breaking change and the minor version an additive, +/// non-breaking change. Both version numbers are signals to users +/// what to expect from different versions, and should be carefully +/// chosen based on the product plan. +/// +/// The major version is also reflected in the package name of the +/// API, which must end in `v`, as in +/// `google.feature.v1`. For major versions 0 and 1, the suffix can +/// be omitted. Zero major versions must only be used for +/// experimental, none-GA apis. +@property(nonatomic, readwrite, copy, null_resettable) NSString *version; + +/// Source context for the protocol buffer service represented by this +/// message. +@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext; +/// Test to see if @c sourceContext has been set. +@property(nonatomic, readwrite) BOOL hasSourceContext; + +/// Included APIs. See [Mixin][]. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *mixinsArray; +/// The number of items in @c mixinsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger mixinsArray_Count; + +/// The source syntax of the service. +@property(nonatomic, readwrite) enum GPBSyntax syntax; + +@end + +/// Fetches the raw value of a @c GPBApi's @c syntax property, even +/// if the value was not defined by the enum at the time the code was generated. +int32_t GPBApi_Syntax_RawValue(GPBApi *message); +/// Sets the raw value of an @c GPBApi's @c syntax property, allowing +/// it to be set to a value that was not defined by the enum at the time the code +/// was generated. +void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value); + +#pragma mark - GPBMethod + +typedef GPB_ENUM(GPBMethod_FieldNumber) { + GPBMethod_FieldNumber_Name = 1, + GPBMethod_FieldNumber_RequestTypeURL = 2, + GPBMethod_FieldNumber_RequestStreaming = 3, + GPBMethod_FieldNumber_ResponseTypeURL = 4, + GPBMethod_FieldNumber_ResponseStreaming = 5, + GPBMethod_FieldNumber_OptionsArray = 6, + GPBMethod_FieldNumber_Syntax = 7, +}; + +/// Method represents a method of an api. +@interface GPBMethod : GPBMessage + +/// The simple name of this method. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// A URL of the input message type. +@property(nonatomic, readwrite, copy, null_resettable) NSString *requestTypeURL; + +/// If true, the request is streamed. +@property(nonatomic, readwrite) BOOL requestStreaming; + +/// The URL of the output message type. +@property(nonatomic, readwrite, copy, null_resettable) NSString *responseTypeURL; + +/// If true, the response is streamed. +@property(nonatomic, readwrite) BOOL responseStreaming; + +/// Any metadata attached to the method. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; +/// The number of items in @c optionsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger optionsArray_Count; + +/// The source syntax of this method. +@property(nonatomic, readwrite) enum GPBSyntax syntax; + +@end + +/// Fetches the raw value of a @c GPBMethod's @c syntax property, even +/// if the value was not defined by the enum at the time the code was generated. +int32_t GPBMethod_Syntax_RawValue(GPBMethod *message); +/// Sets the raw value of an @c GPBMethod's @c syntax property, allowing +/// it to be set to a value that was not defined by the enum at the time the code +/// was generated. +void SetGPBMethod_Syntax_RawValue(GPBMethod *message, int32_t value); + +#pragma mark - GPBMixin + +typedef GPB_ENUM(GPBMixin_FieldNumber) { + GPBMixin_FieldNumber_Name = 1, + GPBMixin_FieldNumber_Root = 2, +}; + +/// Declares an API to be included in this API. The including API must +/// redeclare all the methods from the included API, but documentation +/// and options are inherited as follows: +/// +/// - If after comment and whitespace stripping, the documentation +/// string of the redeclared method is empty, it will be inherited +/// from the original method. +/// +/// - Each annotation belonging to the service config (http, +/// visibility) which is not set in the redeclared method will be +/// inherited. +/// +/// - If an http annotation is inherited, the path pattern will be +/// modified as follows. Any version prefix will be replaced by the +/// version of the including API plus the [root][] path if specified. +/// +/// Example of a simple mixin: +/// +/// package google.acl.v1; +/// service AccessControl { +/// // Get the underlying ACL object. +/// rpc GetAcl(GetAclRequest) returns (Acl) { +/// option (google.api.http).get = "/v1/{resource=**}:getAcl"; +/// } +/// } +/// +/// package google.storage.v2; +/// service Storage { +/// rpc GetAcl(GetAclRequest) returns (Acl); +/// +/// // Get a data record. +/// rpc GetData(GetDataRequest) returns (Data) { +/// option (google.api.http).get = "/v2/{resource=**}"; +/// } +/// } +/// +/// Example of a mixin configuration: +/// +/// apis: +/// - name: google.storage.v2.Storage +/// mixins: +/// - name: google.acl.v1.AccessControl +/// +/// The mixin construct implies that all methods in `AccessControl` are +/// also declared with same name and request/response types in +/// `Storage`. A documentation generator or annotation processor will +/// see the effective `Storage.GetAcl` method after inherting +/// documentation and annotations as follows: +/// +/// service Storage { +/// // Get the underlying ACL object. +/// rpc GetAcl(GetAclRequest) returns (Acl) { +/// option (google.api.http).get = "/v2/{resource=**}:getAcl"; +/// } +/// ... +/// } +/// +/// Note how the version in the path pattern changed from `v1` to `v2`. +/// +/// If the `root` field in the mixin is specified, it should be a +/// relative path under which inherited HTTP paths are placed. Example: +/// +/// apis: +/// - name: google.storage.v2.Storage +/// mixins: +/// - name: google.acl.v1.AccessControl +/// root: acls +/// +/// This implies the following inherited HTTP annotation: +/// +/// service Storage { +/// // Get the underlying ACL object. +/// rpc GetAcl(GetAclRequest) returns (Acl) { +/// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; +/// } +/// ... +/// } +@interface GPBMixin : GPBMessage + +/// The fully qualified name of the API which is included. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// If non-empty specifies a path under which inherited HTTP paths +/// are rooted. +@property(nonatomic, readwrite, copy, null_resettable) NSString *root; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Api.pbobjc.m b/objectivec/google/google/protobuf/Api.pbobjc.m new file mode 100644 index 00000000..45a06e60 --- /dev/null +++ b/objectivec/google/google/protobuf/Api.pbobjc.m @@ -0,0 +1,348 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/api.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Api.pbobjc.h" +#import "google/protobuf/SourceContext.pbobjc.h" +#import "google/protobuf/Type.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBApiRoot + +@implementation GPBApiRoot + ++ (GPBExtensionRegistry*)extensionRegistry { + // This is called by +initialize so there is no need to worry + // about thread safety and initialization of registry. + static GPBExtensionRegistry* registry = nil; + if (!registry) { + GPBDebugCheckRuntimeVersion(); + registry = [[GPBExtensionRegistry alloc] init]; + [registry addExtensions:[GPBSourceContextRoot extensionRegistry]]; + [registry addExtensions:[GPBTypeRoot extensionRegistry]]; + } + return registry; +} + +@end + +#pragma mark - GPBApiRoot_FileDescriptor + +static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBApi + +@implementation GPBApi + +@dynamic name; +@dynamic methodsArray, methodsArray_Count; +@dynamic optionsArray, optionsArray_Count; +@dynamic version; +@dynamic hasSourceContext, sourceContext; +@dynamic mixinsArray, mixinsArray_Count; +@dynamic syntax; + +typedef struct GPBApi__storage_ { + uint32_t _has_storage_[1]; + GPBSyntax syntax; + NSString *name; + NSMutableArray *methodsArray; + NSMutableArray *optionsArray; + NSString *version; + GPBSourceContext *sourceContext; + NSMutableArray *mixinsArray; +} GPBApi__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBApi_FieldNumber_Name, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBApi__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "methodsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBMethod), + .number = GPBApi_FieldNumber_MethodsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBApi__storage_, methodsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .number = GPBApi_FieldNumber_OptionsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBApi__storage_, optionsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "version", + .dataTypeSpecific.className = NULL, + .number = GPBApi_FieldNumber_Version, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBApi__storage_, version), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "sourceContext", + .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), + .number = GPBApi_FieldNumber_SourceContext, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBApi__storage_, sourceContext), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "mixinsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBMixin), + .number = GPBApi_FieldNumber_MixinsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBApi__storage_, mixinsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, + .number = GPBApi_FieldNumber_Syntax, + .hasIndex = 3, + .offset = (uint32_t)offsetof(GPBApi__storage_, syntax), + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .dataType = GPBDataTypeEnum, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBApi class] + rootClass:[GPBApiRoot class] + file:GPBApiRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBApi__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +int32_t GPBApi_Syntax_RawValue(GPBApi *message) { + GPBDescriptor *descriptor = [GPBApi descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBApi_FieldNumber_Syntax]; + return GPBGetMessageInt32Field(message, field); +} + +void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value) { + GPBDescriptor *descriptor = [GPBApi descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBApi_FieldNumber_Syntax]; + GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); +} + +#pragma mark - GPBMethod + +@implementation GPBMethod + +@dynamic name; +@dynamic requestTypeURL; +@dynamic requestStreaming; +@dynamic responseTypeURL; +@dynamic responseStreaming; +@dynamic optionsArray, optionsArray_Count; +@dynamic syntax; + +typedef struct GPBMethod__storage_ { + uint32_t _has_storage_[1]; + GPBSyntax syntax; + NSString *name; + NSString *requestTypeURL; + NSString *responseTypeURL; + NSMutableArray *optionsArray; +} GPBMethod__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBMethod_FieldNumber_Name, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBMethod__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "requestTypeURL", + .dataTypeSpecific.className = NULL, + .number = GPBMethod_FieldNumber_RequestTypeURL, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBMethod__storage_, requestTypeURL), + .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, + .dataType = GPBDataTypeString, + }, + { + .name = "requestStreaming", + .dataTypeSpecific.className = NULL, + .number = GPBMethod_FieldNumber_RequestStreaming, + .hasIndex = 2, + .offset = 3, // Stored in _has_storage_ to save space. + .flags = GPBFieldOptional, + .dataType = GPBDataTypeBool, + }, + { + .name = "responseTypeURL", + .dataTypeSpecific.className = NULL, + .number = GPBMethod_FieldNumber_ResponseTypeURL, + .hasIndex = 4, + .offset = (uint32_t)offsetof(GPBMethod__storage_, responseTypeURL), + .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, + .dataType = GPBDataTypeString, + }, + { + .name = "responseStreaming", + .dataTypeSpecific.className = NULL, + .number = GPBMethod_FieldNumber_ResponseStreaming, + .hasIndex = 5, + .offset = 6, // Stored in _has_storage_ to save space. + .flags = GPBFieldOptional, + .dataType = GPBDataTypeBool, + }, + { + .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .number = GPBMethod_FieldNumber_OptionsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBMethod__storage_, optionsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, + .number = GPBMethod_FieldNumber_Syntax, + .hasIndex = 7, + .offset = (uint32_t)offsetof(GPBMethod__storage_, syntax), + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .dataType = GPBDataTypeEnum, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBMethod class] + rootClass:[GPBApiRoot class] + file:GPBApiRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBMethod__storage_) + flags:0]; +#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + static const char *extraTextFormatInfo = + "\002\002\007\244\241!!\000\004\010\244\241!!\000"; + [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; +#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +int32_t GPBMethod_Syntax_RawValue(GPBMethod *message) { + GPBDescriptor *descriptor = [GPBMethod descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBMethod_FieldNumber_Syntax]; + return GPBGetMessageInt32Field(message, field); +} + +void SetGPBMethod_Syntax_RawValue(GPBMethod *message, int32_t value) { + GPBDescriptor *descriptor = [GPBMethod descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBMethod_FieldNumber_Syntax]; + GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); +} + +#pragma mark - GPBMixin + +@implementation GPBMixin + +@dynamic name; +@dynamic root; + +typedef struct GPBMixin__storage_ { + uint32_t _has_storage_[1]; + NSString *name; + NSString *root; +} GPBMixin__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBMixin_FieldNumber_Name, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBMixin__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "root", + .dataTypeSpecific.className = NULL, + .number = GPBMixin_FieldNumber_Root, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBMixin__storage_, root), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBMixin class] + rootClass:[GPBApiRoot class] + file:GPBApiRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBMixin__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Duration.pbobjc.h b/objectivec/google/google/protobuf/Duration.pbobjc.h new file mode 100644 index 00000000..29888d6c --- /dev/null +++ b/objectivec/google/google/protobuf/Duration.pbobjc.h @@ -0,0 +1,101 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/duration.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBDurationRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBDurationRoot : GPBRootObject +@end + +#pragma mark - GPBDuration + +typedef GPB_ENUM(GPBDuration_FieldNumber) { + GPBDuration_FieldNumber_Seconds = 1, + GPBDuration_FieldNumber_Nanos = 2, +}; + +/// A Duration represents a signed, fixed-length span of time represented +/// as a count of seconds and fractions of seconds at nanosecond +/// resolution. It is independent of any calendar and concepts like "day" +/// or "month". It is related to Timestamp in that the difference between +/// two Timestamp values is a Duration and it can be added or subtracted +/// from a Timestamp. Range is approximately +-10,000 years. +/// +/// Example 1: Compute Duration from two Timestamps in pseudo code. +/// +/// Timestamp start = ...; +/// Timestamp end = ...; +/// Duration duration = ...; +/// +/// duration.seconds = end.seconds - start.seconds; +/// duration.nanos = end.nanos - start.nanos; +/// +/// if (duration.seconds < 0 && duration.nanos > 0) { +/// duration.seconds += 1; +/// duration.nanos -= 1000000000; +/// } else if (durations.seconds > 0 && duration.nanos < 0) { +/// duration.seconds -= 1; +/// duration.nanos += 1000000000; +/// } +/// +/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. +/// +/// Timestamp start = ...; +/// Duration duration = ...; +/// Timestamp end = ...; +/// +/// end.seconds = start.seconds + duration.seconds; +/// end.nanos = start.nanos + duration.nanos; +/// +/// if (end.nanos < 0) { +/// end.seconds -= 1; +/// end.nanos += 1000000000; +/// } else if (end.nanos >= 1000000000) { +/// end.seconds += 1; +/// end.nanos -= 1000000000; +/// } +@interface GPBDuration : GPBMessage + +/// Signed seconds of the span of time. Must be from -315,576,000,000 +/// to +315,576,000,000 inclusive. +@property(nonatomic, readwrite) int64_t seconds; + +/// Signed fractions of a second at nanosecond resolution of the span +/// of time. Durations less than one second are represented with a 0 +/// `seconds` field and a positive or negative `nanos` field. For durations +/// of one second or more, a non-zero value for the `nanos` field must be +/// of the same sign as the `seconds` field. Must be from -999,999,999 +/// to +999,999,999 inclusive. +@property(nonatomic, readwrite) int32_t nanos; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Duration.pbobjc.m b/objectivec/google/google/protobuf/Duration.pbobjc.m new file mode 100644 index 00000000..7dd6b64a --- /dev/null +++ b/objectivec/google/google/protobuf/Duration.pbobjc.m @@ -0,0 +1,88 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/duration.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Duration.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBDurationRoot + +@implementation GPBDurationRoot + +@end + +#pragma mark - GPBDurationRoot_FileDescriptor + +static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBDuration + +@implementation GPBDuration + +@dynamic seconds; +@dynamic nanos; + +typedef struct GPBDuration__storage_ { + uint32_t _has_storage_[1]; + int32_t nanos; + int64_t seconds; +} GPBDuration__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "seconds", + .dataTypeSpecific.className = NULL, + .number = GPBDuration_FieldNumber_Seconds, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBDuration__storage_, seconds), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt64, + }, + { + .name = "nanos", + .dataTypeSpecific.className = NULL, + .number = GPBDuration_FieldNumber_Nanos, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBDuration__storage_, nanos), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt32, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBDuration class] + rootClass:[GPBDurationRoot class] + file:GPBDurationRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBDuration__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Empty.pbobjc.h b/objectivec/google/google/protobuf/Empty.pbobjc.h new file mode 100644 index 00000000..f33db017 --- /dev/null +++ b/objectivec/google/google/protobuf/Empty.pbobjc.h @@ -0,0 +1,53 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/empty.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBEmptyRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBEmptyRoot : GPBRootObject +@end + +#pragma mark - GPBEmpty + +/// A generic empty message that you can re-use to avoid defining duplicated +/// empty messages in your APIs. A typical example is to use it as the request +/// or the response type of an API method. For instance: +/// +/// service Foo { +/// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); +/// } +/// +/// The JSON representation for `Empty` is empty JSON object `{}`. +@interface GPBEmpty : GPBMessage + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Empty.pbobjc.m b/objectivec/google/google/protobuf/Empty.pbobjc.m new file mode 100644 index 00000000..88753aaf --- /dev/null +++ b/objectivec/google/google/protobuf/Empty.pbobjc.m @@ -0,0 +1,64 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/empty.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Empty.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBEmptyRoot + +@implementation GPBEmptyRoot + +@end + +#pragma mark - GPBEmptyRoot_FileDescriptor + +static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBEmpty + +@implementation GPBEmpty + + +typedef struct GPBEmpty__storage_ { + uint32_t _has_storage_[1]; +} GPBEmpty__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBEmpty class] + rootClass:[GPBEmptyRoot class] + file:GPBEmptyRoot_FileDescriptor() + fields:NULL + fieldCount:0 + storageSize:sizeof(GPBEmpty__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/google/protobuf/FieldMask.pbobjc.h new file mode 100644 index 00000000..73cbd8a5 --- /dev/null +++ b/objectivec/google/google/protobuf/FieldMask.pbobjc.h @@ -0,0 +1,202 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/field_mask.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBFieldMaskRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBFieldMaskRoot : GPBRootObject +@end + +#pragma mark - GPBFieldMask + +typedef GPB_ENUM(GPBFieldMask_FieldNumber) { + GPBFieldMask_FieldNumber_PathsArray = 1, +}; + +/// `FieldMask` represents a set of symbolic field paths, for example: +/// +/// paths: "f.a" +/// paths: "f.b.d" +/// +/// Here `f` represents a field in some root message, `a` and `b` +/// fields in the message found in `f`, and `d` a field found in the +/// message in `f.b`. +/// +/// Field masks are used to specify a subset of fields that should be +/// returned by a get operation or modified by an update operation. +/// Field masks also have a custom JSON encoding (see below). +/// +/// # Field Masks in Projections +/// +/// When used in the context of a projection, a response message or +/// sub-message is filtered by the API to only contain those fields as +/// specified in the mask. For example, if the mask in the previous +/// example is applied to a response message as follows: +/// +/// f { +/// a : 22 +/// b { +/// d : 1 +/// x : 2 +/// } +/// y : 13 +/// } +/// z: 8 +/// +/// The result will not contain specific values for fields x,y and z +/// (their value will be set to the default, and omitted in proto text +/// output): +/// +/// +/// f { +/// a : 22 +/// b { +/// d : 1 +/// } +/// } +/// +/// A repeated field is not allowed except at the last position of a +/// field mask. +/// +/// If a FieldMask object is not present in a get operation, the +/// operation applies to all fields (as if a FieldMask of all fields +/// had been specified). +/// +/// Note that a field mask does not necessarily apply to the +/// top-level response message. In case of a REST get operation, the +/// field mask applies directly to the response, but in case of a REST +/// list operation, the mask instead applies to each individual message +/// in the returned resource list. In case of a REST custom method, +/// other definitions may be used. Where the mask applies will be +/// clearly documented together with its declaration in the API. In +/// any case, the effect on the returned resource/resources is required +/// behavior for APIs. +/// +/// # Field Masks in Update Operations +/// +/// A field mask in update operations specifies which fields of the +/// targeted resource are going to be updated. The API is required +/// to only change the values of the fields as specified in the mask +/// and leave the others untouched. If a resource is passed in to +/// describe the updated values, the API ignores the values of all +/// fields not covered by the mask. +/// +/// In order to reset a field's value to the default, the field must +/// be in the mask and set to the default value in the provided resource. +/// Hence, in order to reset all fields of a resource, provide a default +/// instance of the resource and set all fields in the mask, or do +/// not provide a mask as described below. +/// +/// If a field mask is not present on update, the operation applies to +/// all fields (as if a field mask of all fields has been specified). +/// Note that in the presence of schema evolution, this may mean that +/// fields the client does not know and has therefore not filled into +/// the request will be reset to their default. If this is unwanted +/// behavior, a specific service may require a client to always specify +/// a field mask, producing an error if not. +/// +/// As with get operations, the location of the resource which +/// describes the updated values in the request message depends on the +/// operation kind. In any case, the effect of the field mask is +/// required to be honored by the API. +/// +/// ## Considerations for HTTP REST +/// +/// The HTTP kind of an update operation which uses a field mask must +/// be set to PATCH instead of PUT in order to satisfy HTTP semantics +/// (PUT must only be used for full updates). +/// +/// # JSON Encoding of Field Masks +/// +/// In JSON, a field mask is encoded as a single string where paths are +/// separated by a comma. Fields name in each path are converted +/// to/from lower-camel naming conventions. +/// +/// As an example, consider the following message declarations: +/// +/// message Profile { +/// User user = 1; +/// Photo photo = 2; +/// } +/// message User { +/// string display_name = 1; +/// string address = 2; +/// } +/// +/// In proto a field mask for `Profile` may look as such: +/// +/// mask { +/// paths: "user.display_name" +/// paths: "photo" +/// } +/// +/// In JSON, the same mask is represented as below: +/// +/// { +/// mask: "user.displayName,photo" +/// } +/// +/// # Field Masks and Oneof Fields +/// +/// Field masks treat fields in oneofs just as regular fields. Consider the +/// following message: +/// +/// message SampleMessage { +/// oneof test_oneof { +/// string name = 4; +/// SubMessage sub_message = 9; +/// } +/// } +/// +/// The field mask can be: +/// +/// mask { +/// paths: "name" +/// } +/// +/// Or: +/// +/// mask { +/// paths: "sub_message" +/// } +/// +/// Note that oneof type names ("test_oneof" in this case) cannot be used in +/// paths. +@interface GPBFieldMask : GPBMessage + +/// The set of field mask paths. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *pathsArray; +/// The number of items in @c pathsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger pathsArray_Count; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/google/protobuf/FieldMask.pbobjc.m new file mode 100644 index 00000000..8c241afc --- /dev/null +++ b/objectivec/google/google/protobuf/FieldMask.pbobjc.m @@ -0,0 +1,77 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/field_mask.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/FieldMask.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBFieldMaskRoot + +@implementation GPBFieldMaskRoot + +@end + +#pragma mark - GPBFieldMaskRoot_FileDescriptor + +static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBFieldMask + +@implementation GPBFieldMask + +@dynamic pathsArray, pathsArray_Count; + +typedef struct GPBFieldMask__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *pathsArray; +} GPBFieldMask__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "pathsArray", + .dataTypeSpecific.className = NULL, + .number = GPBFieldMask_FieldNumber_PathsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBFieldMask__storage_, pathsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeString, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBFieldMask class] + rootClass:[GPBFieldMaskRoot class] + file:GPBFieldMaskRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBFieldMask__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/google/protobuf/SourceContext.pbobjc.h new file mode 100644 index 00000000..8775348e --- /dev/null +++ b/objectivec/google/google/protobuf/SourceContext.pbobjc.h @@ -0,0 +1,54 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/source_context.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBSourceContextRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBSourceContextRoot : GPBRootObject +@end + +#pragma mark - GPBSourceContext + +typedef GPB_ENUM(GPBSourceContext_FieldNumber) { + GPBSourceContext_FieldNumber_FileName = 1, +}; + +/// `SourceContext` represents information about the source of a +/// protobuf element, like the file in which it is defined. +@interface GPBSourceContext : GPBMessage + +/// The path-qualified name of the .proto file that contained the associated +/// protobuf element. For example: `"google/protobuf/source.proto"`. +@property(nonatomic, readwrite, copy, null_resettable) NSString *fileName; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/google/protobuf/SourceContext.pbobjc.m new file mode 100644 index 00000000..95007126 --- /dev/null +++ b/objectivec/google/google/protobuf/SourceContext.pbobjc.m @@ -0,0 +1,77 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/source_context.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/SourceContext.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBSourceContextRoot + +@implementation GPBSourceContextRoot + +@end + +#pragma mark - GPBSourceContextRoot_FileDescriptor + +static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBSourceContext + +@implementation GPBSourceContext + +@dynamic fileName; + +typedef struct GPBSourceContext__storage_ { + uint32_t _has_storage_[1]; + NSString *fileName; +} GPBSourceContext__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "fileName", + .dataTypeSpecific.className = NULL, + .number = GPBSourceContext_FieldNumber_FileName, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBSourceContext__storage_, fileName), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBSourceContext class] + rootClass:[GPBSourceContextRoot class] + file:GPBSourceContextRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBSourceContext__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Struct.pbobjc.h b/objectivec/google/google/protobuf/Struct.pbobjc.h new file mode 100644 index 00000000..3924b4b7 --- /dev/null +++ b/objectivec/google/google/protobuf/Struct.pbobjc.h @@ -0,0 +1,167 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/struct.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +@class GPBListValue; +@class GPBStruct; +@class GPBValue; + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - Enum GPBNullValue + +/// `NullValue` is a singleton enumeration to represent the null value for the +/// `Value` type union. +/// +/// The JSON representation for `NullValue` is JSON `null`. +typedef GPB_ENUM(GPBNullValue) { + /// Value used if any message's field encounters a value that is not defined + /// by this enum. The message will also have C functions to get/set the rawValue + /// of the field. + GPBNullValue_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, + /// Null value. + GPBNullValue_NullValue = 0, +}; + +GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void); + +/// Checks to see if the given value is defined by the enum or was not known at +/// the time this source was generated. +BOOL GPBNullValue_IsValidValue(int32_t value); + +#pragma mark - GPBStructRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBStructRoot : GPBRootObject +@end + +#pragma mark - GPBStruct + +typedef GPB_ENUM(GPBStruct_FieldNumber) { + GPBStruct_FieldNumber_Fields = 1, +}; + +/// `Struct` represents a structured data value, consisting of fields +/// which map to dynamically typed values. In some languages, `Struct` +/// might be supported by a native representation. For example, in +/// scripting languages like JS a struct is represented as an +/// object. The details of that representation are described together +/// with the proto support for the language. +/// +/// The JSON representation for `Struct` is JSON object. +@interface GPBStruct : GPBMessage + +/// Unordered map of dynamically typed values. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *fields; +/// The number of items in @c fields without causing the array to be created. +@property(nonatomic, readonly) NSUInteger fields_Count; + +@end + +#pragma mark - GPBValue + +typedef GPB_ENUM(GPBValue_FieldNumber) { + GPBValue_FieldNumber_NullValue = 1, + GPBValue_FieldNumber_NumberValue = 2, + GPBValue_FieldNumber_StringValue = 3, + GPBValue_FieldNumber_BoolValue = 4, + GPBValue_FieldNumber_StructValue = 5, + GPBValue_FieldNumber_ListValue = 6, +}; + +typedef GPB_ENUM(GPBValue_Kind_OneOfCase) { + GPBValue_Kind_OneOfCase_GPBUnsetOneOfCase = 0, + GPBValue_Kind_OneOfCase_NullValue = 1, + GPBValue_Kind_OneOfCase_NumberValue = 2, + GPBValue_Kind_OneOfCase_StringValue = 3, + GPBValue_Kind_OneOfCase_BoolValue = 4, + GPBValue_Kind_OneOfCase_StructValue = 5, + GPBValue_Kind_OneOfCase_ListValue = 6, +}; + +/// `Value` represents a dynamically typed value which can be either +/// null, a number, a string, a boolean, a recursive struct value, or a +/// list of values. A producer of value is expected to set one of that +/// variants, absence of any variant indicates an error. +/// +/// The JSON representation for `Value` is JSON value. +@interface GPBValue : GPBMessage + +/// The kind of value. +@property(nonatomic, readonly) GPBValue_Kind_OneOfCase kindOneOfCase; + +/// Represents a null value. +@property(nonatomic, readwrite) GPBNullValue nullValue; + +/// Represents a double value. +@property(nonatomic, readwrite) double numberValue; + +/// Represents a string value. +@property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue; + +/// Represents a boolean value. +@property(nonatomic, readwrite) BOOL boolValue; + +/// Represents a structured value. +@property(nonatomic, readwrite, strong, null_resettable) GPBStruct *structValue; + +/// Represents a repeated `Value`. +@property(nonatomic, readwrite, strong, null_resettable) GPBListValue *listValue; + +@end + +/// Fetches the raw value of a @c GPBValue's @c nullValue property, even +/// if the value was not defined by the enum at the time the code was generated. +int32_t GPBValue_NullValue_RawValue(GPBValue *message); +/// Sets the raw value of an @c GPBValue's @c nullValue property, allowing +/// it to be set to a value that was not defined by the enum at the time the code +/// was generated. +void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value); + +/// Clears whatever value was set for the oneof 'kind'. +void GPBValue_ClearKindOneOfCase(GPBValue *message); + +#pragma mark - GPBListValue + +typedef GPB_ENUM(GPBListValue_FieldNumber) { + GPBListValue_FieldNumber_ValuesArray = 1, +}; + +/// `ListValue` is a wrapper around a repeated field of values. +/// +/// The JSON representation for `ListValue` is JSON array. +@interface GPBListValue : GPBMessage + +/// Repeated field of dynamically typed values. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valuesArray; +/// The number of items in @c valuesArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger valuesArray_Count; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Struct.pbobjc.m b/objectivec/google/google/protobuf/Struct.pbobjc.m new file mode 100644 index 00000000..60940027 --- /dev/null +++ b/objectivec/google/google/protobuf/Struct.pbobjc.m @@ -0,0 +1,273 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/struct.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Struct.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBStructRoot + +@implementation GPBStructRoot + +@end + +#pragma mark - GPBStructRoot_FileDescriptor + +static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - Enum GPBNullValue + +GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static const char *valueNames = + "NullValue\000"; + static const int32_t values[] = { + GPBNullValue_NullValue, + }; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBNullValue) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBNullValue_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } + } + return descriptor; +} + +BOOL GPBNullValue_IsValidValue(int32_t value__) { + switch (value__) { + case GPBNullValue_NullValue: + return YES; + default: + return NO; + } +} + +#pragma mark - GPBStruct + +@implementation GPBStruct + +@dynamic fields, fields_Count; + +typedef struct GPBStruct__storage_ { + uint32_t _has_storage_[1]; + NSMutableDictionary *fields; +} GPBStruct__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "fields", + .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), + .number = GPBStruct_FieldNumber_Fields, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBStruct__storage_, fields), + .flags = GPBFieldMapKeyString, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBStruct class] + rootClass:[GPBStructRoot class] + file:GPBStructRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBStruct__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBValue + +@implementation GPBValue + +@dynamic kindOneOfCase; +@dynamic nullValue; +@dynamic numberValue; +@dynamic stringValue; +@dynamic boolValue; +@dynamic structValue; +@dynamic listValue; + +typedef struct GPBValue__storage_ { + uint32_t _has_storage_[2]; + GPBNullValue nullValue; + NSString *stringValue; + GPBStruct *structValue; + GPBListValue *listValue; + double numberValue; +} GPBValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "nullValue", + .dataTypeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor, + .number = GPBValue_FieldNumber_NullValue, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, nullValue), + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .dataType = GPBDataTypeEnum, + }, + { + .name = "numberValue", + .dataTypeSpecific.className = NULL, + .number = GPBValue_FieldNumber_NumberValue, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, numberValue), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeDouble, + }, + { + .name = "stringValue", + .dataTypeSpecific.className = NULL, + .number = GPBValue_FieldNumber_StringValue, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, stringValue), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "boolValue", + .dataTypeSpecific.className = NULL, + .number = GPBValue_FieldNumber_BoolValue, + .hasIndex = -1, + .offset = 0, // Stored in _has_storage_ to save space. + .flags = GPBFieldOptional, + .dataType = GPBDataTypeBool, + }, + { + .name = "structValue", + .dataTypeSpecific.className = GPBStringifySymbol(GPBStruct), + .number = GPBValue_FieldNumber_StructValue, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, structValue), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "listValue", + .dataTypeSpecific.className = GPBStringifySymbol(GPBListValue), + .number = GPBValue_FieldNumber_ListValue, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GPBValue__storage_, listValue), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBValue class] + rootClass:[GPBStructRoot class] + file:GPBStructRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBValue__storage_) + flags:0]; + static const char *oneofs[] = { + "kind", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +int32_t GPBValue_NullValue_RawValue(GPBValue *message) { + GPBDescriptor *descriptor = [GPBValue descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue]; + return GPBGetMessageInt32Field(message, field); +} + +void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value) { + GPBDescriptor *descriptor = [GPBValue descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue]; + GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); +} + +void GPBValue_ClearKindOneOfCase(GPBValue *message) { + GPBDescriptor *descriptor = [message descriptor]; + GPBOneofDescriptor *oneof = descriptor->oneofs_[0]; + GPBMaybeClearOneof(message, oneof, -1, 0); +} +#pragma mark - GPBListValue + +@implementation GPBListValue + +@dynamic valuesArray, valuesArray_Count; + +typedef struct GPBListValue__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *valuesArray; +} GPBListValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "valuesArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), + .number = GPBListValue_FieldNumber_ValuesArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBListValue__storage_, valuesArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBListValue class] + rootClass:[GPBStructRoot class] + file:GPBStructRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBListValue__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/google/protobuf/Timestamp.pbobjc.h new file mode 100644 index 00000000..925dca84 --- /dev/null +++ b/objectivec/google/google/protobuf/Timestamp.pbobjc.h @@ -0,0 +1,113 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/timestamp.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBTimestampRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBTimestampRoot : GPBRootObject +@end + +#pragma mark - GPBTimestamp + +typedef GPB_ENUM(GPBTimestamp_FieldNumber) { + GPBTimestamp_FieldNumber_Seconds = 1, + GPBTimestamp_FieldNumber_Nanos = 2, +}; + +/// A Timestamp represents a point in time independent of any time zone +/// or calendar, represented as seconds and fractions of seconds at +/// nanosecond resolution in UTC Epoch time. It is encoded using the +/// Proleptic Gregorian Calendar which extends the Gregorian calendar +/// backwards to year one. It is encoded assuming all minutes are 60 +/// seconds long, i.e. leap seconds are "smeared" so that no leap second +/// table is needed for interpretation. Range is from +/// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. +/// By restricting to that range, we ensure that we can convert to +/// and from RFC 3339 date strings. +/// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). +/// +/// Example 1: Compute Timestamp from POSIX `time()`. +/// +/// Timestamp timestamp; +/// timestamp.set_seconds(time(NULL)); +/// timestamp.set_nanos(0); +/// +/// Example 2: Compute Timestamp from POSIX `gettimeofday()`. +/// +/// struct timeval tv; +/// gettimeofday(&tv, NULL); +/// +/// Timestamp timestamp; +/// timestamp.set_seconds(tv.tv_sec); +/// timestamp.set_nanos(tv.tv_usec * 1000); +/// +/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. +/// +/// FILETIME ft; +/// GetSystemTimeAsFileTime(&ft); +/// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; +/// +/// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z +/// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. +/// Timestamp timestamp; +/// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); +/// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); +/// +/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. +/// +/// long millis = System.currentTimeMillis(); +/// +/// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) +/// .setNanos((int) ((millis % 1000) * 1000000)).build(); +/// +/// +/// Example 5: Compute Timestamp from current time in Python. +/// +/// now = time.time() +/// seconds = int(now) +/// nanos = int((now - seconds) * 10**9) +/// timestamp = Timestamp(seconds=seconds, nanos=nanos) +@interface GPBTimestamp : GPBMessage + +/// Represents seconds of UTC time since Unix epoch +/// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to +/// 9999-12-31T23:59:59Z inclusive. +@property(nonatomic, readwrite) int64_t seconds; + +/// Non-negative fractions of a second at nanosecond resolution. Negative +/// second values with fractions must still have non-negative nanos values +/// that count forward in time. Must be from 0 to 999,999,999 +/// inclusive. +@property(nonatomic, readwrite) int32_t nanos; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/google/protobuf/Timestamp.pbobjc.m new file mode 100644 index 00000000..f35e435d --- /dev/null +++ b/objectivec/google/google/protobuf/Timestamp.pbobjc.m @@ -0,0 +1,88 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/timestamp.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Timestamp.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBTimestampRoot + +@implementation GPBTimestampRoot + +@end + +#pragma mark - GPBTimestampRoot_FileDescriptor + +static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBTimestamp + +@implementation GPBTimestamp + +@dynamic seconds; +@dynamic nanos; + +typedef struct GPBTimestamp__storage_ { + uint32_t _has_storage_[1]; + int32_t nanos; + int64_t seconds; +} GPBTimestamp__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "seconds", + .dataTypeSpecific.className = NULL, + .number = GPBTimestamp_FieldNumber_Seconds, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBTimestamp__storage_, seconds), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt64, + }, + { + .name = "nanos", + .dataTypeSpecific.className = NULL, + .number = GPBTimestamp_FieldNumber_Nanos, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBTimestamp__storage_, nanos), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt32, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBTimestamp class] + rootClass:[GPBTimestampRoot class] + file:GPBTimestampRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBTimestamp__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Type.pbobjc.h b/objectivec/google/google/protobuf/Type.pbobjc.h new file mode 100644 index 00000000..590d970b --- /dev/null +++ b/objectivec/google/google/protobuf/Type.pbobjc.h @@ -0,0 +1,373 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/type.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +@class GPBAny; +@class GPBEnumValue; +@class GPBField; +@class GPBOption; +@class GPBSourceContext; + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - Enum GPBSyntax + +/// The syntax in which a protocol buffer element is defined. +typedef GPB_ENUM(GPBSyntax) { + /// Value used if any message's field encounters a value that is not defined + /// by this enum. The message will also have C functions to get/set the rawValue + /// of the field. + GPBSyntax_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, + /// Syntax `proto2`. + GPBSyntax_SyntaxProto2 = 0, + + /// Syntax `proto3`. + GPBSyntax_SyntaxProto3 = 1, +}; + +GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void); + +/// Checks to see if the given value is defined by the enum or was not known at +/// the time this source was generated. +BOOL GPBSyntax_IsValidValue(int32_t value); + +#pragma mark - Enum GPBField_Kind + +/// Basic field types. +typedef GPB_ENUM(GPBField_Kind) { + /// Value used if any message's field encounters a value that is not defined + /// by this enum. The message will also have C functions to get/set the rawValue + /// of the field. + GPBField_Kind_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, + /// Field type unknown. + GPBField_Kind_TypeUnknown = 0, + + /// Field type double. + GPBField_Kind_TypeDouble = 1, + + /// Field type float. + GPBField_Kind_TypeFloat = 2, + + /// Field type int64. + GPBField_Kind_TypeInt64 = 3, + + /// Field type uint64. + GPBField_Kind_TypeUint64 = 4, + + /// Field type int32. + GPBField_Kind_TypeInt32 = 5, + + /// Field type fixed64. + GPBField_Kind_TypeFixed64 = 6, + + /// Field type fixed32. + GPBField_Kind_TypeFixed32 = 7, + + /// Field type bool. + GPBField_Kind_TypeBool = 8, + + /// Field type string. + GPBField_Kind_TypeString = 9, + + /// Field type group. Proto2 syntax only, and deprecated. + GPBField_Kind_TypeGroup = 10, + + /// Field type message. + GPBField_Kind_TypeMessage = 11, + + /// Field type bytes. + GPBField_Kind_TypeBytes = 12, + + /// Field type uint32. + GPBField_Kind_TypeUint32 = 13, + + /// Field type enum. + GPBField_Kind_TypeEnum = 14, + + /// Field type sfixed32. + GPBField_Kind_TypeSfixed32 = 15, + + /// Field type sfixed64. + GPBField_Kind_TypeSfixed64 = 16, + + /// Field type sint32. + GPBField_Kind_TypeSint32 = 17, + + /// Field type sint64. + GPBField_Kind_TypeSint64 = 18, +}; + +GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void); + +/// Checks to see if the given value is defined by the enum or was not known at +/// the time this source was generated. +BOOL GPBField_Kind_IsValidValue(int32_t value); + +#pragma mark - Enum GPBField_Cardinality + +/// Whether a field is optional, required, or repeated. +typedef GPB_ENUM(GPBField_Cardinality) { + /// Value used if any message's field encounters a value that is not defined + /// by this enum. The message will also have C functions to get/set the rawValue + /// of the field. + GPBField_Cardinality_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, + /// For fields with unknown cardinality. + GPBField_Cardinality_CardinalityUnknown = 0, + + /// For optional fields. + GPBField_Cardinality_CardinalityOptional = 1, + + /// For required fields. Proto2 syntax only. + GPBField_Cardinality_CardinalityRequired = 2, + + /// For repeated fields. + GPBField_Cardinality_CardinalityRepeated = 3, +}; + +GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void); + +/// Checks to see if the given value is defined by the enum or was not known at +/// the time this source was generated. +BOOL GPBField_Cardinality_IsValidValue(int32_t value); + +#pragma mark - GPBTypeRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBTypeRoot : GPBRootObject +@end + +#pragma mark - GPBType + +typedef GPB_ENUM(GPBType_FieldNumber) { + GPBType_FieldNumber_Name = 1, + GPBType_FieldNumber_FieldsArray = 2, + GPBType_FieldNumber_OneofsArray = 3, + GPBType_FieldNumber_OptionsArray = 4, + GPBType_FieldNumber_SourceContext = 5, + GPBType_FieldNumber_Syntax = 6, +}; + +/// A protocol buffer message type. +@interface GPBType : GPBMessage + +/// The fully qualified message name. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// The list of fields. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldsArray; +/// The number of items in @c fieldsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger fieldsArray_Count; + +/// The list of types appearing in `oneof` definitions in this type. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *oneofsArray; +/// The number of items in @c oneofsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger oneofsArray_Count; + +/// The protocol buffer options. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; +/// The number of items in @c optionsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger optionsArray_Count; + +/// The source context. +@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext; +/// Test to see if @c sourceContext has been set. +@property(nonatomic, readwrite) BOOL hasSourceContext; + +/// The source syntax. +@property(nonatomic, readwrite) GPBSyntax syntax; + +@end + +/// Fetches the raw value of a @c GPBType's @c syntax property, even +/// if the value was not defined by the enum at the time the code was generated. +int32_t GPBType_Syntax_RawValue(GPBType *message); +/// Sets the raw value of an @c GPBType's @c syntax property, allowing +/// it to be set to a value that was not defined by the enum at the time the code +/// was generated. +void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value); + +#pragma mark - GPBField + +typedef GPB_ENUM(GPBField_FieldNumber) { + GPBField_FieldNumber_Kind = 1, + GPBField_FieldNumber_Cardinality = 2, + GPBField_FieldNumber_Number = 3, + GPBField_FieldNumber_Name = 4, + GPBField_FieldNumber_TypeURL = 6, + GPBField_FieldNumber_OneofIndex = 7, + GPBField_FieldNumber_Packed = 8, + GPBField_FieldNumber_OptionsArray = 9, + GPBField_FieldNumber_JsonName = 10, + GPBField_FieldNumber_DefaultValue = 11, +}; + +/// A single field of a message type. +@interface GPBField : GPBMessage + +/// The field type. +@property(nonatomic, readwrite) GPBField_Kind kind; + +/// The field cardinality. +@property(nonatomic, readwrite) GPBField_Cardinality cardinality; + +/// The field number. +@property(nonatomic, readwrite) int32_t number; + +/// The field name. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// The field type URL, without the scheme, for message or enumeration +/// types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. +@property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL; + +/// The index of the field type in `Type.oneofs`, for message or enumeration +/// types. The first type has index 1; zero means the type is not in the list. +@property(nonatomic, readwrite) int32_t oneofIndex; + +/// Whether to use alternative packed wire representation. +@property(nonatomic, readwrite) BOOL packed; + +/// The protocol buffer options. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; +/// The number of items in @c optionsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger optionsArray_Count; + +/// The field JSON name. +@property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName; + +/// The string value of the default value of this field. Proto2 syntax only. +@property(nonatomic, readwrite, copy, null_resettable) NSString *defaultValue; + +@end + +/// Fetches the raw value of a @c GPBField's @c kind property, even +/// if the value was not defined by the enum at the time the code was generated. +int32_t GPBField_Kind_RawValue(GPBField *message); +/// Sets the raw value of an @c GPBField's @c kind property, allowing +/// it to be set to a value that was not defined by the enum at the time the code +/// was generated. +void SetGPBField_Kind_RawValue(GPBField *message, int32_t value); + +/// Fetches the raw value of a @c GPBField's @c cardinality property, even +/// if the value was not defined by the enum at the time the code was generated. +int32_t GPBField_Cardinality_RawValue(GPBField *message); +/// Sets the raw value of an @c GPBField's @c cardinality property, allowing +/// it to be set to a value that was not defined by the enum at the time the code +/// was generated. +void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value); + +#pragma mark - GPBEnum + +typedef GPB_ENUM(GPBEnum_FieldNumber) { + GPBEnum_FieldNumber_Name = 1, + GPBEnum_FieldNumber_EnumvalueArray = 2, + GPBEnum_FieldNumber_OptionsArray = 3, + GPBEnum_FieldNumber_SourceContext = 4, + GPBEnum_FieldNumber_Syntax = 5, +}; + +/// Enum type definition. +@interface GPBEnum : GPBMessage + +/// Enum type name. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// Enum value definitions. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumvalueArray; +/// The number of items in @c enumvalueArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger enumvalueArray_Count; + +/// Protocol buffer options. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; +/// The number of items in @c optionsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger optionsArray_Count; + +/// The source context. +@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext; +/// Test to see if @c sourceContext has been set. +@property(nonatomic, readwrite) BOOL hasSourceContext; + +/// The source syntax. +@property(nonatomic, readwrite) GPBSyntax syntax; + +@end + +/// Fetches the raw value of a @c GPBEnum's @c syntax property, even +/// if the value was not defined by the enum at the time the code was generated. +int32_t GPBEnum_Syntax_RawValue(GPBEnum *message); +/// Sets the raw value of an @c GPBEnum's @c syntax property, allowing +/// it to be set to a value that was not defined by the enum at the time the code +/// was generated. +void SetGPBEnum_Syntax_RawValue(GPBEnum *message, int32_t value); + +#pragma mark - GPBEnumValue + +typedef GPB_ENUM(GPBEnumValue_FieldNumber) { + GPBEnumValue_FieldNumber_Name = 1, + GPBEnumValue_FieldNumber_Number = 2, + GPBEnumValue_FieldNumber_OptionsArray = 3, +}; + +/// Enum value definition. +@interface GPBEnumValue : GPBMessage + +/// Enum value name. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// Enum value number. +@property(nonatomic, readwrite) int32_t number; + +/// Protocol buffer options. +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; +/// The number of items in @c optionsArray without causing the array to be created. +@property(nonatomic, readonly) NSUInteger optionsArray_Count; + +@end + +#pragma mark - GPBOption + +typedef GPB_ENUM(GPBOption_FieldNumber) { + GPBOption_FieldNumber_Name = 1, + GPBOption_FieldNumber_Value = 2, +}; + +/// A protocol buffer option, which can be attached to a message, field, +/// enumeration, etc. +@interface GPBOption : GPBMessage + +/// The option's name. For example, `"java_package"`. +@property(nonatomic, readwrite, copy, null_resettable) NSString *name; + +/// The option's value. For example, `"com.google.protobuf"`. +@property(nonatomic, readwrite, strong, null_resettable) GPBAny *value; +/// Test to see if @c value has been set. +@property(nonatomic, readwrite) BOOL hasValue; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Type.pbobjc.m b/objectivec/google/google/protobuf/Type.pbobjc.m new file mode 100644 index 00000000..5554a222 --- /dev/null +++ b/objectivec/google/google/protobuf/Type.pbobjc.m @@ -0,0 +1,693 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/type.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Type.pbobjc.h" +#import "google/protobuf/Any.pbobjc.h" +#import "google/protobuf/SourceContext.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBTypeRoot + +@implementation GPBTypeRoot + ++ (GPBExtensionRegistry*)extensionRegistry { + // This is called by +initialize so there is no need to worry + // about thread safety and initialization of registry. + static GPBExtensionRegistry* registry = nil; + if (!registry) { + GPBDebugCheckRuntimeVersion(); + registry = [[GPBExtensionRegistry alloc] init]; + [registry addExtensions:[GPBAnyRoot extensionRegistry]]; + [registry addExtensions:[GPBSourceContextRoot extensionRegistry]]; + } + return registry; +} + +@end + +#pragma mark - GPBTypeRoot_FileDescriptor + +static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - Enum GPBSyntax + +GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static const char *valueNames = + "SyntaxProto2\000SyntaxProto3\000"; + static const int32_t values[] = { + GPBSyntax_SyntaxProto2, + GPBSyntax_SyntaxProto3, + }; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBSyntax) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBSyntax_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } + } + return descriptor; +} + +BOOL GPBSyntax_IsValidValue(int32_t value__) { + switch (value__) { + case GPBSyntax_SyntaxProto2: + case GPBSyntax_SyntaxProto3: + return YES; + default: + return NO; + } +} + +#pragma mark - GPBType + +@implementation GPBType + +@dynamic name; +@dynamic fieldsArray, fieldsArray_Count; +@dynamic oneofsArray, oneofsArray_Count; +@dynamic optionsArray, optionsArray_Count; +@dynamic hasSourceContext, sourceContext; +@dynamic syntax; + +typedef struct GPBType__storage_ { + uint32_t _has_storage_[1]; + GPBSyntax syntax; + NSString *name; + NSMutableArray *fieldsArray; + NSMutableArray *oneofsArray; + NSMutableArray *optionsArray; + GPBSourceContext *sourceContext; +} GPBType__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBType_FieldNumber_Name, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBType__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "fieldsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBField), + .number = GPBType_FieldNumber_FieldsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBType__storage_, fieldsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "oneofsArray", + .dataTypeSpecific.className = NULL, + .number = GPBType_FieldNumber_OneofsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBType__storage_, oneofsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeString, + }, + { + .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .number = GPBType_FieldNumber_OptionsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBType__storage_, optionsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "sourceContext", + .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), + .number = GPBType_FieldNumber_SourceContext, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBType__storage_, sourceContext), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, + .number = GPBType_FieldNumber_Syntax, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBType__storage_, syntax), + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .dataType = GPBDataTypeEnum, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBType class] + rootClass:[GPBTypeRoot class] + file:GPBTypeRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBType__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +int32_t GPBType_Syntax_RawValue(GPBType *message) { + GPBDescriptor *descriptor = [GPBType descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBType_FieldNumber_Syntax]; + return GPBGetMessageInt32Field(message, field); +} + +void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value) { + GPBDescriptor *descriptor = [GPBType descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBType_FieldNumber_Syntax]; + GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); +} + +#pragma mark - GPBField + +@implementation GPBField + +@dynamic kind; +@dynamic cardinality; +@dynamic number; +@dynamic name; +@dynamic typeURL; +@dynamic oneofIndex; +@dynamic packed; +@dynamic optionsArray, optionsArray_Count; +@dynamic jsonName; +@dynamic defaultValue; + +typedef struct GPBField__storage_ { + uint32_t _has_storage_[1]; + GPBField_Kind kind; + GPBField_Cardinality cardinality; + int32_t number; + int32_t oneofIndex; + NSString *name; + NSString *typeURL; + NSMutableArray *optionsArray; + NSString *jsonName; + NSString *defaultValue; +} GPBField__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "kind", + .dataTypeSpecific.enumDescFunc = GPBField_Kind_EnumDescriptor, + .number = GPBField_FieldNumber_Kind, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBField__storage_, kind), + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .dataType = GPBDataTypeEnum, + }, + { + .name = "cardinality", + .dataTypeSpecific.enumDescFunc = GPBField_Cardinality_EnumDescriptor, + .number = GPBField_FieldNumber_Cardinality, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBField__storage_, cardinality), + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .dataType = GPBDataTypeEnum, + }, + { + .name = "number", + .dataTypeSpecific.className = NULL, + .number = GPBField_FieldNumber_Number, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBField__storage_, number), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt32, + }, + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBField_FieldNumber_Name, + .hasIndex = 3, + .offset = (uint32_t)offsetof(GPBField__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "typeURL", + .dataTypeSpecific.className = NULL, + .number = GPBField_FieldNumber_TypeURL, + .hasIndex = 4, + .offset = (uint32_t)offsetof(GPBField__storage_, typeURL), + .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, + .dataType = GPBDataTypeString, + }, + { + .name = "oneofIndex", + .dataTypeSpecific.className = NULL, + .number = GPBField_FieldNumber_OneofIndex, + .hasIndex = 5, + .offset = (uint32_t)offsetof(GPBField__storage_, oneofIndex), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt32, + }, + { + .name = "packed", + .dataTypeSpecific.className = NULL, + .number = GPBField_FieldNumber_Packed, + .hasIndex = 6, + .offset = 7, // Stored in _has_storage_ to save space. + .flags = GPBFieldOptional, + .dataType = GPBDataTypeBool, + }, + { + .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .number = GPBField_FieldNumber_OptionsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBField__storage_, optionsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "jsonName", + .dataTypeSpecific.className = NULL, + .number = GPBField_FieldNumber_JsonName, + .hasIndex = 8, + .offset = (uint32_t)offsetof(GPBField__storage_, jsonName), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "defaultValue", + .dataTypeSpecific.className = NULL, + .number = GPBField_FieldNumber_DefaultValue, + .hasIndex = 9, + .offset = (uint32_t)offsetof(GPBField__storage_, defaultValue), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBField class] + rootClass:[GPBTypeRoot class] + file:GPBTypeRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBField__storage_) + flags:0]; +#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + static const char *extraTextFormatInfo = + "\001\006\004\241!!\000"; + [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; +#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +int32_t GPBField_Kind_RawValue(GPBField *message) { + GPBDescriptor *descriptor = [GPBField descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind]; + return GPBGetMessageInt32Field(message, field); +} + +void SetGPBField_Kind_RawValue(GPBField *message, int32_t value) { + GPBDescriptor *descriptor = [GPBField descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind]; + GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); +} + +int32_t GPBField_Cardinality_RawValue(GPBField *message) { + GPBDescriptor *descriptor = [GPBField descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality]; + return GPBGetMessageInt32Field(message, field); +} + +void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value) { + GPBDescriptor *descriptor = [GPBField descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality]; + GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); +} + +#pragma mark - Enum GPBField_Kind + +GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static const char *valueNames = + "TypeUnknown\000TypeDouble\000TypeFloat\000TypeInt" + "64\000TypeUint64\000TypeInt32\000TypeFixed64\000Type" + "Fixed32\000TypeBool\000TypeString\000TypeGroup\000Ty" + "peMessage\000TypeBytes\000TypeUint32\000TypeEnum\000" + "TypeSfixed32\000TypeSfixed64\000TypeSint32\000Typ" + "eSint64\000"; + static const int32_t values[] = { + GPBField_Kind_TypeUnknown, + GPBField_Kind_TypeDouble, + GPBField_Kind_TypeFloat, + GPBField_Kind_TypeInt64, + GPBField_Kind_TypeUint64, + GPBField_Kind_TypeInt32, + GPBField_Kind_TypeFixed64, + GPBField_Kind_TypeFixed32, + GPBField_Kind_TypeBool, + GPBField_Kind_TypeString, + GPBField_Kind_TypeGroup, + GPBField_Kind_TypeMessage, + GPBField_Kind_TypeBytes, + GPBField_Kind_TypeUint32, + GPBField_Kind_TypeEnum, + GPBField_Kind_TypeSfixed32, + GPBField_Kind_TypeSfixed64, + GPBField_Kind_TypeSint32, + GPBField_Kind_TypeSint64, + }; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Kind) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBField_Kind_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } + } + return descriptor; +} + +BOOL GPBField_Kind_IsValidValue(int32_t value__) { + switch (value__) { + case GPBField_Kind_TypeUnknown: + case GPBField_Kind_TypeDouble: + case GPBField_Kind_TypeFloat: + case GPBField_Kind_TypeInt64: + case GPBField_Kind_TypeUint64: + case GPBField_Kind_TypeInt32: + case GPBField_Kind_TypeFixed64: + case GPBField_Kind_TypeFixed32: + case GPBField_Kind_TypeBool: + case GPBField_Kind_TypeString: + case GPBField_Kind_TypeGroup: + case GPBField_Kind_TypeMessage: + case GPBField_Kind_TypeBytes: + case GPBField_Kind_TypeUint32: + case GPBField_Kind_TypeEnum: + case GPBField_Kind_TypeSfixed32: + case GPBField_Kind_TypeSfixed64: + case GPBField_Kind_TypeSint32: + case GPBField_Kind_TypeSint64: + return YES; + default: + return NO; + } +} + +#pragma mark - Enum GPBField_Cardinality + +GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void) { + static GPBEnumDescriptor *descriptor = NULL; + if (!descriptor) { + static const char *valueNames = + "CardinalityUnknown\000CardinalityOptional\000C" + "ardinalityRequired\000CardinalityRepeated\000"; + static const int32_t values[] = { + GPBField_Cardinality_CardinalityUnknown, + GPBField_Cardinality_CardinalityOptional, + GPBField_Cardinality_CardinalityRequired, + GPBField_Cardinality_CardinalityRepeated, + }; + GPBEnumDescriptor *worker = + [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Cardinality) + valueNames:valueNames + values:values + count:(uint32_t)(sizeof(values) / sizeof(int32_t)) + enumVerifier:GPBField_Cardinality_IsValidValue]; + if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { + [worker release]; + } + } + return descriptor; +} + +BOOL GPBField_Cardinality_IsValidValue(int32_t value__) { + switch (value__) { + case GPBField_Cardinality_CardinalityUnknown: + case GPBField_Cardinality_CardinalityOptional: + case GPBField_Cardinality_CardinalityRequired: + case GPBField_Cardinality_CardinalityRepeated: + return YES; + default: + return NO; + } +} + +#pragma mark - GPBEnum + +@implementation GPBEnum + +@dynamic name; +@dynamic enumvalueArray, enumvalueArray_Count; +@dynamic optionsArray, optionsArray_Count; +@dynamic hasSourceContext, sourceContext; +@dynamic syntax; + +typedef struct GPBEnum__storage_ { + uint32_t _has_storage_[1]; + GPBSyntax syntax; + NSString *name; + NSMutableArray *enumvalueArray; + NSMutableArray *optionsArray; + GPBSourceContext *sourceContext; +} GPBEnum__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBEnum_FieldNumber_Name, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBEnum__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "enumvalueArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValue), + .number = GPBEnum_FieldNumber_EnumvalueArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBEnum__storage_, enumvalueArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .number = GPBEnum_FieldNumber_OptionsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBEnum__storage_, optionsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + { + .name = "sourceContext", + .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), + .number = GPBEnum_FieldNumber_SourceContext, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBEnum__storage_, sourceContext), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "syntax", + .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, + .number = GPBEnum_FieldNumber_Syntax, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GPBEnum__storage_, syntax), + .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, + .dataType = GPBDataTypeEnum, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBEnum class] + rootClass:[GPBTypeRoot class] + file:GPBTypeRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBEnum__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +int32_t GPBEnum_Syntax_RawValue(GPBEnum *message) { + GPBDescriptor *descriptor = [GPBEnum descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBEnum_FieldNumber_Syntax]; + return GPBGetMessageInt32Field(message, field); +} + +void SetGPBEnum_Syntax_RawValue(GPBEnum *message, int32_t value) { + GPBDescriptor *descriptor = [GPBEnum descriptor]; + GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBEnum_FieldNumber_Syntax]; + GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); +} + +#pragma mark - GPBEnumValue + +@implementation GPBEnumValue + +@dynamic name; +@dynamic number; +@dynamic optionsArray, optionsArray_Count; + +typedef struct GPBEnumValue__storage_ { + uint32_t _has_storage_[1]; + int32_t number; + NSString *name; + NSMutableArray *optionsArray; +} GPBEnumValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBEnumValue_FieldNumber_Name, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBEnumValue__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "number", + .dataTypeSpecific.className = NULL, + .number = GPBEnumValue_FieldNumber_Number, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBEnumValue__storage_, number), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt32, + }, + { + .name = "optionsArray", + .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), + .number = GPBEnumValue_FieldNumber_OptionsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GPBEnumValue__storage_, optionsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBEnumValue class] + rootClass:[GPBTypeRoot class] + file:GPBTypeRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBEnumValue__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBOption + +@implementation GPBOption + +@dynamic name; +@dynamic hasValue, value; + +typedef struct GPBOption__storage_ { + uint32_t _has_storage_[1]; + NSString *name; + GPBAny *value; +} GPBOption__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "name", + .dataTypeSpecific.className = NULL, + .number = GPBOption_FieldNumber_Name, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBOption__storage_, name), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + { + .name = "value", + .dataTypeSpecific.className = GPBStringifySymbol(GPBAny), + .number = GPBOption_FieldNumber_Value, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GPBOption__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBOption class] + rootClass:[GPBTypeRoot class] + file:GPBTypeRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBOption__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/google/protobuf/Wrappers.pbobjc.h new file mode 100644 index 00000000..46510500 --- /dev/null +++ b/objectivec/google/google/protobuf/Wrappers.pbobjc.h @@ -0,0 +1,182 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/wrappers.proto + +#import "GPBProtocolBuffers.h" + +#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 +#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. +#endif + +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +CF_EXTERN_C_BEGIN + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - GPBWrappersRoot + +/// Exposes the extension registry for this file. +/// +/// The base class provides: +/// @code +/// + (GPBExtensionRegistry *)extensionRegistry; +/// @endcode +/// which is a @c GPBExtensionRegistry that includes all the extensions defined by +/// this file and all files that it depends on. +@interface GPBWrappersRoot : GPBRootObject +@end + +#pragma mark - GPBDoubleValue + +typedef GPB_ENUM(GPBDoubleValue_FieldNumber) { + GPBDoubleValue_FieldNumber_Value = 1, +}; + +/// Wrapper message for `double`. +/// +/// The JSON representation for `DoubleValue` is JSON number. +@interface GPBDoubleValue : GPBMessage + +/// The double value. +@property(nonatomic, readwrite) double value; + +@end + +#pragma mark - GPBFloatValue + +typedef GPB_ENUM(GPBFloatValue_FieldNumber) { + GPBFloatValue_FieldNumber_Value = 1, +}; + +/// Wrapper message for `float`. +/// +/// The JSON representation for `FloatValue` is JSON number. +@interface GPBFloatValue : GPBMessage + +/// The float value. +@property(nonatomic, readwrite) float value; + +@end + +#pragma mark - GPBInt64Value + +typedef GPB_ENUM(GPBInt64Value_FieldNumber) { + GPBInt64Value_FieldNumber_Value = 1, +}; + +/// Wrapper message for `int64`. +/// +/// The JSON representation for `Int64Value` is JSON string. +@interface GPBInt64Value : GPBMessage + +/// The int64 value. +@property(nonatomic, readwrite) int64_t value; + +@end + +#pragma mark - GPBUInt64Value + +typedef GPB_ENUM(GPBUInt64Value_FieldNumber) { + GPBUInt64Value_FieldNumber_Value = 1, +}; + +/// Wrapper message for `uint64`. +/// +/// The JSON representation for `UInt64Value` is JSON string. +@interface GPBUInt64Value : GPBMessage + +/// The uint64 value. +@property(nonatomic, readwrite) uint64_t value; + +@end + +#pragma mark - GPBInt32Value + +typedef GPB_ENUM(GPBInt32Value_FieldNumber) { + GPBInt32Value_FieldNumber_Value = 1, +}; + +/// Wrapper message for `int32`. +/// +/// The JSON representation for `Int32Value` is JSON number. +@interface GPBInt32Value : GPBMessage + +/// The int32 value. +@property(nonatomic, readwrite) int32_t value; + +@end + +#pragma mark - GPBUInt32Value + +typedef GPB_ENUM(GPBUInt32Value_FieldNumber) { + GPBUInt32Value_FieldNumber_Value = 1, +}; + +/// Wrapper message for `uint32`. +/// +/// The JSON representation for `UInt32Value` is JSON number. +@interface GPBUInt32Value : GPBMessage + +/// The uint32 value. +@property(nonatomic, readwrite) uint32_t value; + +@end + +#pragma mark - GPBBoolValue + +typedef GPB_ENUM(GPBBoolValue_FieldNumber) { + GPBBoolValue_FieldNumber_Value = 1, +}; + +/// Wrapper message for `bool`. +/// +/// The JSON representation for `BoolValue` is JSON `true` and `false`. +@interface GPBBoolValue : GPBMessage + +/// The bool value. +@property(nonatomic, readwrite) BOOL value; + +@end + +#pragma mark - GPBStringValue + +typedef GPB_ENUM(GPBStringValue_FieldNumber) { + GPBStringValue_FieldNumber_Value = 1, +}; + +/// Wrapper message for `string`. +/// +/// The JSON representation for `StringValue` is JSON string. +@interface GPBStringValue : GPBMessage + +/// The string value. +@property(nonatomic, readwrite, copy, null_resettable) NSString *value; + +@end + +#pragma mark - GPBBytesValue + +typedef GPB_ENUM(GPBBytesValue_FieldNumber) { + GPBBytesValue_FieldNumber_Value = 1, +}; + +/// Wrapper message for `bytes`. +/// +/// The JSON representation for `BytesValue` is JSON string. +@interface GPBBytesValue : GPBMessage + +/// The bytes value. +@property(nonatomic, readwrite, copy, null_resettable) NSData *value; + +@end + +NS_ASSUME_NONNULL_END + +CF_EXTERN_C_END + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/google/protobuf/Wrappers.pbobjc.m new file mode 100644 index 00000000..5cc6c2e4 --- /dev/null +++ b/objectivec/google/google/protobuf/Wrappers.pbobjc.m @@ -0,0 +1,420 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/wrappers.proto + +#import "GPBProtocolBuffers_RuntimeSupport.h" +#import "google/protobuf/Wrappers.pbobjc.h" +// @@protoc_insertion_point(imports) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#pragma mark - GPBWrappersRoot + +@implementation GPBWrappersRoot + +@end + +#pragma mark - GPBWrappersRoot_FileDescriptor + +static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) { + // This is called by +initialize so there is no need to worry + // about thread safety of the singleton. + static GPBFileDescriptor *descriptor = NULL; + if (!descriptor) { + GPBDebugCheckRuntimeVersion(); + descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" + syntax:GPBFileSyntaxProto3]; + } + return descriptor; +} + +#pragma mark - GPBDoubleValue + +@implementation GPBDoubleValue + +@dynamic value; + +typedef struct GPBDoubleValue__storage_ { + uint32_t _has_storage_[1]; + double value; +} GPBDoubleValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBDoubleValue_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBDoubleValue__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeDouble, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBDoubleValue class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBDoubleValue__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBFloatValue + +@implementation GPBFloatValue + +@dynamic value; + +typedef struct GPBFloatValue__storage_ { + uint32_t _has_storage_[1]; + float value; +} GPBFloatValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBFloatValue_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBFloatValue__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeFloat, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBFloatValue class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBFloatValue__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBInt64Value + +@implementation GPBInt64Value + +@dynamic value; + +typedef struct GPBInt64Value__storage_ { + uint32_t _has_storage_[1]; + int64_t value; +} GPBInt64Value__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBInt64Value_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBInt64Value__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt64, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBInt64Value class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBInt64Value__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBUInt64Value + +@implementation GPBUInt64Value + +@dynamic value; + +typedef struct GPBUInt64Value__storage_ { + uint32_t _has_storage_[1]; + uint64_t value; +} GPBUInt64Value__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBUInt64Value_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBUInt64Value__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeUInt64, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBUInt64Value class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBUInt64Value__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBInt32Value + +@implementation GPBInt32Value + +@dynamic value; + +typedef struct GPBInt32Value__storage_ { + uint32_t _has_storage_[1]; + int32_t value; +} GPBInt32Value__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBInt32Value_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBInt32Value__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeInt32, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBInt32Value class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBInt32Value__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBUInt32Value + +@implementation GPBUInt32Value + +@dynamic value; + +typedef struct GPBUInt32Value__storage_ { + uint32_t _has_storage_[1]; + uint32_t value; +} GPBUInt32Value__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBUInt32Value_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBUInt32Value__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeUInt32, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBUInt32Value class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBUInt32Value__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBBoolValue + +@implementation GPBBoolValue + +@dynamic value; + +typedef struct GPBBoolValue__storage_ { + uint32_t _has_storage_[1]; +} GPBBoolValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBBoolValue_FieldNumber_Value, + .hasIndex = 0, + .offset = 1, // Stored in _has_storage_ to save space. + .flags = GPBFieldOptional, + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBBoolValue class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBBoolValue__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBStringValue + +@implementation GPBStringValue + +@dynamic value; + +typedef struct GPBStringValue__storage_ { + uint32_t _has_storage_[1]; + NSString *value; +} GPBStringValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBStringValue_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBStringValue__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeString, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBStringValue class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBStringValue__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GPBBytesValue + +@implementation GPBBytesValue + +@dynamic value; + +typedef struct GPBBytesValue__storage_ { + uint32_t _has_storage_[1]; + NSData *value; +} GPBBytesValue__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "value", + .dataTypeSpecific.className = NULL, + .number = GPBBytesValue_FieldNumber_Value, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GPBBytesValue__storage_, value), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GPBBytesValue class] + rootClass:[GPBWrappersRoot class] + file:GPBWrappersRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GPBBytesValue__storage_) + flags:0]; + NSAssert(descriptor == nil, @"Startup recursed!"); + descriptor = localDescriptor; + } + return descriptor; +} + +@end + + +#pragma clang diagnostic pop + +// @@protoc_insertion_point(global_scope) diff --git a/php/tests/autoload.php b/php/tests/autoload.php new file mode 100644 index 00000000..af88ba01 --- /dev/null +++ b/php/tests/autoload.php @@ -0,0 +1,4 @@ +options()); const Descriptor *message_type = options.GetDescriptor(); - PyObject* message_class(cdescriptor_pool::GetMessageClass( - pool, message_type)); + CMessageClass* message_class( + cdescriptor_pool::GetMessageClass(pool, message_type)); if (message_class == NULL) { // The Options message was not found in the current DescriptorPool. // In this case, there cannot be extensions to these options, and we can @@ -215,7 +215,8 @@ static PyObject* GetOrBuildOptions(const DescriptorClass *descriptor) { message_type->full_name().c_str()); return NULL; } - ScopedPyObjectPtr value(PyEval_CallObject(message_class, NULL)); + ScopedPyObjectPtr value( + PyEval_CallObject(message_class->AsPyObject(), NULL)); if (value == NULL) { return NULL; } @@ -433,11 +434,11 @@ static PyObject* GetConcreteClass(PyBaseDescriptor* self, void *closure) { // which contains this descriptor. // This might not be the one you expect! For example the returned object does // not know about extensions defined in a custom pool. - PyObject* concrete_class(cdescriptor_pool::GetMessageClass( + CMessageClass* concrete_class(cdescriptor_pool::GetMessageClass( GetDescriptorPool_FromPool(_GetDescriptor(self)->file()->pool()), _GetDescriptor(self))); Py_XINCREF(concrete_class); - return concrete_class; + return concrete_class->AsPyObject(); } static PyObject* GetFieldsByName(PyBaseDescriptor* self, void *closure) { diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc index 0bc76bc9..1faff96b 100644 --- a/python/google/protobuf/pyext/descriptor_pool.cc +++ b/python/google/protobuf/pyext/descriptor_pool.cc @@ -190,8 +190,8 @@ PyObject* FindMessageByName(PyDescriptorPool* self, PyObject* arg) { // Add a message class to our database. int RegisterMessageClass(PyDescriptorPool* self, - const Descriptor *message_descriptor, - PyObject *message_class) { + const Descriptor* message_descriptor, + CMessageClass* message_class) { Py_INCREF(message_class); typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator; std::pair ret = self->classes_by_descriptor->insert( @@ -205,8 +205,8 @@ int RegisterMessageClass(PyDescriptorPool* self, } // Retrieve the message class added to our database. -PyObject *GetMessageClass(PyDescriptorPool* self, - const Descriptor *message_descriptor) { +CMessageClass* GetMessageClass(PyDescriptorPool* self, + const Descriptor* message_descriptor) { typedef PyDescriptorPool::ClassesByMessageMap::iterator iterator; iterator ret = self->classes_by_descriptor->find(message_descriptor); if (ret == self->classes_by_descriptor->end()) { diff --git a/python/google/protobuf/pyext/descriptor_pool.h b/python/google/protobuf/pyext/descriptor_pool.h index 16bc910c..2a42c112 100644 --- a/python/google/protobuf/pyext/descriptor_pool.h +++ b/python/google/protobuf/pyext/descriptor_pool.h @@ -42,6 +42,9 @@ class MessageFactory; namespace python { +// The (meta) type of all Messages classes. +struct CMessageClass; + // Wraps operations to the global DescriptorPool which contains information // about all messages and fields. // @@ -78,7 +81,7 @@ typedef struct PyDescriptorPool { // // Descriptor pointers stored here are owned by the DescriptorPool above. // Python references to classes are owned by this PyDescriptorPool. - typedef hash_map ClassesByMessageMap; + typedef hash_map ClassesByMessageMap; ClassesByMessageMap* classes_by_descriptor; // Cache the options for any kind of descriptor. @@ -101,14 +104,14 @@ const Descriptor* FindMessageTypeByName(PyDescriptorPool* self, // On error, returns -1 with a Python exception set. int RegisterMessageClass(PyDescriptorPool* self, const Descriptor* message_descriptor, - PyObject* message_class); + CMessageClass* message_class); // Retrieves the Python class registered with the given message descriptor. // // Returns a *borrowed* reference if found, otherwise returns NULL with an // exception set. -PyObject* GetMessageClass(PyDescriptorPool* self, - const Descriptor* message_descriptor); +CMessageClass* GetMessageClass(PyDescriptorPool* self, + const Descriptor* message_descriptor); // The functions below are also exposed as methods of the DescriptorPool type. diff --git a/python/google/protobuf/pyext/extension_dict.cc b/python/google/protobuf/pyext/extension_dict.cc index 555bd293..21bbb8c2 100644 --- a/python/google/protobuf/pyext/extension_dict.cc +++ b/python/google/protobuf/pyext/extension_dict.cc @@ -130,7 +130,7 @@ PyObject* subscript(ExtensionDict* self, PyObject* key) { if (descriptor->label() == FieldDescriptor::LABEL_REPEATED) { if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject *message_class = cdescriptor_pool::GetMessageClass( + CMessageClass* message_class = cdescriptor_pool::GetMessageClass( cmessage::GetDescriptorPoolForMessage(self->parent), descriptor->message_type()); if (message_class == NULL) { @@ -239,6 +239,21 @@ PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name) { } } +PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number) { + ScopedPyObjectPtr extensions_by_number(PyObject_GetAttrString( + reinterpret_cast(self->parent), "_extensions_by_number")); + if (extensions_by_number == NULL) { + return NULL; + } + PyObject* result = PyDict_GetItem(extensions_by_number.get(), number); + if (result == NULL) { + Py_RETURN_NONE; + } else { + Py_INCREF(result); + return result; + } +} + ExtensionDict* NewExtensionDict(CMessage *parent) { ExtensionDict* self = reinterpret_cast( PyType_GenericAlloc(&ExtensionDict_Type, 0)); @@ -271,6 +286,8 @@ static PyMethodDef Methods[] = { EDMETHOD(HasExtension, METH_O, "Checks if the object has an extension."), EDMETHOD(_FindExtensionByName, METH_O, "Finds an extension by name."), + EDMETHOD(_FindExtensionByNumber, METH_O, + "Finds an extension by field number."), { NULL, NULL } }; diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h index 1e7f6f7b..049d2e45 100644 --- a/python/google/protobuf/pyext/extension_dict.h +++ b/python/google/protobuf/pyext/extension_dict.h @@ -123,6 +123,12 @@ PyObject* ClearExtension(ExtensionDict* self, // Returns a new reference. PyObject* _FindExtensionByName(ExtensionDict* self, PyObject* name); +// Gets an extension from the dict given the extension field number as +// opposed to descriptor. +// +// Returns a new reference. +PyObject* _FindExtensionByNumber(ExtensionDict* self, PyObject* number); + } // namespace extension_dict } // namespace python } // namespace protobuf diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc index df9138a4..e022406d 100644 --- a/python/google/protobuf/pyext/map_container.cc +++ b/python/google/protobuf/pyext/map_container.cc @@ -32,6 +32,11 @@ #include +#include +#ifndef _SHARED_PTR_H +#include +#endif + #include #include #include @@ -70,7 +75,7 @@ class MapReflectionFriend { struct MapIterator { PyObject_HEAD; - scoped_ptr< ::google::protobuf::MapIterator> iter; + google::protobuf::scoped_ptr< ::google::protobuf::MapIterator> iter; // A pointer back to the container, so we can notice changes to the version. // We own a ref on this. @@ -610,8 +615,7 @@ static PyObject* GetCMessage(MessageMapContainer* self, Message* message) { PyObject* ret = PyDict_GetItem(self->message_dict, key.get()); if (ret == NULL) { - CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init, - message->GetDescriptor()); + CMessage* cmsg = cmessage::NewEmptyMessage(self->message_class); ret = reinterpret_cast(cmsg); if (cmsg == NULL) { @@ -634,7 +638,7 @@ static PyObject* GetCMessage(MessageMapContainer* self, Message* message) { PyObject* NewMessageMapContainer( CMessage* parent, const google::protobuf::FieldDescriptor* parent_field_descriptor, - PyObject* concrete_class) { + CMessageClass* message_class) { if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { return NULL; } @@ -669,8 +673,8 @@ PyObject* NewMessageMapContainer( "Could not allocate message dict."); } - Py_INCREF(concrete_class); - self->subclass_init = concrete_class; + Py_INCREF(message_class); + self->message_class = message_class; if (self->key_field_descriptor == NULL || self->value_field_descriptor == NULL) { @@ -763,6 +767,7 @@ static void MessageMapDealloc(PyObject* _self) { MessageMapContainer* self = GetMessageMap(_self); self->owner.reset(); Py_DECREF(self->message_dict); + Py_DECREF(self->message_class); Py_TYPE(_self)->tp_free(_self); } diff --git a/python/google/protobuf/pyext/map_container.h b/python/google/protobuf/pyext/map_container.h index 27ee6dbd..b11dfa34 100644 --- a/python/google/protobuf/pyext/map_container.h +++ b/python/google/protobuf/pyext/map_container.h @@ -55,6 +55,7 @@ using internal::shared_ptr; namespace python { struct CMessage; +struct CMessageClass; // This struct is used directly for ScalarMap, and is the base class of // MessageMapContainer, which is used for MessageMap. @@ -104,8 +105,8 @@ struct MapContainer { }; struct MessageMapContainer : public MapContainer { - // A callable that is used to create new child messages. - PyObject* subclass_init; + // The type used to create new child messages. + CMessageClass* message_class; // A dict mapping Message* -> CMessage. PyObject* message_dict; @@ -132,7 +133,7 @@ extern PyObject* NewScalarMapContainer( // field descriptor. extern PyObject* NewMessageMapContainer( CMessage* parent, const FieldDescriptor* parent_field_descriptor, - PyObject* concrete_class); + CMessageClass* message_class); } // namespace python } // namespace protobuf diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 6d7b2b0f..83c151ff 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc @@ -98,31 +98,6 @@ static PyObject* PythonMessage_class; static PyObject* kEmptyWeakref; static PyObject* WKT_classes = NULL; -// Defines the Metaclass of all Message classes. -// It allows us to cache some C++ pointers in the class object itself, they are -// faster to extract than from the type's dictionary. - -struct PyMessageMeta { - // This is how CPython subclasses C structures: the base structure must be - // the first member of the object. - PyHeapTypeObject super; - - // C++ descriptor of this message. - const Descriptor* message_descriptor; - - // Owned reference, used to keep the pointer above alive. - PyObject* py_message_descriptor; - - // The Python DescriptorPool used to create the class. It is needed to resolve - // fields descriptors, including extensions fields; its C++ MessageFactory is - // used to instantiate submessages. - // This can be different from DESCRIPTOR.file.pool, in the case of a custom - // DescriptorPool which defines new extensions. - // We own the reference, because it's important to keep the descriptors and - // factory alive. - PyDescriptorPool* py_descriptor_pool; -}; - namespace message_meta { static int InsertEmptyWeakref(PyTypeObject* base); @@ -173,10 +148,6 @@ static int AddDescriptors(PyObject* cls, const Descriptor* descriptor) { } // For each enum set cls. = EnumTypeWrapper(). - // - // The enum descriptor we get from - // .enum_types_by_name[name] - // which was built previously. for (int i = 0; i < descriptor->enum_type_count(); ++i) { const EnumDescriptor* enum_descriptor = descriptor->enum_type(i); ScopedPyObjectPtr enum_type( @@ -309,7 +280,7 @@ static PyObject* New(PyTypeObject* type, if (result == NULL) { return NULL; } - PyMessageMeta* newtype = reinterpret_cast(result.get()); + CMessageClass* newtype = reinterpret_cast(result.get()); // Insert the empty weakref into the base classes. if (InsertEmptyWeakref( @@ -338,7 +309,7 @@ static PyObject* New(PyTypeObject* type, // Add the message to the DescriptorPool. if (cdescriptor_pool::RegisterMessageClass(newtype->py_descriptor_pool, - descriptor, result.get()) < 0) { + descriptor, newtype) < 0) { return NULL; } @@ -349,7 +320,7 @@ static PyObject* New(PyTypeObject* type, return result.release(); } -static void Dealloc(PyMessageMeta *self) { +static void Dealloc(CMessageClass *self) { Py_DECREF(self->py_message_descriptor); Py_DECREF(self->py_descriptor_pool); Py_TYPE(self)->tp_free(reinterpret_cast(self)); @@ -378,10 +349,10 @@ static int InsertEmptyWeakref(PyTypeObject *base_type) { } // namespace message_meta -PyTypeObject PyMessageMeta_Type = { +PyTypeObject CMessageClass_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) FULL_MODULE_NAME ".MessageMeta", // tp_name - sizeof(PyMessageMeta), // tp_basicsize + sizeof(CMessageClass), // tp_basicsize 0, // tp_itemsize (destructor)message_meta::Dealloc, // tp_dealloc 0, // tp_print @@ -419,16 +390,16 @@ PyTypeObject PyMessageMeta_Type = { message_meta::New, // tp_new }; -static PyMessageMeta* CheckMessageClass(PyTypeObject* cls) { - if (!PyObject_TypeCheck(cls, &PyMessageMeta_Type)) { +static CMessageClass* CheckMessageClass(PyTypeObject* cls) { + if (!PyObject_TypeCheck(cls, &CMessageClass_Type)) { PyErr_Format(PyExc_TypeError, "Class %s is not a Message", cls->tp_name); return NULL; } - return reinterpret_cast(cls); + return reinterpret_cast(cls); } static const Descriptor* GetMessageDescriptor(PyTypeObject* cls) { - PyMessageMeta* type = CheckMessageClass(cls); + CMessageClass* type = CheckMessageClass(cls); if (type == NULL) { return NULL; } @@ -783,9 +754,9 @@ namespace cmessage { PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message) { // No need to check the type: the type of instances of CMessage is always - // an instance of PyMessageMeta. Let's prove it with a debug-only check. + // an instance of CMessageClass. Let's prove it with a debug-only check. GOOGLE_DCHECK(PyObject_TypeCheck(message, &CMessage_Type)); - return reinterpret_cast(Py_TYPE(message))->py_descriptor_pool; + return reinterpret_cast(Py_TYPE(message))->py_descriptor_pool; } MessageFactory* GetFactoryForMessage(CMessage* message) { @@ -1090,6 +1061,10 @@ int InitAttributes(CMessage* self, PyObject* kwargs) { PyString_AsString(name)); return -1; } + if (value == Py_None) { + // field=None is the same as no field at all. + continue; + } if (descriptor->is_map()) { ScopedPyObjectPtr map(GetAttr(self, name)); const FieldDescriptor* value_descriptor = @@ -1220,9 +1195,9 @@ int InitAttributes(CMessage* self, PyObject* kwargs) { // Allocates an incomplete Python Message: the caller must fill self->message, // self->owner and eventually self->parent. -CMessage* NewEmptyMessage(PyObject* type, const Descriptor *descriptor) { +CMessage* NewEmptyMessage(CMessageClass* type) { CMessage* self = reinterpret_cast( - PyType_GenericAlloc(reinterpret_cast(type), 0)); + PyType_GenericAlloc(&type->super.ht_type, 0)); if (self == NULL) { return NULL; } @@ -1242,7 +1217,7 @@ CMessage* NewEmptyMessage(PyObject* type, const Descriptor *descriptor) { // Creates a new C++ message and takes ownership. static PyObject* New(PyTypeObject* cls, PyObject* unused_args, PyObject* unused_kwargs) { - PyMessageMeta* type = CheckMessageClass(cls); + CMessageClass* type = CheckMessageClass(cls); if (type == NULL) { return NULL; } @@ -1258,8 +1233,7 @@ static PyObject* New(PyTypeObject* cls, return NULL; } - CMessage* self = NewEmptyMessage(reinterpret_cast(type), - message_descriptor); + CMessage* self = NewEmptyMessage(type); if (self == NULL) { return NULL; } @@ -2023,10 +1997,34 @@ static PyObject* RegisterExtension(PyObject* cls, PyErr_SetString(PyExc_TypeError, "no extensions_by_number on class"); return NULL; } + ScopedPyObjectPtr number(PyObject_GetAttrString(extension_handle, "number")); if (number == NULL) { return NULL; } + + // If the extension was already registered by number, check that it is the + // same. + existing_extension = PyDict_GetItem(extensions_by_number.get(), number.get()); + if (existing_extension != NULL) { + const FieldDescriptor* existing_extension_descriptor = + GetExtensionDescriptor(existing_extension); + if (existing_extension_descriptor != descriptor) { + const Descriptor* msg_desc = GetMessageDescriptor( + reinterpret_cast(cls)); + PyErr_Format( + PyExc_ValueError, + "Extensions \"%s\" and \"%s\" both try to extend message type " + "\"%s\" with field number %ld.", + existing_extension_descriptor->full_name().c_str(), + descriptor->full_name().c_str(), + msg_desc->full_name().c_str(), + PyInt_AsLong(number.get())); + return NULL; + } + // Nothing else to do. + Py_RETURN_NONE; + } if (PyDict_SetItem(extensions_by_number.get(), number.get(), extension_handle) < 0) { return NULL; @@ -2166,6 +2164,12 @@ static PyObject* ListFields(CMessage* self) { return all_fields.release(); } +static PyObject* DiscardUnknownFields(CMessage* self) { + AssureWritable(self); + self->message->DiscardUnknownFields(); + Py_RETURN_NONE; +} + PyObject* FindInitializationErrors(CMessage* self) { Message* message = self->message; vector errors; @@ -2309,14 +2313,13 @@ PyObject* InternalGetSubMessage( const Message& sub_message = reflection->GetMessage( *self->message, field_descriptor, pool->message_factory); - PyObject *message_class = cdescriptor_pool::GetMessageClass( + CMessageClass* message_class = cdescriptor_pool::GetMessageClass( pool, field_descriptor->message_type()); if (message_class == NULL) { return NULL; } - CMessage* cmsg = cmessage::NewEmptyMessage(message_class, - sub_message.GetDescriptor()); + CMessage* cmsg = cmessage::NewEmptyMessage(message_class); if (cmsg == NULL) { return NULL; } @@ -2585,6 +2588,8 @@ static PyMethodDef Methods[] = { "Clears a message field." }, { "CopyFrom", (PyCFunction)CopyFrom, METH_O, "Copies a protocol message into the current message." }, + { "DiscardUnknownFields", (PyCFunction)DiscardUnknownFields, METH_NOARGS, + "Discards the unknown fields." }, { "FindInitializationErrors", (PyCFunction)FindInitializationErrors, METH_NOARGS, "Finds unset required fields." }, @@ -2654,7 +2659,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { const Descriptor* entry_type = field_descriptor->message_type(); const FieldDescriptor* value_type = entry_type->FindFieldByName("value"); if (value_type->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject* value_class = cdescriptor_pool::GetMessageClass( + CMessageClass* value_class = cdescriptor_pool::GetMessageClass( GetDescriptorPoolForMessage(self), value_type->message_type()); if (value_class == NULL) { return NULL; @@ -2677,7 +2682,7 @@ PyObject* GetAttr(CMessage* self, PyObject* name) { if (field_descriptor->label() == FieldDescriptor::LABEL_REPEATED) { PyObject* py_container = NULL; if (field_descriptor->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - PyObject *message_class = cdescriptor_pool::GetMessageClass( + CMessageClass* message_class = cdescriptor_pool::GetMessageClass( GetDescriptorPoolForMessage(self), field_descriptor->message_type()); if (message_class == NULL) { return NULL; @@ -2749,7 +2754,7 @@ int SetAttr(CMessage* self, PyObject* name, PyObject* value) { } // namespace cmessage PyTypeObject CMessage_Type = { - PyVarObject_HEAD_INIT(&PyMessageMeta_Type, 0) + PyVarObject_HEAD_INIT(&CMessageClass_Type, 0) FULL_MODULE_NAME ".CMessage", // tp_name sizeof(CMessage), // tp_basicsize 0, // tp_itemsize @@ -2864,12 +2869,12 @@ bool InitProto2MessageModule(PyObject *m) { // Initialize constants defined in this file. InitGlobals(); - PyMessageMeta_Type.tp_base = &PyType_Type; - if (PyType_Ready(&PyMessageMeta_Type) < 0) { + CMessageClass_Type.tp_base = &PyType_Type; + if (PyType_Ready(&CMessageClass_Type) < 0) { return false; } PyModule_AddObject(m, "MessageMeta", - reinterpret_cast(&PyMessageMeta_Type)); + reinterpret_cast(&CMessageClass_Type)); if (PyType_Ready(&CMessage_Type) < 0) { return false; @@ -3077,9 +3082,10 @@ bool InitProto2MessageModule(PyObject *m) { } // namespace protobuf static PyMethodDef ModuleMethods[] = { - {"SetAllowOversizeProtos", - (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos, - METH_O, "Enable/disable oversize proto parsing."}, + {"SetAllowOversizeProtos", + (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos, + METH_O, "Enable/disable oversize proto parsing."}, + { NULL, NULL} }; #if PY_MAJOR_VERSION >= 3 diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index c2b62649..9dce198f 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -116,12 +116,43 @@ typedef struct CMessage { extern PyTypeObject CMessage_Type; + +// The (meta) type of all Messages classes. +// It allows us to cache some C++ pointers in the class object itself, they are +// faster to extract than from the type's dictionary. + +struct CMessageClass { + // This is how CPython subclasses C structures: the base structure must be + // the first member of the object. + PyHeapTypeObject super; + + // C++ descriptor of this message. + const Descriptor* message_descriptor; + + // Owned reference, used to keep the pointer above alive. + PyObject* py_message_descriptor; + + // The Python DescriptorPool used to create the class. It is needed to resolve + // fields descriptors, including extensions fields; its C++ MessageFactory is + // used to instantiate submessages. + // This can be different from DESCRIPTOR.file.pool, in the case of a custom + // DescriptorPool which defines new extensions. + // We own the reference, because it's important to keep the descriptors and + // factory alive. + PyDescriptorPool* py_descriptor_pool; + + PyObject* AsPyObject() { + return reinterpret_cast(this); + } +}; + + namespace cmessage { // Internal function to create a new empty Message Python object, but with empty // pointers to the C++ objects. // The caller must fill self->message, self->owner and eventually self->parent. -CMessage* NewEmptyMessage(PyObject* type, const Descriptor* descriptor); +CMessage* NewEmptyMessage(CMessageClass* type); // Release a submessage from its proto tree, making it a new top-level messgae. // A new message will be created if this is a read-only default instance. diff --git a/python/google/protobuf/pyext/repeated_composite_container.cc b/python/google/protobuf/pyext/repeated_composite_container.cc index b01123b4..4f339e77 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.cc +++ b/python/google/protobuf/pyext/repeated_composite_container.cc @@ -107,8 +107,7 @@ static int UpdateChildMessages(RepeatedCompositeContainer* self) { for (Py_ssize_t i = child_length; i < message_length; ++i) { const Message& sub_message = reflection->GetRepeatedMessage( *(self->message), self->parent_field_descriptor, i); - CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init, - sub_message.GetDescriptor()); + CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class); ScopedPyObjectPtr py_cmsg(reinterpret_cast(cmsg)); if (cmsg == NULL) { return -1; @@ -140,8 +139,7 @@ static PyObject* AddToAttached(RepeatedCompositeContainer* self, Message* sub_message = message->GetReflection()->AddMessage(message, self->parent_field_descriptor); - CMessage* cmsg = cmessage::NewEmptyMessage(self->subclass_init, - sub_message->GetDescriptor()); + CMessage* cmsg = cmessage::NewEmptyMessage(self->child_message_class); if (cmsg == NULL) return NULL; @@ -168,7 +166,7 @@ static PyObject* AddToReleased(RepeatedCompositeContainer* self, // Create a new Message detached from the rest. PyObject* py_cmsg = PyEval_CallObjectWithKeywords( - self->subclass_init, NULL, kwargs); + self->child_message_class->AsPyObject(), NULL, kwargs); if (py_cmsg == NULL) return NULL; @@ -506,7 +504,7 @@ int SetOwner(RepeatedCompositeContainer* self, PyObject *NewContainer( CMessage* parent, const FieldDescriptor* parent_field_descriptor, - PyObject *concrete_class) { + CMessageClass* concrete_class) { if (!CheckFieldBelongsToMessage(parent_field_descriptor, parent->message)) { return NULL; } @@ -523,7 +521,7 @@ PyObject *NewContainer( self->parent_field_descriptor = parent_field_descriptor; self->owner = parent->owner; Py_INCREF(concrete_class); - self->subclass_init = concrete_class; + self->child_message_class = concrete_class; self->child_messages = PyList_New(0); return reinterpret_cast(self); @@ -531,7 +529,7 @@ PyObject *NewContainer( static void Dealloc(RepeatedCompositeContainer* self) { Py_CLEAR(self->child_messages); - Py_CLEAR(self->subclass_init); + Py_CLEAR(self->child_message_class); // TODO(tibell): Do we need to call delete on these objects to make // sure their destructors are called? self->owner.reset(); diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h index 442ce7e3..25463037 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.h +++ b/python/google/protobuf/pyext/repeated_composite_container.h @@ -58,6 +58,7 @@ using internal::shared_ptr; namespace python { struct CMessage; +struct CMessageClass; // A RepeatedCompositeContainer can be in one of two states: attached // or released. @@ -94,8 +95,8 @@ typedef struct RepeatedCompositeContainer { // calling Clear() or ClearField() on the parent. Message* message; - // A callable that is used to create new child messages. - PyObject* subclass_init; + // The type used to create new child messages. + CMessageClass* child_message_class; // A list of child messages. PyObject* child_messages; @@ -110,7 +111,7 @@ namespace repeated_composite_container { PyObject *NewContainer( CMessage* parent, const FieldDescriptor* parent_field_descriptor, - PyObject *concrete_class); + CMessageClass *child_message_class); // Appends a new CMessage to the container and returns it. The // CMessage is initialized using the content of kwargs. diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py index a6f41ca8..6f1e3c8b 100755 --- a/python/google/protobuf/text_format.py +++ b/python/google/protobuf/text_format.py @@ -99,7 +99,7 @@ class TextWriter(object): def MessageToString(message, as_utf8=False, as_one_line=False, pointy_brackets=False, use_index_order=False, - float_format=None): + float_format=None, use_field_number=False): """Convert protobuf message to text format. Floating point values can be formatted compactly with 15 digits of @@ -118,15 +118,16 @@ def MessageToString(message, as_utf8=False, as_one_line=False, field number order. float_format: If set, use this to specify floating point number formatting (per the "Format Specification Mini-Language"); otherwise, str() is used. + use_field_number: If True, print field numbers instead of names. Returns: A string of the text formatted protocol buffer message. """ out = TextWriter(as_utf8) - PrintMessage(message, out, as_utf8=as_utf8, as_one_line=as_one_line, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, - float_format=float_format) + printer = _Printer(out, 0, as_utf8, as_one_line, + pointy_brackets, use_index_order, float_format, + use_field_number) + printer.PrintMessage(message) result = out.getvalue() out.close() if as_one_line: @@ -142,133 +143,187 @@ def _IsMapEntry(field): def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False, pointy_brackets=False, use_index_order=False, - float_format=None): - fields = message.ListFields() - if use_index_order: - fields.sort(key=lambda x: x[0].index) - for field, value in fields: - if _IsMapEntry(field): - for key in sorted(value): - # This is slow for maps with submessage entires because it copies the - # entire tree. Unfortunately this would take significant refactoring - # of this file to work around. - # - # TODO(haberman): refactor and optimize if this becomes an issue. - entry_submsg = field.message_type._concrete_class( - key=key, value=value[key]) - PrintField(field, entry_submsg, out, indent, as_utf8, as_one_line, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, float_format=float_format) - elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - for element in value: - PrintField(field, element, out, indent, as_utf8, as_one_line, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, - float_format=float_format) - else: - PrintField(field, value, out, indent, as_utf8, as_one_line, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, - float_format=float_format) + float_format=None, use_field_number=False): + printer = _Printer(out, indent, as_utf8, as_one_line, + pointy_brackets, use_index_order, float_format, + use_field_number) + printer.PrintMessage(message) def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False, pointy_brackets=False, use_index_order=False, float_format=None): - """Print a single field name/value pair. For repeated fields, the value - should be a single element. - """ - - out.write(' ' * indent) - if field.is_extension: - out.write('[') - if (field.containing_type.GetOptions().message_set_wire_format and - field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and - field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL): - out.write(field.message_type.full_name) - else: - out.write(field.full_name) - out.write(']') - elif field.type == descriptor.FieldDescriptor.TYPE_GROUP: - # For groups, use the capitalized name. - out.write(field.message_type.name) - else: - out.write(field.name) - - if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - # The colon is optional in this case, but our cross-language golden files - # don't include it. - out.write(': ') - - PrintFieldValue(field, value, out, indent, as_utf8, as_one_line, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, - float_format=float_format) - if as_one_line: - out.write(' ') - else: - out.write('\n') + """Print a single field name/value pair.""" + printer = _Printer(out, indent, as_utf8, as_one_line, + pointy_brackets, use_index_order, float_format) + printer.PrintField(field, value) def PrintFieldValue(field, value, out, indent=0, as_utf8=False, as_one_line=False, pointy_brackets=False, use_index_order=False, float_format=None): - """Print a single field value (not including name). For repeated fields, - the value should be a single element.""" + """Print a single field value (not including name).""" + printer = _Printer(out, indent, as_utf8, as_one_line, + pointy_brackets, use_index_order, float_format) + printer.PrintFieldValue(field, value) - if pointy_brackets: - openb = '<' - closeb = '>' - else: - openb = '{' - closeb = '}' - if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - if as_one_line: - out.write(' %s ' % openb) - PrintMessage(value, out, indent, as_utf8, as_one_line, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, - float_format=float_format) - out.write(closeb) +class _Printer(object): + """Text format printer for protocol message.""" + + def __init__(self, out, indent=0, as_utf8=False, as_one_line=False, + pointy_brackets=False, use_index_order=False, float_format=None, + use_field_number=False): + """Initialize the Printer. + + Floating point values can be formatted compactly with 15 digits of + precision (which is the most that IEEE 754 "double" can guarantee) + using float_format='.15g'. To ensure that converting to text and back to a + proto will result in an identical value, float_format='.17g' should be used. + + Args: + out: To record the text format result. + indent: The indent level for pretty print. + as_utf8: Produce text output in UTF8 format. + as_one_line: Don't introduce newlines between fields. + pointy_brackets: If True, use angle brackets instead of curly braces for + nesting. + use_index_order: If True, print fields of a proto message using the order + defined in source code instead of the field number. By default, use the + field number order. + float_format: If set, use this to specify floating point number formatting + (per the "Format Specification Mini-Language"); otherwise, str() is + used. + use_field_number: If True, print field numbers instead of names. + """ + self.out = out + self.indent = indent + self.as_utf8 = as_utf8 + self.as_one_line = as_one_line + self.pointy_brackets = pointy_brackets + self.use_index_order = use_index_order + self.float_format = float_format + self.use_field_number = use_field_number + + def PrintMessage(self, message): + """Convert protobuf message to text format. + + Args: + message: The protocol buffers message. + """ + fields = message.ListFields() + if self.use_index_order: + fields.sort(key=lambda x: x[0].index) + for field, value in fields: + if _IsMapEntry(field): + for key in sorted(value): + # This is slow for maps with submessage entires because it copies the + # entire tree. Unfortunately this would take significant refactoring + # of this file to work around. + # + # TODO(haberman): refactor and optimize if this becomes an issue. + entry_submsg = field.message_type._concrete_class( + key=key, value=value[key]) + self.PrintField(field, entry_submsg) + elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + for element in value: + self.PrintField(field, element) + else: + self.PrintField(field, value) + + def PrintField(self, field, value): + """Print a single field name/value pair.""" + out = self.out + out.write(' ' * self.indent) + if self.use_field_number: + out.write(str(field.number)) else: - out.write(' %s\n' % openb) - PrintMessage(value, out, indent + 2, as_utf8, as_one_line, - pointy_brackets=pointy_brackets, - use_index_order=use_index_order, - float_format=float_format) - out.write(' ' * indent + closeb) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: - enum_value = field.enum_type.values_by_number.get(value, None) - if enum_value is not None: - out.write(enum_value.name) + if field.is_extension: + out.write('[') + if (field.containing_type.GetOptions().message_set_wire_format and + field.type == descriptor.FieldDescriptor.TYPE_MESSAGE and + field.label == descriptor.FieldDescriptor.LABEL_OPTIONAL): + out.write(field.message_type.full_name) + else: + out.write(field.full_name) + out.write(']') + elif field.type == descriptor.FieldDescriptor.TYPE_GROUP: + # For groups, use the capitalized name. + out.write(field.message_type.name) + else: + out.write(field.name) + + if field.cpp_type != descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + # The colon is optional in this case, but our cross-language golden files + # don't include it. + out.write(': ') + + self.PrintFieldValue(field, value) + if self.as_one_line: + out.write(' ') + else: + out.write('\n') + + def PrintFieldValue(self, field, value): + """Print a single field value (not including name). + + For repeated fields, the value should be a single element. + + Args: + field: The descriptor of the field to be printed. + value: The value of the field. + """ + out = self.out + if self.pointy_brackets: + openb = '<' + closeb = '>' + else: + openb = '{' + closeb = '}' + + if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + if self.as_one_line: + out.write(' %s ' % openb) + self.PrintMessage(value) + out.write(closeb) + else: + out.write(' %s\n' % openb) + self.indent += 2 + self.PrintMessage(value) + self.indent -= 2 + out.write(' ' * self.indent + closeb) + elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM: + enum_value = field.enum_type.values_by_number.get(value, None) + if enum_value is not None: + out.write(enum_value.name) + else: + out.write(str(value)) + elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: + out.write('\"') + if isinstance(value, six.text_type): + out_value = value.encode('utf-8') + else: + out_value = value + if field.type == descriptor.FieldDescriptor.TYPE_BYTES: + # We need to escape non-UTF8 chars in TYPE_BYTES field. + out_as_utf8 = False + else: + out_as_utf8 = self.as_utf8 + out.write(text_encoding.CEscape(out_value, out_as_utf8)) + out.write('\"') + elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: + if value: + out.write('true') + else: + out.write('false') + elif field.cpp_type in _FLOAT_TYPES and self.float_format is not None: + out.write('{1:{0}}'.format(self.float_format, value)) else: out.write(str(value)) - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING: - out.write('\"') - if isinstance(value, six.text_type): - out_value = value.encode('utf-8') - else: - out_value = value - if field.type == descriptor.FieldDescriptor.TYPE_BYTES: - # We need to escape non-UTF8 chars in TYPE_BYTES field. - out_as_utf8 = False - else: - out_as_utf8 = as_utf8 - out.write(text_encoding.CEscape(out_value, out_as_utf8)) - out.write('\"') - elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL: - if value: - out.write('true') - else: - out.write('false') - elif field.cpp_type in _FLOAT_TYPES and float_format is not None: - out.write('{1:{0}}'.format(float_format, value)) - else: - out.write(str(value)) -def Parse(text, message, allow_unknown_extension=False): +def Parse(text, message, + allow_unknown_extension=False, allow_field_number=False): """Parses an text representation of a protocol message into a message. Args: @@ -276,6 +331,7 @@ def Parse(text, message, allow_unknown_extension=False): message: A protocol buffer message to merge into. allow_unknown_extension: if True, skip over missing extensions and keep parsing + allow_field_number: if True, both field number and field name are allowed. Returns: The same message passed as argument. @@ -285,10 +341,12 @@ def Parse(text, message, allow_unknown_extension=False): """ if not isinstance(text, str): text = text.decode('utf-8') - return ParseLines(text.split('\n'), message, allow_unknown_extension) + return ParseLines(text.split('\n'), message, allow_unknown_extension, + allow_field_number) -def Merge(text, message, allow_unknown_extension=False): +def Merge(text, message, allow_unknown_extension=False, + allow_field_number=False): """Parses an text representation of a protocol message into a message. Like Parse(), but allows repeated values for a non-repeated field, and uses @@ -299,6 +357,7 @@ def Merge(text, message, allow_unknown_extension=False): message: A protocol buffer message to merge into. allow_unknown_extension: if True, skip over missing extensions and keep parsing + allow_field_number: if True, both field number and field name are allowed. Returns: The same message passed as argument. @@ -306,10 +365,12 @@ def Merge(text, message, allow_unknown_extension=False): Raises: ParseError: On text parsing problems. """ - return MergeLines(text.split('\n'), message, allow_unknown_extension) + return MergeLines(text.split('\n'), message, allow_unknown_extension, + allow_field_number) -def ParseLines(lines, message, allow_unknown_extension=False): +def ParseLines(lines, message, allow_unknown_extension=False, + allow_field_number=False): """Parses an text representation of a protocol message into a message. Args: @@ -317,6 +378,7 @@ def ParseLines(lines, message, allow_unknown_extension=False): message: A protocol buffer message to merge into. allow_unknown_extension: if True, skip over missing extensions and keep parsing + allow_field_number: if True, both field number and field name are allowed. Returns: The same message passed as argument. @@ -324,11 +386,12 @@ def ParseLines(lines, message, allow_unknown_extension=False): Raises: ParseError: On text parsing problems. """ - _ParseOrMerge(lines, message, False, allow_unknown_extension) - return message + parser = _Parser(allow_unknown_extension, allow_field_number) + return parser.ParseLines(lines, message) -def MergeLines(lines, message, allow_unknown_extension=False): +def MergeLines(lines, message, allow_unknown_extension=False, + allow_field_number=False): """Parses an text representation of a protocol message into a message. Args: @@ -336,6 +399,7 @@ def MergeLines(lines, message, allow_unknown_extension=False): message: A protocol buffer message to merge into. allow_unknown_extension: if True, skip over missing extensions and keep parsing + allow_field_number: if True, both field number and field name are allowed. Returns: The same message passed as argument. @@ -343,146 +407,272 @@ def MergeLines(lines, message, allow_unknown_extension=False): Raises: ParseError: On text parsing problems. """ - _ParseOrMerge(lines, message, True, allow_unknown_extension) - return message + parser = _Parser(allow_unknown_extension, allow_field_number) + return parser.MergeLines(lines, message) -def _ParseOrMerge(lines, - message, - allow_multiple_scalars, - allow_unknown_extension=False): - """Converts an text representation of a protocol message into a message. +class _Parser(object): + """Text format parser for protocol message.""" - Args: - lines: Lines of a message's text representation. - message: A protocol buffer message to merge into. - allow_multiple_scalars: Determines if repeated values for a non-repeated - field are permitted, e.g., the string "foo: 1 foo: 2" for a - required/optional field named "foo". - allow_unknown_extension: if True, skip over missing extensions and keep - parsing + def __init__(self, allow_unknown_extension=False, allow_field_number=False): + self.allow_unknown_extension = allow_unknown_extension + self.allow_field_number = allow_field_number - Raises: - ParseError: On text parsing problems. - """ - tokenizer = _Tokenizer(lines) - while not tokenizer.AtEnd(): - _MergeField(tokenizer, message, allow_multiple_scalars, - allow_unknown_extension) + def ParseFromString(self, text, message): + """Parses an text representation of a protocol message into a message.""" + if not isinstance(text, str): + text = text.decode('utf-8') + return self.ParseLines(text.split('\n'), message) + def ParseLines(self, lines, message): + """Parses an text representation of a protocol message into a message.""" + self._allow_multiple_scalars = False + self._ParseOrMerge(lines, message) + return message -def _MergeField(tokenizer, - message, - allow_multiple_scalars, - allow_unknown_extension=False): - """Merges a single protocol message field into a message. + def MergeFromString(self, text, message): + """Merges an text representation of a protocol message into a message.""" + return self._MergeLines(text.split('\n'), message) - Args: - tokenizer: A tokenizer to parse the field name and values. - message: A protocol message to record the data. - allow_multiple_scalars: Determines if repeated values for a non-repeated - field are permitted, e.g., the string "foo: 1 foo: 2" for a - required/optional field named "foo". - allow_unknown_extension: if True, skip over missing extensions and keep - parsing. + def MergeLines(self, lines, message): + """Merges an text representation of a protocol message into a message.""" + self._allow_multiple_scalars = True + self._ParseOrMerge(lines, message) + return message - Raises: - ParseError: In case of text parsing problems. - """ - message_descriptor = message.DESCRIPTOR - if (hasattr(message_descriptor, 'syntax') and - message_descriptor.syntax == 'proto3'): - # Proto3 doesn't represent presence so we can't test if multiple - # scalars have occurred. We have to allow them. - allow_multiple_scalars = True - if tokenizer.TryConsume('['): - name = [tokenizer.ConsumeIdentifier()] - while tokenizer.TryConsume('.'): - name.append(tokenizer.ConsumeIdentifier()) - name = '.'.join(name) + def _ParseOrMerge(self, lines, message): + """Converts an text representation of a protocol message into a message. - if not message_descriptor.is_extendable: - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" does not have extensions.' % - message_descriptor.full_name) - # pylint: disable=protected-access - field = message.Extensions._FindExtensionByName(name) - # pylint: enable=protected-access - if not field: - if allow_unknown_extension: - field = None + Args: + lines: Lines of a message's text representation. + message: A protocol buffer message to merge into. + + Raises: + ParseError: On text parsing problems. + """ + tokenizer = _Tokenizer(lines) + while not tokenizer.AtEnd(): + self._MergeField(tokenizer, message) + + def _MergeField(self, tokenizer, message): + """Merges a single protocol message field into a message. + + Args: + tokenizer: A tokenizer to parse the field name and values. + message: A protocol message to record the data. + + Raises: + ParseError: In case of text parsing problems. + """ + message_descriptor = message.DESCRIPTOR + if (hasattr(message_descriptor, 'syntax') and + message_descriptor.syntax == 'proto3'): + # Proto3 doesn't represent presence so we can't test if multiple + # scalars have occurred. We have to allow them. + self._allow_multiple_scalars = True + if tokenizer.TryConsume('['): + name = [tokenizer.ConsumeIdentifier()] + while tokenizer.TryConsume('.'): + name.append(tokenizer.ConsumeIdentifier()) + name = '.'.join(name) + + if not message_descriptor.is_extendable: + raise tokenizer.ParseErrorPreviousToken( + 'Message type "%s" does not have extensions.' % + message_descriptor.full_name) + # pylint: disable=protected-access + field = message.Extensions._FindExtensionByName(name) + # pylint: enable=protected-access + if not field: + if self.allow_unknown_extension: + field = None + else: + raise tokenizer.ParseErrorPreviousToken( + 'Extension "%s" not registered.' % name) + elif message_descriptor != field.containing_type: + raise tokenizer.ParseErrorPreviousToken( + 'Extension "%s" does not extend message type "%s".' % ( + name, message_descriptor.full_name)) + + tokenizer.Consume(']') + + else: + name = tokenizer.ConsumeIdentifier() + if self.allow_field_number and name.isdigit(): + number = ParseInteger(name, True, True) + field = message_descriptor.fields_by_number.get(number, None) + if not field and message_descriptor.is_extendable: + field = message.Extensions._FindExtensionByNumber(number) else: + field = message_descriptor.fields_by_name.get(name, None) + + # Group names are expected to be capitalized as they appear in the + # .proto file, which actually matches their type names, not their field + # names. + if not field: + field = message_descriptor.fields_by_name.get(name.lower(), None) + if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP: + field = None + + if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and + field.message_type.name != name): + field = None + + if not field: raise tokenizer.ParseErrorPreviousToken( - 'Extension "%s" not registered.' % name) - elif message_descriptor != field.containing_type: - raise tokenizer.ParseErrorPreviousToken( - 'Extension "%s" does not extend message type "%s".' % ( - name, message_descriptor.full_name)) + 'Message type "%s" has no field named "%s".' % ( + message_descriptor.full_name, name)) - tokenizer.Consume(']') + if field: + if not self._allow_multiple_scalars and field.containing_oneof: + # Check if there's a different field set in this oneof. + # Note that we ignore the case if the same field was set before, and we + # apply _allow_multiple_scalars to non-scalar fields as well. + which_oneof = message.WhichOneof(field.containing_oneof.name) + if which_oneof is not None and which_oneof != field.name: + raise tokenizer.ParseErrorPreviousToken( + 'Field "%s" is specified along with field "%s", another member ' + 'of oneof "%s" for message type "%s".' % ( + field.name, which_oneof, field.containing_oneof.name, + message_descriptor.full_name)) - else: - name = tokenizer.ConsumeIdentifier() - field = message_descriptor.fields_by_name.get(name, None) + if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + tokenizer.TryConsume(':') + merger = self._MergeMessageField + else: + tokenizer.Consume(':') + merger = self._MergeScalarField - # Group names are expected to be capitalized as they appear in the - # .proto file, which actually matches their type names, not their field - # names. - if not field: - field = message_descriptor.fields_by_name.get(name.lower(), None) - if field and field.type != descriptor.FieldDescriptor.TYPE_GROUP: - field = None + if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED + and tokenizer.TryConsume('[')): + # Short repeated format, e.g. "foo: [1, 2, 3]" + while True: + merger(tokenizer, message, field) + if tokenizer.TryConsume(']'): break + tokenizer.Consume(',') - if (field and field.type == descriptor.FieldDescriptor.TYPE_GROUP and - field.message_type.name != name): - field = None + else: + merger(tokenizer, message, field) - if not field: - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" has no field named "%s".' % ( - message_descriptor.full_name, name)) + else: # Proto field is unknown. + assert self.allow_unknown_extension + _SkipFieldContents(tokenizer) - if field: - if not allow_multiple_scalars and field.containing_oneof: - # Check if there's a different field set in this oneof. - # Note that we ignore the case if the same field was set before, and we - # apply allow_multiple_scalars to non-scalar fields as well. - which_oneof = message.WhichOneof(field.containing_oneof.name) - if which_oneof is not None and which_oneof != field.name: - raise tokenizer.ParseErrorPreviousToken( - 'Field "%s" is specified along with field "%s", another member of ' - 'oneof "%s" for message type "%s".' % ( - field.name, which_oneof, field.containing_oneof.name, - message_descriptor.full_name)) + # For historical reasons, fields may optionally be separated by commas or + # semicolons. + if not tokenizer.TryConsume(','): + tokenizer.TryConsume(';') - if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - tokenizer.TryConsume(':') - merger = _MergeMessageField + def _MergeMessageField(self, tokenizer, message, field): + """Merges a single scalar field into a message. + + Args: + tokenizer: A tokenizer to parse the field value. + message: The message of which field is a member. + field: The descriptor of the field to be merged. + + Raises: + ParseError: In case of text parsing problems. + """ + is_map_entry = _IsMapEntry(field) + + if tokenizer.TryConsume('<'): + end_token = '>' else: - tokenizer.Consume(':') - merger = _MergeScalarField - - if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED - and tokenizer.TryConsume('[')): - # Short repeated format, e.g. "foo: [1, 2, 3]" - while True: - merger(tokenizer, message, field, allow_multiple_scalars, - allow_unknown_extension) - if tokenizer.TryConsume(']'): break - tokenizer.Consume(',') + tokenizer.Consume('{') + end_token = '}' + if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if field.is_extension: + sub_message = message.Extensions[field].add() + elif is_map_entry: + # pylint: disable=protected-access + sub_message = field.message_type._concrete_class() + else: + sub_message = getattr(message, field.name).add() else: - merger(tokenizer, message, field, allow_multiple_scalars, - allow_unknown_extension) + if field.is_extension: + sub_message = message.Extensions[field] + else: + sub_message = getattr(message, field.name) + sub_message.SetInParent() - else: # Proto field is unknown. - assert allow_unknown_extension - _SkipFieldContents(tokenizer) + while not tokenizer.TryConsume(end_token): + if tokenizer.AtEnd(): + raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token,)) + self._MergeField(tokenizer, sub_message) - # For historical reasons, fields may optionally be separated by commas or - # semicolons. - if not tokenizer.TryConsume(','): - tokenizer.TryConsume(';') + if is_map_entry: + value_cpptype = field.message_type.fields_by_name['value'].cpp_type + if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: + value = getattr(message, field.name)[sub_message.key] + value.MergeFrom(sub_message.value) + else: + getattr(message, field.name)[sub_message.key] = sub_message.value + + def _MergeScalarField(self, tokenizer, message, field): + """Merges a single scalar field into a message. + + Args: + tokenizer: A tokenizer to parse the field value. + message: A protocol message to record the data. + field: The descriptor of the field to be merged. + + Raises: + ParseError: In case of text parsing problems. + RuntimeError: On runtime errors. + """ + _ = self.allow_unknown_extension + value = None + + if field.type in (descriptor.FieldDescriptor.TYPE_INT32, + descriptor.FieldDescriptor.TYPE_SINT32, + descriptor.FieldDescriptor.TYPE_SFIXED32): + value = tokenizer.ConsumeInt32() + elif field.type in (descriptor.FieldDescriptor.TYPE_INT64, + descriptor.FieldDescriptor.TYPE_SINT64, + descriptor.FieldDescriptor.TYPE_SFIXED64): + value = tokenizer.ConsumeInt64() + elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32, + descriptor.FieldDescriptor.TYPE_FIXED32): + value = tokenizer.ConsumeUint32() + elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64, + descriptor.FieldDescriptor.TYPE_FIXED64): + value = tokenizer.ConsumeUint64() + elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT, + descriptor.FieldDescriptor.TYPE_DOUBLE): + value = tokenizer.ConsumeFloat() + elif field.type == descriptor.FieldDescriptor.TYPE_BOOL: + value = tokenizer.ConsumeBool() + elif field.type == descriptor.FieldDescriptor.TYPE_STRING: + value = tokenizer.ConsumeString() + elif field.type == descriptor.FieldDescriptor.TYPE_BYTES: + value = tokenizer.ConsumeByteString() + elif field.type == descriptor.FieldDescriptor.TYPE_ENUM: + value = tokenizer.ConsumeEnum(field) + else: + raise RuntimeError('Unknown field type %d' % field.type) + + if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: + if field.is_extension: + message.Extensions[field].append(value) + else: + getattr(message, field.name).append(value) + else: + if field.is_extension: + if not self._allow_multiple_scalars and message.HasExtension(field): + raise tokenizer.ParseErrorPreviousToken( + 'Message type "%s" should not have multiple "%s" extensions.' % + (message.DESCRIPTOR.full_name, field.full_name)) + else: + message.Extensions[field] = value + else: + if not self._allow_multiple_scalars and message.HasField(field.name): + raise tokenizer.ParseErrorPreviousToken( + 'Message type "%s" should not have multiple "%s" fields.' % + (message.DESCRIPTOR.full_name, field.name)) + else: + setattr(message, field.name, value) def _SkipFieldContents(tokenizer): @@ -555,10 +745,10 @@ def _SkipFieldValue(tokenizer): Raises: ParseError: In case an invalid field value is found. """ - # String tokens can come in multiple adjacent string literals. + # String/bytes tokens can come in multiple adjacent string literals. # If we can consume one, consume as many as we can. - if tokenizer.TryConsumeString(): - while tokenizer.TryConsumeString(): + if tokenizer.TryConsumeByteString(): + while tokenizer.TryConsumeByteString(): pass return @@ -569,132 +759,6 @@ def _SkipFieldValue(tokenizer): raise ParseError('Invalid field value: ' + tokenizer.token) -def _MergeMessageField(tokenizer, message, field, allow_multiple_scalars, - allow_unknown_extension): - """Merges a single scalar field into a message. - - Args: - tokenizer: A tokenizer to parse the field value. - message: The message of which field is a member. - field: The descriptor of the field to be merged. - allow_multiple_scalars: Determines if repeated values for a non-repeated - field are permitted, e.g., the string "foo: 1 foo: 2" for a - required/optional field named "foo". - allow_unknown_extension: if True, skip over missing extensions and keep - parsing. - - Raises: - ParseError: In case of text parsing problems. - """ - is_map_entry = _IsMapEntry(field) - - if tokenizer.TryConsume('<'): - end_token = '>' - else: - tokenizer.Consume('{') - end_token = '}' - - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - if field.is_extension: - sub_message = message.Extensions[field].add() - elif is_map_entry: - # pylint: disable=protected-access - sub_message = field.message_type._concrete_class() - else: - sub_message = getattr(message, field.name).add() - else: - if field.is_extension: - sub_message = message.Extensions[field] - else: - sub_message = getattr(message, field.name) - sub_message.SetInParent() - - while not tokenizer.TryConsume(end_token): - if tokenizer.AtEnd(): - raise tokenizer.ParseErrorPreviousToken('Expected "%s".' % (end_token,)) - _MergeField(tokenizer, sub_message, allow_multiple_scalars, - allow_unknown_extension) - - if is_map_entry: - value_cpptype = field.message_type.fields_by_name['value'].cpp_type - if value_cpptype == descriptor.FieldDescriptor.CPPTYPE_MESSAGE: - value = getattr(message, field.name)[sub_message.key] - value.MergeFrom(sub_message.value) - else: - getattr(message, field.name)[sub_message.key] = sub_message.value - - -def _MergeScalarField(tokenizer, message, field, allow_multiple_scalars, - allow_unknown_extension): - """Merges a single scalar field into a message. - - Args: - tokenizer: A tokenizer to parse the field value. - message: A protocol message to record the data. - field: The descriptor of the field to be merged. - allow_multiple_scalars: Determines if repeated values for a non-repeated - field are permitted, e.g., the string "foo: 1 foo: 2" for a - required/optional field named "foo". - allow_unknown_extension: Unused, just here for consistency with - _MergeMessageField. - - Raises: - ParseError: In case of text parsing problems. - RuntimeError: On runtime errors. - """ - _ = allow_unknown_extension - value = None - - if field.type in (descriptor.FieldDescriptor.TYPE_INT32, - descriptor.FieldDescriptor.TYPE_SINT32, - descriptor.FieldDescriptor.TYPE_SFIXED32): - value = tokenizer.ConsumeInt32() - elif field.type in (descriptor.FieldDescriptor.TYPE_INT64, - descriptor.FieldDescriptor.TYPE_SINT64, - descriptor.FieldDescriptor.TYPE_SFIXED64): - value = tokenizer.ConsumeInt64() - elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32, - descriptor.FieldDescriptor.TYPE_FIXED32): - value = tokenizer.ConsumeUint32() - elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64, - descriptor.FieldDescriptor.TYPE_FIXED64): - value = tokenizer.ConsumeUint64() - elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT, - descriptor.FieldDescriptor.TYPE_DOUBLE): - value = tokenizer.ConsumeFloat() - elif field.type == descriptor.FieldDescriptor.TYPE_BOOL: - value = tokenizer.ConsumeBool() - elif field.type == descriptor.FieldDescriptor.TYPE_STRING: - value = tokenizer.ConsumeString() - elif field.type == descriptor.FieldDescriptor.TYPE_BYTES: - value = tokenizer.ConsumeByteString() - elif field.type == descriptor.FieldDescriptor.TYPE_ENUM: - value = tokenizer.ConsumeEnum(field) - else: - raise RuntimeError('Unknown field type %d' % field.type) - - if field.label == descriptor.FieldDescriptor.LABEL_REPEATED: - if field.is_extension: - message.Extensions[field].append(value) - else: - getattr(message, field.name).append(value) - else: - if field.is_extension: - if not allow_multiple_scalars and message.HasExtension(field): - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" should not have multiple "%s" extensions.' % - (message.DESCRIPTOR.full_name, field.full_name)) - else: - message.Extensions[field] = value - else: - if not allow_multiple_scalars and message.HasField(field.name): - raise tokenizer.ParseErrorPreviousToken( - 'Message type "%s" should not have multiple "%s" fields.' % - (message.DESCRIPTOR.full_name, field.name)) - else: - setattr(message, field.name, value) - - class _Tokenizer(object): """Protocol buffer text representation tokenizer. @@ -925,9 +989,9 @@ class _Tokenizer(object): self.NextToken() return result - def TryConsumeString(self): + def TryConsumeByteString(self): try: - self.ConsumeString() + self.ConsumeByteString() return True except ParseError: return False diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc index e8878ba4..fbde4a6d 100644 --- a/src/google/protobuf/any.pb.cc +++ b/src/google/protobuf/any.pb.cc @@ -196,13 +196,14 @@ Any* Any::New(::google::protobuf::Arena* arena) const { } void Any::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Any) type_url_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); value_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } bool Any::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Any) for (;;) { @@ -308,6 +309,7 @@ void Any::SerializeWithCachedSizes( } int Any::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Any) int total_size = 0; // optional string type_url = 1; @@ -331,18 +333,22 @@ int Any::ByteSize() const { } void Any::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Any) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Any* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Any) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Any) MergeFrom(*source); } } void Any::MergeFrom(const Any& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Any) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.type_url().size() > 0) { @@ -355,12 +361,14 @@ void Any::MergeFrom(const Any& from) { } void Any::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Any) if (&from == this) return; Clear(); MergeFrom(from); } void Any::CopyFrom(const Any& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Any) if (&from == this) return; Clear(); MergeFrom(from); @@ -423,6 +431,7 @@ void Any::clear_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Any::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -466,6 +475,7 @@ void Any::clear_value() { return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Any::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.value) return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h index 82c70ad9..100a67f6 100644 --- a/src/google/protobuf/any.pb.h +++ b/src/google/protobuf/any.pb.h @@ -184,6 +184,7 @@ inline ::std::string* Any::mutable_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Any::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -227,6 +228,7 @@ inline ::std::string* Any::mutable_value() { return value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Any::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Any.value) return value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto index 47d288c3..45db6ede 100644 --- a/src/google/protobuf/any.proto +++ b/src/google/protobuf/any.proto @@ -110,6 +110,8 @@ message Any { // * If no schema is provided, `https` is assumed. // * The last segment of the URL's path must represent the fully // qualified name of the type (as in `path/google.protobuf.Duration`). + // The name should be in a canonical form (e.g., leading "." is + // not accepted). // * An HTTP GET on the URL must yield a [google.protobuf.Type][] // value in binary format, or produce an error. // * Applications are allowed to cache lookup results based on the diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc index e589a89d..def2ec19 100644 --- a/src/google/protobuf/api.pb.cc +++ b/src/google/protobuf/api.pb.cc @@ -265,6 +265,7 @@ Api* Api::New(::google::protobuf::Arena* arena) const { } void Api::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Api) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); version_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; @@ -277,7 +278,7 @@ void Api::Clear() { bool Api::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Api) for (;;) { @@ -538,6 +539,7 @@ void Api::SerializeWithCachedSizes( } int Api::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Api) int total_size = 0; // optional string name = 1; @@ -598,18 +600,22 @@ int Api::ByteSize() const { } void Api::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Api) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Api* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Api) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Api) MergeFrom(*source); } } void Api::MergeFrom(const Api& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Api) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); methods_.MergeFrom(from.methods_); options_.MergeFrom(from.options_); @@ -631,12 +637,14 @@ void Api::MergeFrom(const Api& from) { } void Api::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Api) if (&from == this) return; Clear(); MergeFrom(from); } void Api::CopyFrom(const Api& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Api) if (&from == this) return; Clear(); MergeFrom(from); @@ -704,6 +712,7 @@ void Api::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Api::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -807,6 +816,7 @@ void Api::clear_version() { return version_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Api::release_version() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.version) return version_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -841,6 +851,7 @@ const ::google::protobuf::SourceContext& Api::source_context() const { return source_context_; } ::google::protobuf::SourceContext* Api::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -984,6 +995,7 @@ Method* Method::New(::google::protobuf::Arena* arena) const { } void Method::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Method) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -1005,7 +1017,7 @@ void Method::Clear() { bool Method::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Method) for (;;) { @@ -1269,6 +1281,7 @@ void Method::SerializeWithCachedSizes( } int Method::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Method) int total_size = 0; // optional string name = 1; @@ -1323,18 +1336,22 @@ int Method::ByteSize() const { } void Method::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Method) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Method* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Method) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Method) MergeFrom(*source); } } void Method::MergeFrom(const Method& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Method) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); options_.MergeFrom(from.options_); if (from.name().size() > 0) { @@ -1361,12 +1378,14 @@ void Method::MergeFrom(const Method& from) { } void Method::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Method) if (&from == this) return; Clear(); MergeFrom(from); } void Method::CopyFrom(const Method& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Method) if (&from == this) return; Clear(); MergeFrom(from); @@ -1434,6 +1453,7 @@ void Method::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Method::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1477,6 +1497,7 @@ void Method::clear_request_type_url() { return request_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Method::release_request_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url) return request_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1534,6 +1555,7 @@ void Method::clear_response_type_url() { return response_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Method::release_response_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url) return response_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1678,13 +1700,14 @@ Mixin* Mixin::New(::google::protobuf::Arena* arena) const { } void Mixin::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Mixin) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); root_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } bool Mixin::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Mixin) for (;;) { @@ -1802,6 +1825,7 @@ void Mixin::SerializeWithCachedSizes( } int Mixin::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Mixin) int total_size = 0; // optional string name = 1; @@ -1825,18 +1849,22 @@ int Mixin::ByteSize() const { } void Mixin::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Mixin) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Mixin* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Mixin) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Mixin) MergeFrom(*source); } } void Mixin::MergeFrom(const Mixin& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Mixin) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.name().size() > 0) { @@ -1849,12 +1877,14 @@ void Mixin::MergeFrom(const Mixin& from) { } void Mixin::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Mixin) if (&from == this) return; Clear(); MergeFrom(from); } void Mixin::CopyFrom(const Mixin& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Mixin) if (&from == this) return; Clear(); MergeFrom(from); @@ -1917,6 +1947,7 @@ void Mixin::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Mixin::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1960,6 +1991,7 @@ void Mixin::clear_root() { return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Mixin::release_root() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root) return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h index e1dca4e4..bb35e471 100644 --- a/src/google/protobuf/api.pb.h +++ b/src/google/protobuf/api.pb.h @@ -468,6 +468,7 @@ inline ::std::string* Api::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Api::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -571,6 +572,7 @@ inline ::std::string* Api::mutable_version() { return version_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Api::release_version() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.version) return version_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -605,6 +607,7 @@ inline ::google::protobuf::SourceContext* Api::mutable_source_context() { return source_context_; } inline ::google::protobuf::SourceContext* Api::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Api.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -699,6 +702,7 @@ inline ::std::string* Method::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Method::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -742,6 +746,7 @@ inline ::std::string* Method::mutable_request_type_url() { return request_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Method::release_request_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.request_type_url) return request_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -799,6 +804,7 @@ inline ::std::string* Method::mutable_response_type_url() { return response_type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Method::release_response_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Method.response_type_url) return response_type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -904,6 +910,7 @@ inline ::std::string* Mixin::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Mixin::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -947,6 +954,7 @@ inline ::std::string* Mixin::mutable_root() { return root_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Mixin::release_root() { + // @@protoc_insertion_point(field_release:google.protobuf.Mixin.root) return root_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index e856f5b1..613e5897 100755 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -30,6 +30,7 @@ #include + #ifdef ADDRESS_SANITIZER #include #endif @@ -248,6 +249,19 @@ uint64 Arena::SpaceUsed() const { return space_used; } +pair Arena::SpaceAllocatedAndUsed() const { + uint64 allocated = 0; + uint64 used = 0; + + Block* b = reinterpret_cast(google::protobuf::internal::NoBarrier_Load(&blocks_)); + while (b != NULL) { + allocated += b->size; + used += (b->pos - kHeaderSize); + b = b->next; + } + return std::make_pair(allocated, used); +} + uint64 Arena::FreeBlocks() { uint64 space_allocated = 0; Block* b = reinterpret_cast(google::protobuf::internal::NoBarrier_Load(&blocks_)); diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h index 9ab0a0f9..b3d66d91 100644 --- a/src/google/protobuf/arena.h +++ b/src/google/protobuf/arena.h @@ -211,7 +211,12 @@ struct ArenaOptions { // // This protocol is implemented by all arena-enabled proto2 message classes as // well as RepeatedPtrField. + +#if __cplusplus >= 201103L +class Arena final { +#else class LIBPROTOBUF_EXPORT Arena { +#endif public: // Arena constructor taking custom options. See ArenaOptions below for // descriptions of the options available. @@ -231,7 +236,6 @@ class LIBPROTOBUF_EXPORT Arena { // if it was passed in. ~Arena(); - // API to create proto2 message objects on the arena. If the arena passed in // is NULL, then a heap allocated object is returned. Type T must be a message // defined in a .proto file with cc_enable_arenas set to true, otherwise a @@ -448,6 +452,10 @@ class LIBPROTOBUF_EXPORT Arena { // As above, but does not include any free space in underlying blocks. GOOGLE_ATTRIBUTE_NOINLINE uint64 SpaceUsed() const; + // Combines SpaceAllocated and SpaceUsed. Returns a pair of + // . + GOOGLE_ATTRIBUTE_NOINLINE pair SpaceAllocatedAndUsed() const; + // Frees all storage allocated by this arena after calling destructors // registered with OwnDestructor() and freeing objects registered with Own(). // Any objects allocated on this arena are unusable after this call. It also diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index 6b67f446..ab25ffe1 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -342,6 +342,64 @@ TEST(ArenaTest, Swap) { EXPECT_EQ(42, arena2_message->unknown_fields().field(0).varint()); } +TEST(ArenaTest, ReflectionSwapFields) { + Arena arena1; + Arena arena2; + TestAllTypes* arena1_message; + TestAllTypes* arena2_message; + + // Case 1: messages on different arenas, only one message is set. + arena1_message = Arena::CreateMessage(&arena1); + arena2_message = Arena::CreateMessage(&arena2); + TestUtil::SetAllFields(arena1_message); + const Reflection* reflection = arena1_message->GetReflection(); + std::vector fields; + reflection->ListFields(*arena1_message, &fields); + reflection->SwapFields(arena1_message, arena2_message, fields); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); + string output; + arena1_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + TestUtil::ExpectAllFieldsSet(*arena2_message); + reflection->SwapFields(arena1_message, arena2_message, fields); + arena2_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + TestUtil::ExpectAllFieldsSet(*arena1_message); + + // Case 2: messages on different arenas, both messages are set. + arena1_message = Arena::CreateMessage(&arena1); + arena2_message = Arena::CreateMessage(&arena2); + TestUtil::SetAllFields(arena1_message); + TestUtil::SetAllFields(arena2_message); + reflection->SwapFields(arena1_message, arena2_message, fields); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(&arena2, arena2_message->GetArena()); + TestUtil::ExpectAllFieldsSet(*arena1_message); + TestUtil::ExpectAllFieldsSet(*arena2_message); + + // Case 3: messages on different arenas with different lifetimes. + arena1_message = Arena::CreateMessage(&arena1); + { + Arena arena3; + TestAllTypes* arena3_message = Arena::CreateMessage(&arena3); + TestUtil::SetAllFields(arena3_message); + reflection->SwapFields(arena1_message, arena3_message, fields); + } + TestUtil::ExpectAllFieldsSet(*arena1_message); + + // Case 4: one message on arena, the other on heap. + arena1_message = Arena::CreateMessage(&arena1); + TestAllTypes message; + TestUtil::SetAllFields(arena1_message); + reflection->SwapFields(arena1_message, &message, fields); + EXPECT_EQ(&arena1, arena1_message->GetArena()); + EXPECT_EQ(NULL, message.GetArena()); + arena1_message->SerializeToString(&output); + EXPECT_EQ(0, output.size()); + TestUtil::ExpectAllFieldsSet(message); +} + TEST(ArenaTest, SetAllocatedMessage) { Arena arena; TestAllTypes *arena_message = Arena::CreateMessage(&arena); diff --git a/src/google/protobuf/arenastring_unittest.cc b/src/google/protobuf/arenastring_unittest.cc index 3fb582be..ea405d7d 100644 --- a/src/google/protobuf/arenastring_unittest.cc +++ b/src/google/protobuf/arenastring_unittest.cc @@ -28,9 +28,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// arenastring_unittest.cc is not open-sourced. Do not include in open-source -// distribution. - // Based on mvels@'s frankenstring. #include diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 87843f62..fcad6b61 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -46,6 +46,7 @@ #include #endif #include +#include #include #include @@ -948,17 +949,23 @@ bool CommandLineInterface::MakeInputsBeProtoPathRelative( return true; } + CommandLineInterface::ParseArgumentStatus CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { executable_name_ = argv[0]; + vector arguments; + for (int i = 1; i < argc; ++i) { + arguments.push_back(argv[i]); + } + // Iterate through all arguments and parse them. - for (int i = 1; i < argc; i++) { + for (int i = 0; i < arguments.size(); ++i) { string name, value; - if (ParseArgument(argv[i], &name, &value)) { + if (ParseArgument(arguments[i].c_str(), &name, &value)) { // Returned true => Use the next argument as the flag value. - if (i + 1 == argc || argv[i+1][0] == '-') { + if (i + 1 == arguments.size() || arguments[i + 1][0] == '-') { std::cerr << "Missing value for flag: " << name << std::endl; if (name == "--decode") { std::cerr << "To decode an unknown message, use --decode_raw." @@ -967,7 +974,7 @@ CommandLineInterface::ParseArguments(int argc, const char* const argv[]) { return PARSE_ARGUMENT_FAIL; } else { ++i; - value = argv[i]; + value = arguments[i]; } } diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index f196ffc5..d1377666 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -212,6 +212,7 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Parse all command-line arguments. ParseArgumentStatus ParseArguments(int argc, const char* const argv[]); + // Parses a command-line argument into a name/value pair. Returns // true if the next argument in the argv should be used as the value, // false otherwise. diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index e3dd2295..ae2900b1 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -60,6 +60,7 @@ #include #include +#include #include #include @@ -376,7 +377,9 @@ void CommandLineInterfaceTest::CreateTempFile( // Write file. string full_name = temp_directory_ + "/" + name; - GOOGLE_CHECK_OK(File::SetContents(full_name, contents, true)); + GOOGLE_CHECK_OK(File::SetContents( + full_name, StringReplace(contents, "$tmpdir", temp_directory_, true), + true)); } void CommandLineInterfaceTest::CreateTempDir(const string& name) { @@ -1090,6 +1093,7 @@ TEST_F(CommandLineInterfaceTest, WriteDependencyManifestFileForAbsolutePath) { } #endif // !_WIN32 + // ------------------------------------------------------------------- TEST_F(CommandLineInterfaceTest, ParseErrors) { diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index 47729e1c..77451ab1 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -53,6 +53,7 @@ #include #include +#include #include #include #include diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 415ae60f..c81c5982 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -98,9 +98,11 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { vars["number"] = Int32ToString(descriptor_->value(i)->number()); vars["prefix"] = (descriptor_->containing_type() == NULL) ? "" : classname_ + "_"; + vars["deprecation"] = descriptor_->value(i)->options().deprecated() ? + " PROTOBUF_DEPRECATED" : ""; if (i > 0) printer->Print(",\n"); - printer->Print(vars, "$prefix$$name$ = $number$"); + printer->Print(vars, "$prefix$$name$$deprecation$ = $number$"); if (descriptor_->value(i)->number() < min_value->number()) { min_value = descriptor_->value(i); @@ -142,15 +144,16 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { "$prefix$$short_name$_MAX + 1;\n\n"); } - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n"); // The _Name and _Parse methods - printer->Print(vars, - "inline const ::std::string& $classname$_Name($classname$ value) {\n" - " return ::google::protobuf::internal::NameOfEnum(\n" - " $classname$_descriptor(), value);\n" - "}\n"); + printer->Print( + vars, + "inline const ::std::string& $classname$_Name($classname$ value) {\n" + " return ::google::protobuf::internal::NameOfEnum(\n" + " $classname$_descriptor(), value);\n" + "}\n"); printer->Print(vars, "inline bool $classname$_Parse(\n" " const ::std::string& name, $classname$* value) {\n" @@ -166,7 +169,7 @@ GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { "template <> struct is_proto_enum< $classname$> : ::google::protobuf::internal::true_type " "{};\n", "classname", ClassName(descriptor_, true)); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "template <>\n" "inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n" @@ -185,8 +188,11 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { for (int j = 0; j < descriptor_->value_count(); j++) { vars["tag"] = EnumValueName(descriptor_->value(j)); + vars["deprecated_attr"] = descriptor_->value(j)->options().deprecated() ? + "PROTOBUF_DEPRECATED_ATTR " : ""; printer->Print(vars, - "static $constexpr$const $nested_name$ $tag$ = $classname$_$tag$;\n"); + "$deprecated_attr$static $constexpr$const $nested_name$ $tag$ =\n" + " $classname$_$tag$;\n"); } printer->Print(vars, @@ -203,16 +209,18 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { " $classname$_$nested_name$_ARRAYSIZE;\n"); } - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "static inline const ::google::protobuf::EnumDescriptor*\n" "$nested_name$_descriptor() {\n" " return $classname$_descriptor();\n" "}\n"); printer->Print(vars, - "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" - " return $classname$_Name(value);\n" - "}\n"); + "static inline const ::std::string& " + "$nested_name$_Name($nested_name$ value) {" + "\n" + " return $classname$_Name(value);\n" + "}\n"); printer->Print(vars, "static inline bool $nested_name$_Parse(const ::std::string& name,\n" " $nested_name$* value) {\n" @@ -242,7 +250,7 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { vars["classname"] = classname_; vars["constexpr"] = options_.proto_h ? "constexpr " : ""; - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" " protobuf_AssignDescriptorsOnce();\n" diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.h b/src/google/protobuf/compiler/cpp/cpp_enum.h index 61e40346..90edf001 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum.h @@ -35,12 +35,12 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ +#include #include #include #include #include - namespace google { namespace protobuf { namespace io { @@ -55,8 +55,7 @@ namespace cpp { class EnumGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit EnumGenerator(const EnumDescriptor* descriptor, - const Options& options); + EnumGenerator(const EnumDescriptor* descriptor, const Options& options); ~EnumGenerator(); // Header stuff. @@ -96,10 +95,10 @@ class EnumGenerator { private: const EnumDescriptor* descriptor_; - string classname_; - Options options_; + const string classname_; + const Options& options_; // whether to generate the *_ARRAYSIZE constant. - bool generate_array_size_; + const bool generate_array_size_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 824e2205..78a4c402 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -58,10 +58,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor, // =================================================================== -EnumFieldGenerator:: -EnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetEnumVariables(descriptor, &variables_, options); } @@ -75,8 +74,8 @@ GeneratePrivateMembers(io::Printer* printer) const { void EnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$() const$deprecation$;\n" - "void set_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$() const;\n" + "$deprecated_attr$void set_$name$($type$ value);\n"); } void EnumFieldGenerator:: @@ -135,7 +134,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "if ($type$_IsValid(value)) {\n" " set_$name$(static_cast< $type$ >(value));\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, "} else {\n" " mutable_unknown_fields()->AddVarint($number$, value);\n"); @@ -228,10 +227,9 @@ GenerateConstructorCode(io::Printer* printer) const { // =================================================================== -RepeatedEnumFieldGenerator:: -RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetEnumVariables(descriptor, &variables_, options); } @@ -241,8 +239,8 @@ void RepeatedEnumFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField $name$_;\n"); - if (descriptor_->is_packed() - && HasGeneratedMethods(descriptor_->file())) { + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); } @@ -251,12 +249,12 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$(int index) const$deprecation$;\n" - "void set_$name$(int index, $type$ value)$deprecation$;\n" - "void add_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$(int index) const;\n" + "$deprecated_attr$void set_$name$(int index, $type$ value);\n" + "$deprecated_attr$void add_$name$($type$ value);\n"); printer->Print(variables_, - "const ::google::protobuf::RepeatedField& $name$() const$deprecation$;\n" - "::google::protobuf::RepeatedField* mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedField& $name$() const;\n" + "$deprecated_attr$::google::protobuf::RepeatedField* mutable_$name$();\n"); } void RepeatedEnumFieldGenerator:: @@ -335,7 +333,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, "} else {\n" " mutable_unknown_fields()->AddVarint($number$, value);\n"); @@ -362,7 +360,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { " NULL,\n" " NULL,\n" " this->mutable_$name$())));\n"); - } else if (UseUnknownFieldSet(descriptor_->file())) { + } else if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, "DO_((::google::protobuf::internal::WireFormat::ReadPackedEnumPreserveUnknowns(\n" " input,\n" @@ -399,7 +397,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { " if ($type$_IsValid(value)) {\n" " add_$name$(static_cast< $type$ >(value));\n" " } else {\n"); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(variables_, " mutable_unknown_fields()->AddVarint($number$, value);\n"); } else { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 5b1d01ea..fe21c575 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -46,8 +46,7 @@ namespace cpp { class EnumFieldGenerator : public FieldGenerator { public: - explicit EnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + EnumFieldGenerator(const FieldDescriptor* descriptor, const Options& options); ~EnumFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -74,8 +73,8 @@ class EnumFieldGenerator : public FieldGenerator { class EnumOneofFieldGenerator : public EnumFieldGenerator { public: - explicit EnumOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + EnumOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~EnumOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -91,8 +90,8 @@ class EnumOneofFieldGenerator : public EnumFieldGenerator { class RepeatedEnumFieldGenerator : public FieldGenerator { public: - explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedEnumFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index 8d47d4e0..b3ba3a2e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -77,6 +77,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, WireFormat::TagSize(descriptor->number(), descriptor->type())); (*variables)["deprecation"] = descriptor->options().deprecated() ? " PROTOBUF_DEPRECATED" : ""; + (*variables)["deprecated_attr"] = descriptor->options().deprecated() + ? "PROTOBUF_DEPRECATED_ATTR " : ""; (*variables)["cppget"] = "Get"; @@ -121,6 +123,7 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Options& options) : descriptor_(descriptor), + options_(options), field_generators_( new google::protobuf::scoped_ptr[descriptor->field_count()]) { // Construct all the FieldGenerators. diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 1d7f8233..3b012527 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -69,7 +69,7 @@ void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor, class FieldGenerator { public: - FieldGenerator() {} + explicit FieldGenerator(const Options& options) : options_(options) {} virtual ~FieldGenerator(); // Generate lines of code declaring members fields of the message class @@ -194,6 +194,9 @@ class FieldGenerator { // are placed in the message's ByteSize() method. virtual void GenerateByteSize(io::Printer* printer) const = 0; + protected: + const Options& options_; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); }; @@ -201,13 +204,14 @@ class FieldGenerator { // Convenience class which constructs FieldGenerators for a Descriptor. class FieldGeneratorMap { public: - explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options); + FieldGeneratorMap(const Descriptor* descriptor, const Options& options); ~FieldGeneratorMap(); const FieldGenerator& get(const FieldDescriptor* field) const; private: const Descriptor* descriptor_; + const Options& options_; google::protobuf::scoped_array > field_generators_; static FieldGenerator* MakeGenerator(const FieldDescriptor* field, diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index d48171b0..385b973e 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -59,6 +59,7 @@ namespace cpp { FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) : file_(file), + options_(options), message_generators_( new google::protobuf::scoped_ptr[file->message_type_count()]), enum_generators_( @@ -66,8 +67,7 @@ FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options) service_generators_( new google::protobuf::scoped_ptr[file->service_count()]), extension_generators_( - new google::protobuf::scoped_ptr[file->extension_count()]), - options_(options) { + new google::protobuf::scoped_ptr[file->extension_count()]) { for (int i = 0; i < file->message_type_count(); i++) { message_generators_[i].reset( @@ -267,12 +267,12 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "right", use_system_include ? ">" : "\""); // Unknown fields implementation in lite mode uses StringOutputStream - if (!UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { + if (!UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) { printer->Print( "#include \n"); } - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n" "#include \n" @@ -297,7 +297,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { GenerateNamespaceOpeners(printer); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" "namespace {\n" @@ -311,7 +311,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "name", ClassName(file_->enum_type(i), false)); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { for (int i = 0; i < file_->service_count(); i++) { printer->Print( "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", @@ -336,7 +336,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { // Generate classes. for (int i = 0; i < file_->message_type_count(); i++) { - if (i == 0 && HasGeneratedMethods(file_)) { + if (i == 0 && HasGeneratedMethods(file_, options_)) { printer->Print( "\n" "namespace {\n" @@ -361,7 +361,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { printer->Print("#endif // PROTOBUF_INLINE_NOT_IN_HEADERS\n"); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { // Generate services. for (int i = 0; i < file_->service_count(); i++) { if (i == 0) printer->Print("\n"); @@ -462,7 +462,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors() // and we only use AddDescriptors() to allocate default instances. - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "\n" "void $assigndescriptorsname$() {\n", @@ -495,7 +495,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_->enum_type_count(); i++) { enum_generators_[i]->GenerateDescriptorInitializer(printer, i); } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { for (int i = 0; i < file_->service_count(); i++) { service_generators_[i]->GenerateDescriptorInitializer(printer, i); } @@ -561,22 +561,23 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { // Now generate the AddDescriptors() function. PrintHandlingOptionalStaticInitializers( - file_, printer, - // With static initializers. - // Note that we don't need any special synchronization in the following code - // because it is called at static init time before any threads exist. - "void $adddescriptorsname$() {\n" - " static bool already_here = false;\n" - " if (already_here) return;\n" - " already_here = true;\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - "\n", - // Without. - "void $adddescriptorsname$_impl() {\n" - " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" - "\n", - // Vars. - "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); + file_, options_, printer, + // With static initializers. + // Note that we don't need any special synchronization in the following + // code + // because it is called at static init time before any threads exist. + "void $adddescriptorsname$() {\n" + " static bool already_here = false;\n" + " if (already_here) return;\n" + " already_here = true;\n" + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" + "\n", + // Without. + "void $adddescriptorsname$_impl() {\n" + " GOOGLE_PROTOBUF_VERIFY_VERSION;\n" + "\n", + // Vars. + "adddescriptorsname", GlobalAddDescriptorsName(file_->name())); printer->Indent(); @@ -593,7 +594,7 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "name", add_desc_name); } - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { // Embed the descriptor. We simply serialize the entire FileDescriptorProto // and embed it as a string literal, which is parsed and built into real // descriptors at initialization time. @@ -687,23 +688,23 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { "\n"); PrintHandlingOptionalStaticInitializers( - file_, printer, - // With static initializers. - "// Force AddDescriptors() to be called at static initialization time.\n" - "struct StaticDescriptorInitializer_$filename$ {\n" - " StaticDescriptorInitializer_$filename$() {\n" - " $adddescriptorsname$();\n" - " }\n" - "} static_descriptor_initializer_$filename$_;\n", - // Without. - "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n" - "void $adddescriptorsname$() {\n" - " ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n" - " &$adddescriptorsname$_impl);\n" - "}\n", - // Vars. - "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), - "filename", FilenameIdentifier(file_->name())); + file_, options_, printer, + // With static initializers. + "// Force AddDescriptors() to be called at static initialization time.\n" + "struct StaticDescriptorInitializer_$filename$ {\n" + " StaticDescriptorInitializer_$filename$() {\n" + " $adddescriptorsname$();\n" + " }\n" + "} static_descriptor_initializer_$filename$_;\n", + // Without. + "GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n" + "void $adddescriptorsname$() {\n" + " ::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n" + " &$adddescriptorsname$_impl);\n" + "}\n", + // Vars. + "adddescriptorsname", GlobalAddDescriptorsName(file_->name()), "filename", + FilenameIdentifier(file_->name())); } void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) { @@ -760,16 +761,15 @@ void FileGenerator::GenerateTopHeaderGuard(io::Printer* printer, const string& filename_identifier) { // Generate top of header. printer->Print( - "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "// source: $filename$\n" - "\n" - "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" - "#define PROTOBUF_$filename_identifier$__INCLUDED\n" - "\n" - "#include \n" - "\n", - "filename", file_->name(), - "filename_identifier", filename_identifier); + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" + "\n" + "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" + "#define PROTOBUF_$filename_identifier$__INCLUDED\n" + "\n" + "#include \n", + "filename", file_->name(), "filename_identifier", filename_identifier); + printer->Print("\n"); } void FileGenerator::GenerateBottomHeaderGuard( @@ -808,12 +808,12 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { "#include \n" "#include \n" "#include \n"); - if (UseUnknownFieldSet(file_)) { + if (UseUnknownFieldSet(file_, options_)) { printer->Print( "#include \n"); } if (file_->message_type_count() > 0) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n"); } else { @@ -827,7 +827,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { if (HasMapFields(file_)) { printer->Print( "#include \n"); - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n"); } else { @@ -837,7 +837,7 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { } if (HasEnumDefinitions(file_)) { - if (HasDescriptorMethods(file_)) { + if (HasDescriptorMethods(file_, options_)) { printer->Print( "#include \n"); } else { @@ -846,12 +846,12 @@ void FileGenerator::GenerateLibraryIncludes(io::Printer* printer) { } } - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { printer->Print( "#include \n"); } - if (UseUnknownFieldSet(file_) && file_->message_type_count() > 0) { + if (UseUnknownFieldSet(file_, options_) && file_->message_type_count() > 0) { printer->Print( "#include \n"); } @@ -955,7 +955,7 @@ void FileGenerator::GenerateEnumDefinitions(io::Printer* printer) { } void FileGenerator::GenerateServiceDefinitions(io::Printer* printer) { - if (HasGenericServices(file_)) { + if (HasGenericServices(file_, options_)) { // Generate service definitions. for (int i = 0; i < file_->service_count(); i++) { if (i > 0) { diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h index ebe990c2..5dcf692b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/src/google/protobuf/compiler/cpp/cpp_file.h @@ -65,8 +65,7 @@ class ExtensionGenerator; // extension.h class FileGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit FileGenerator(const FileDescriptor* file, - const Options& options); + FileGenerator(const FileDescriptor* file, const Options& options); ~FileGenerator(); // info_path, if non-empty, should be the path (relative to printer's output) @@ -144,6 +143,7 @@ class FileGenerator { void GenerateProto2NamespaceEnumSpecializations(io::Printer* printer); const FileDescriptor* file_; + const Options options_; google::protobuf::scoped_array > message_generators_; google::protobuf::scoped_array > enum_generators_; @@ -152,7 +152,6 @@ class FileGenerator { // E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}. vector package_parts_; - const Options options_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); }; diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc index c7aec93a..31d189c2 100644 --- a/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc @@ -96,6 +96,8 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_options.annotation_pragma_name = options[i].second; } else if (options[i].first == "annotation_guard_name") { file_options.annotation_guard_name = options[i].second; + } else if (options[i].first == "lite") { + file_options.enforce_lite = true; } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -123,7 +125,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_generator.GenerateProtoHeader( &printer, file_options.annotate_headers ? info_path : ""); if (file_options.annotate_headers) { - scoped_ptr info_output( + google::protobuf::scoped_ptr info_output( generator_context->Open(info_path)); annotations.SerializeToZeroCopyStream(info_output.get()); } @@ -143,7 +145,7 @@ bool CppGenerator::Generate(const FileDescriptor* file, file_generator.GeneratePBHeader( &printer, file_options.annotate_headers ? info_path : ""); if (file_options.annotate_headers) { - scoped_ptr info_output( + google::protobuf::scoped_ptr info_output( generator_context->Open(info_path)); annotations.SerializeToZeroCopyStream(info_output.get()); } diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index fb46e387..2ad4d36a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -68,14 +68,15 @@ const char* const kKeywordList[] = { "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "class", "compl", "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", - "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false", - "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", - "namespace", "new", "noexcept", "not", "not_eq", "NULL", "operator", "or", - "or_eq", "private", "protected", "public", "register", "reinterpret_cast", - "return", "short", "signed", "sizeof", "static", "static_assert", - "static_cast", "struct", "switch", "template", "this", "thread_local", - "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", - "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" + "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", + "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", + "mutable", "namespace", "new", "noexcept", "not", "not_eq", "NULL", + "operator", "or", "or_eq", "private", "protected", "public", "register", + "reinterpret_cast", "return", "short", "signed", "sizeof", "static", + "static_assert", "static_cast", "struct", "switch", "template", "this", + "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", + "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", + "while", "xor", "xor_eq" }; hash_set MakeKeywordsMap() { @@ -171,9 +172,10 @@ string DependentBaseClassTemplateName(const Descriptor* descriptor) { return ClassName(descriptor, false) + "_InternalBase"; } -string SuperClassName(const Descriptor* descriptor) { - return HasDescriptorMethods(descriptor->file()) ? - "::google::protobuf::Message" : "::google::protobuf::MessageLite"; +string SuperClassName(const Descriptor* descriptor, const Options& options) { + return HasDescriptorMethods(descriptor->file(), options) + ? "::google::protobuf::Message" + : "::google::protobuf::MessageLite"; } string DependentBaseDownCast() { @@ -485,8 +487,9 @@ string SafeFunctionName(const Descriptor* descriptor, return function_name; } -bool StaticInitializersForced(const FileDescriptor* file) { - if (HasDescriptorMethods(file) || file->extension_count() > 0) { +bool StaticInitializersForced(const FileDescriptor* file, + const Options& options) { + if (HasDescriptorMethods(file, options) || file->extension_count() > 0) { return true; } for (int i = 0; i < file->message_type_count(); ++i) { @@ -498,10 +501,10 @@ bool StaticInitializersForced(const FileDescriptor* file) { } void PrintHandlingOptionalStaticInitializers( - const FileDescriptor* file, io::Printer* printer, + const FileDescriptor* file, const Options& options, io::Printer* printer, const char* with_static_init, const char* without_static_init, - const char* var1, const string& val1, - const char* var2, const string& val2) { + const char* var1, const string& val1, const char* var2, + const string& val2) { map vars; if (var1) { vars[var1] = val1; @@ -510,14 +513,16 @@ void PrintHandlingOptionalStaticInitializers( vars[var2] = val2; } PrintHandlingOptionalStaticInitializers( - vars, file, printer, with_static_init, without_static_init); + vars, file, options, printer, with_static_init, without_static_init); } -void PrintHandlingOptionalStaticInitializers( - const map& vars, const FileDescriptor* file, - io::Printer* printer, const char* with_static_init, - const char* without_static_init) { - if (StaticInitializersForced(file)) { +void PrintHandlingOptionalStaticInitializers(const map& vars, + const FileDescriptor* file, + const Options& options, + io::Printer* printer, + const char* with_static_init, + const char* without_static_init) { + if (StaticInitializersForced(file, options)) { printer->Print(vars, with_static_init); } else { printer->Print(vars, (string( @@ -612,10 +617,11 @@ enum Utf8CheckMode { }; // Which level of UTF-8 enforcemant is placed on this file. -static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field) { +static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, + const Options& options) { if (field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { return STRICT; - } else if (field->file()->options().optimize_for() != + } else if (GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME) { return VERIFY; } else { @@ -624,13 +630,13 @@ static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field) { } static void GenerateUtf8CheckCode(const FieldDescriptor* field, - bool for_parse, + const Options& options, bool for_parse, const map& variables, const char* parameters, const char* strict_function, const char* verify_function, io::Printer* printer) { - switch (GetUtf8CheckMode(field)) { + switch (GetUtf8CheckMode(field, options)) { case STRICT: { if (for_parse) { printer->Print("DO_("); @@ -674,23 +680,22 @@ static void GenerateUtf8CheckCode(const FieldDescriptor* field, } void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, - bool for_parse, + const Options& options, bool for_parse, const map& variables, const char* parameters, io::Printer* printer) { - GenerateUtf8CheckCode(field, for_parse, variables, parameters, + GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, "VerifyUtf8String", "VerifyUTF8StringNamedField", printer); } void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, - bool for_parse, + const Options& options, bool for_parse, const map& variables, const char* parameters, io::Printer* printer) { - GenerateUtf8CheckCode(field, for_parse, variables, parameters, - "VerifyUtf8Cord", "VerifyUTF8CordNamedField", - printer); + GenerateUtf8CheckCode(field, options, for_parse, variables, parameters, + "VerifyUtf8Cord", "VerifyUTF8CordNamedField", printer); } } // namespace cpp diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index a22d414d..018acfca 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -37,8 +37,9 @@ #include #include -#include +#include #include +#include namespace google { namespace protobuf { @@ -72,7 +73,7 @@ string DependentBaseClassTemplateName(const Descriptor* descriptor); // Name of the base class: either the dependent base class (for use with // proto_h) or google::protobuf::Message. -string SuperClassName(const Descriptor* descriptor); +string SuperClassName(const Descriptor* descriptor, const Options& options); // Returns a string that down-casts from the dependent base class to the // derived class. @@ -118,7 +119,7 @@ string DependentTypeName(const FieldDescriptor* field); string FieldMessageTypeName(const FieldDescriptor* field); // Strips ".proto" or ".protodevel" from the end of a filename. -string StripProto(const string& filename); +LIBPROTOC_EXPORT string StripProto(const string& filename); // Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). // Note: non-built-in type names will be qualified, meaning they will start @@ -168,12 +169,17 @@ inline bool PreserveUnknownFields(const Descriptor* message) { return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; } +// Returns the optimize mode for , respecting . +::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( + const FileDescriptor* file, const Options& options); + // If PreserveUnknownFields() is true, determines whether unknown // fields will be stored in an UnknownFieldSet or a string. // If PreserveUnknownFields() is false, this method will not be // used. -inline bool UseUnknownFieldSet(const FileDescriptor* file) { - return file->options().optimize_for() != FileOptions::LITE_RUNTIME; +inline bool UseUnknownFieldSet(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; } @@ -186,45 +192,52 @@ bool HasEnumDefinitions(const FileDescriptor* file); // Does this file have generated parsing, serialization, and other // standard methods for which reflection-based fallback implementations exist? -inline bool HasGeneratedMethods(const FileDescriptor* file) { - return file->options().optimize_for() != FileOptions::CODE_SIZE; +inline bool HasGeneratedMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE; } // Do message classes in this file have descriptor and reflection methods? -inline bool HasDescriptorMethods(const FileDescriptor* file) { - return file->options().optimize_for() != FileOptions::LITE_RUNTIME; +inline bool HasDescriptorMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; } // Should we generate generic services for this file? -inline bool HasGenericServices(const FileDescriptor* file) { +inline bool HasGenericServices(const FileDescriptor* file, + const Options& options) { return file->service_count() > 0 && - file->options().optimize_for() != FileOptions::LITE_RUNTIME && + GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME && file->options().cc_generic_services(); } // Should we generate a separate, super-optimized code path for serializing to // flat arrays? We don't do this in Lite mode because we'd rather reduce code // size. -inline bool HasFastArraySerialization(const FileDescriptor* file) { - return file->options().optimize_for() == FileOptions::SPEED; +inline bool HasFastArraySerialization(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) == FileOptions::SPEED; } // Returns whether we have to generate code with static initializers. -bool StaticInitializersForced(const FileDescriptor* file); +bool StaticInitializersForced(const FileDescriptor* file, + const Options& options); // Prints 'with_static_init' if static initializers have to be used for the // provided file. Otherwise emits both 'with_static_init' and // 'without_static_init' using #ifdef. void PrintHandlingOptionalStaticInitializers( - const FileDescriptor* file, io::Printer* printer, + const FileDescriptor* file, const Options& options, io::Printer* printer, const char* with_static_init, const char* without_static_init, - const char* var1 = NULL, const string& val1 = "", - const char* var2 = NULL, const string& val2 = ""); + const char* var1 = NULL, const string& val1 = "", const char* var2 = NULL, + const string& val2 = ""); -void PrintHandlingOptionalStaticInitializers( - const map& vars, const FileDescriptor* file, - io::Printer* printer, const char* with_static_init, - const char* without_static_init); +void PrintHandlingOptionalStaticInitializers(const map& vars, + const FileDescriptor* file, + const Options& options, + io::Printer* printer, + const char* with_static_init, + const char* without_static_init); inline bool IsMapEntryMessage(const Descriptor* descriptor) { @@ -267,19 +280,23 @@ bool IsAnyMessage(const Descriptor* descriptor); bool IsWellKnownMessage(const FileDescriptor* descriptor); -void GenerateUtf8CheckCodeForString( - const FieldDescriptor* field, - bool for_parse, - const map& variables, - const char* parameters, - io::Printer* printer); +void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, + const Options& options, bool for_parse, + const map& variables, + const char* parameters, + io::Printer* printer); -void GenerateUtf8CheckCodeForCord( - const FieldDescriptor* field, - bool for_parse, - const map& variables, - const char* parameters, - io::Printer* printer); +void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, + const Options& options, bool for_parse, + const map& variables, + const char* parameters, io::Printer* printer); + +inline ::google::protobuf::FileOptions_OptimizeMode GetOptimizeFor( + const FileDescriptor* file, const Options& options) { + return options.enforce_lite + ? FileOptions::LITE_RUNTIME + : file->options().optimize_for(); +} } // namespace cpp } // namespace compiler diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc index e5e2f07d..f585c31b 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc @@ -49,10 +49,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, const Options& options) { SetCommonFieldVariables(descriptor, variables, options); (*variables)["type"] = FieldMessageTypeName(descriptor); - (*variables)["stream_writer"] = (*variables)["declared_type"] + - (HasFastArraySerialization(descriptor->message_type()->file()) ? - "MaybeToArray" : - ""); + (*variables)["stream_writer"] = + (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file(), options) + ? "MaybeToArray" + : ""); (*variables)["full_name"] = descriptor->full_name(); const FieldDescriptor* key = @@ -83,7 +84,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["number"] = SimpleItoa(descriptor->number()); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); - if (HasDescriptorMethods(descriptor->file())) { + if (HasDescriptorMethods(descriptor->file(), options)) { (*variables)["lite"] = ""; } else { (*variables)["lite"] = "Lite"; @@ -98,10 +99,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor, } } -MapFieldGenerator:: -MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), +MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), + descriptor_(descriptor), dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -127,10 +128,10 @@ GeneratePrivateMembers(io::Printer* printer) const { void MapFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" - " $name$() const$deprecation$;\n" - "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" - " mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" + " $name$() const;\n" + "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n" + " mutable_$name$();\n"); } void MapFieldGenerator:: @@ -170,7 +171,7 @@ GenerateSwappingCode(io::Printer* printer) const { void MapFieldGenerator:: GenerateConstructorCode(io::Printer* printer) const { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(variables_, "$name$_.SetAssignDescriptorCallback(\n" " protobuf_AssignDescriptorsOnce);\n" @@ -217,7 +218,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { " (*mutable_$name$())[entry->key()] =\n" " static_cast< $val_cpp$ >(*entry->mutable_value());\n" " } else {\n"); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(variables_, " mutable_unknown_fields()" "->AddLengthDelimited($number$, data);\n"); @@ -238,14 +239,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { descriptor_->message_type()->FindFieldByName("key"); if (key_field->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - key_field, true, variables_, + key_field, options_, true, variables_, "entry->key().data(), entry->key().length(),\n", printer); } if (value_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - value_field, true, variables_, - "entry->mutable_value()->data(),\n" - "entry->mutable_value()->length(),\n", printer); + GenerateUtf8CheckCodeForString(value_field, options_, true, variables_, + "entry->mutable_value()->data(),\n" + "entry->mutable_value()->length(),\n", + printer); } // If entry is allocated by arena, its desctructor should be avoided. @@ -285,14 +286,14 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { const FieldDescriptor* value_field = descriptor_->message_type()->FindFieldByName("value"); if (key_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - key_field, false, variables_, - "it->first.data(), it->first.length(),\n", printer); + GenerateUtf8CheckCodeForString(key_field, options_, false, variables_, + "it->first.data(), it->first.length(),\n", + printer); } if (value_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - value_field, false, variables_, - "it->second.data(), it->second.length(),\n", printer); + GenerateUtf8CheckCodeForString(value_field, options_, false, variables_, + "it->second.data(), it->second.length(),\n", + printer); } printer->Outdent(); @@ -343,14 +344,14 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { const FieldDescriptor* value_field = descriptor_->message_type()->FindFieldByName("value"); if (key_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - key_field, false, variables_, - "it->first.data(), it->first.length(),\n", printer); + GenerateUtf8CheckCodeForString(key_field, options_, false, variables_, + "it->first.data(), it->first.length(),\n", + printer); } if (value_field->type() == FieldDescriptor::TYPE_STRING) { - GenerateUtf8CheckCodeForString( - value_field, false, variables_, - "it->second.data(), it->second.length(),\n", printer); + GenerateUtf8CheckCodeForString(value_field, options_, false, variables_, + "it->second.data(), it->second.length(),\n", + printer); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h index 5e205623..087dcde0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h @@ -43,8 +43,7 @@ namespace cpp { class MapFieldGenerator : public FieldGenerator { public: - explicit MapFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + MapFieldGenerator(const FieldDescriptor* descriptor, const Options& options); ~MapFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index c3166611..da2a4c92 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -106,8 +106,8 @@ struct ExtensionRangeSorter { // Returns true if the "required" restriction check should be ignored for the // given field. -inline static bool ShouldIgnoreRequiredFieldCheck( - const FieldDescriptor* field) { +inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, + const Options& options) { return false; } @@ -116,9 +116,8 @@ inline static bool ShouldIgnoreRequiredFieldCheck( // // already_seen is used to avoid checking the same type multiple times // (and also to protect against recursion). -static bool HasRequiredFields( - const Descriptor* type, - hash_set* already_seen) { +static bool HasRequiredFields(const Descriptor* type, const Options& options, + hash_set* already_seen) { if (already_seen->count(type) > 0) { // Since the first occurrence of a required field causes the whole // function to return true, we can assume that if the type is already @@ -138,8 +137,8 @@ static bool HasRequiredFields( return true; } if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !ShouldIgnoreRequiredFieldCheck(field)) { - if (HasRequiredFields(field->message_type(), already_seen)) { + !ShouldIgnoreRequiredFieldCheck(field, options)) { + if (HasRequiredFields(field->message_type(), options, already_seen)) { return true; } } @@ -148,9 +147,9 @@ static bool HasRequiredFields( return false; } -static bool HasRequiredFields(const Descriptor* type) { +static bool HasRequiredFields(const Descriptor* type, const Options& options) { hash_set already_seen; - return HasRequiredFields(type, &already_seen); + return HasRequiredFields(type, options, &already_seen); } // This returns an estimate of the compiler's alignment for the field. This @@ -480,7 +479,7 @@ GenerateDependentFieldAccessorDeclarations(io::Printer* printer) { // If the message is dependent, the inline clear_*() method will need // to delete the message type, so it must be in the dependent base // class. (See also GenerateFieldAccessorDeclarations.) - printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$void clear_$name$();\n"); } // Generate type-specific accessor declarations. field_generators_.get(field).GenerateDependentAccessorDeclarations(printer); @@ -515,22 +514,24 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) { } if (field->is_repeated()) { - printer->Print(vars, "int $name$_size() const$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$int $name$_size() const;\n"); } else if (HasHasMethod(field)) { - printer->Print(vars, "bool has_$name$() const$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$bool has_$name$() const;\n"); } else if (HasPrivateHasMethod(field)) { printer->Print(vars, "private:\n" - "bool has_$name$() const$deprecation$;\n" + "bool has_$name$() const;\n" "public:\n"); } if (!dependent_field) { // If this field is dependent, then its clear_() method is in the // depenent base class. (See also GenerateDependentAccessorDeclarations.) - printer->Print(vars, "void clear_$name$()$deprecation$;\n"); + printer->Print(vars, "$deprecated_attr$void clear_$name$();\n"); } - printer->Print(vars, "static const int $constant_name$ = $number$;\n"); + printer->Print(vars, + "$deprecated_attr$static const int $constant_name$ = " + "$number$;\n"); // Generate type-specific accessor declarations. field_generators_.get(field).GenerateAccessorDeclarations(printer); @@ -837,7 +838,7 @@ GenerateDependentBaseClassDefinition(io::Printer* printer) { map vars; vars["classname"] = DependentBaseClassTemplateName(descriptor_); - vars["superclass"] = SuperClassName(descriptor_); + vars["superclass"] = SuperClassName(descriptor_, options_); printer->Print(vars, "template \n" @@ -888,7 +889,7 @@ GenerateClassDefinition(io::Printer* printer) { vars["superclass"] = DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; } else { - vars["superclass"] = SuperClassName(descriptor_); + vars["superclass"] = SuperClassName(descriptor_, options_); } printer->Print(vars, "class $dllexport$$classname$ : public $superclass$ {\n"); @@ -912,7 +913,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n" " return _internal_metadata_.unknown_fields();\n" @@ -966,7 +967,7 @@ GenerateClassDefinition(io::Printer* printer) { } // Only generate this member if it's not disabled. - if (HasDescriptorMethods(descriptor_->file()) && + if (HasDescriptorMethods(descriptor_->file(), options_) && !descriptor_->options().no_standard_descriptor_accessor()) { printer->Print(vars, "static const ::google::protobuf::Descriptor* descriptor();\n"); @@ -1003,7 +1004,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (!StaticInitializersForced(descriptor_->file())) { + if (!StaticInitializersForced(descriptor_->file(), options_)) { printer->Print(vars, "#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n" "// Returns the internal default instance pointer. This function can\n" @@ -1046,8 +1047,8 @@ GenerateClassDefinition(io::Printer* printer) { "\n" "$classname$* New(::google::protobuf::Arena* arena) const;\n"); - if (HasGeneratedMethods(descriptor_->file())) { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print(vars, "void CopyFrom(const ::google::protobuf::Message& from);\n" "void MergeFrom(const ::google::protobuf::Message& from);\n"); @@ -1069,11 +1070,11 @@ GenerateClassDefinition(io::Printer* printer) { " ::google::protobuf::io::CodedOutputStream* output) const;\n"); // DiscardUnknownFields() is implemented in message.cc using reflections. We // need to implement this function in generated code for messages. - if (!UseUnknownFieldSet(descriptor_->file())) { + if (!UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "void DiscardUnknownFields();\n"); } - if (HasFastArraySerialization(descriptor_->file())) { + if (HasFastArraySerialization(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n"); } @@ -1096,7 +1097,7 @@ GenerateClassDefinition(io::Printer* printer) { } uses_string_ = false; if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file())) { + !UseUnknownFieldSet(descriptor_->file(), options_)) { uses_string_ = true; } for (int i = 0; i < descriptors.size(); i++) { @@ -1126,7 +1127,7 @@ GenerateClassDefinition(io::Printer* printer) { "classname", classname_); } - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "private:\n" "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n" @@ -1150,7 +1151,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::Metadata GetMetadata() const;\n" "\n"); @@ -1239,7 +1240,7 @@ GenerateClassDefinition(io::Printer* printer) { "oneof_name", descriptor_->oneof_decl(i)->name()); } - if (HasGeneratedMethods(descriptor_->file()) && + if (HasGeneratedMethods(descriptor_->file(), options_) && !descriptor_->options().message_set_wire_format() && num_required_fields_ > 1) { printer->Print( @@ -1281,7 +1282,7 @@ GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n"); } else { @@ -1408,15 +1409,14 @@ GenerateClassDefinition(io::Printer* printer) { // friends so that they can access private static variables like // default_instance_ and reflection_. PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - "friend void $dllexport_decl$ $adddescriptorsname$();\n", - // Without. - "friend void $dllexport_decl$ $adddescriptorsname$_impl();\n", - // Vars. - "dllexport_decl", options_.dllexport_decl, - "adddescriptorsname", - GlobalAddDescriptorsName(descriptor_->file()->name())); + descriptor_->file(), options_, printer, + // With static initializers. + "friend void $dllexport_decl$ $adddescriptorsname$();\n", + // Without. + "friend void $dllexport_decl$ $adddescriptorsname$_impl();\n", + // Vars. + "dllexport_decl", options_.dllexport_decl, "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); printer->Print( "friend void $assigndescriptorsname$();\n" @@ -1579,7 +1579,7 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { // Unknown field offset: either points to the unknown field set if embedded // directly, or indicates that the unknown field set is stored as part of the // internal metadata if not. - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(vars, " -1,\n"); } else { @@ -1619,7 +1619,7 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { // arena pointer and unknown field set (in a space-efficient way) if we use // that implementation strategy, or an offset directly to the arena pointer if // not (because e.g. we don't have an unknown field set). - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" "$classname$, _internal_metadata_),\n"); @@ -1709,7 +1709,7 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { "classname", classname_); if ((descriptor_->oneof_decl_count() > 0) && - HasDescriptorMethods(descriptor_->file())) { + HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "$classname$_default_oneof_instance_ = new $classname$OneofInstance();\n", "classname", classname_); @@ -1749,7 +1749,7 @@ GenerateShutdownCode(io::Printer* printer) { "delete $classname$::default_instance_;\n", "classname", classname_); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { if (descriptor_->oneof_decl_count() > 0) { printer->Print( "delete $classname$_default_oneof_instance_;\n", @@ -1777,7 +1777,8 @@ void MessageGenerator:: GenerateClassMethods(io::Printer* printer) { // mutable_unknown_fields wrapper function for LazyStringOutputStream // callback. - if (!UseUnknownFieldSet(descriptor_->file())) { + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "static ::std::string* MutableUnknownFieldsFor$classname$(\n" " $classname$* ptr) {\n" @@ -1851,7 +1852,7 @@ GenerateClassMethods(io::Printer* printer) { printer->Print("\n"); } - if (HasGeneratedMethods(descriptor_->file())) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { GenerateClear(printer); printer->Print("\n"); @@ -1861,7 +1862,7 @@ GenerateClassMethods(io::Printer* printer) { GenerateSerializeWithCachedSizes(printer); printer->Print("\n"); - if (HasFastArraySerialization(descriptor_->file())) { + if (HasFastArraySerialization(descriptor_->file(), options_)) { GenerateSerializeWithCachedSizesToArray(printer); printer->Print("\n"); } @@ -1882,7 +1883,7 @@ GenerateClassMethods(io::Printer* printer) { GenerateSwap(printer); printer->Print("\n"); - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { printer->Print( "::google::protobuf::Metadata $classname$::GetMetadata() const {\n" " protobuf_AssignDescriptorsOnce();\n" @@ -1959,7 +1960,7 @@ GenerateSharedConstructorCode(io::Printer* printer) { "_cached_size_ = 0;\n").c_str()); if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file())) { + !UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "_unknown_fields_.UnsafeSetDefault(\n" " &::google::protobuf::internal::GetEmptyStringAlreadyInited());\n"); @@ -2004,7 +2005,7 @@ GenerateSharedDestructorCode(io::Printer* printer) { // Write the desctructor for _unknown_fields_ in lite runtime. if (PreserveUnknownFields(descriptor_) && - !UseUnknownFieldSet(descriptor_->file())) { + !UseUnknownFieldSet(descriptor_->file(), options_)) { if (SupportsArenas(descriptor_)) { printer->Print( "_unknown_fields_.Destroy(\n" @@ -2035,11 +2036,11 @@ GenerateSharedDestructorCode(io::Printer* printer) { } PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - "if (this != default_instance_) {\n", - // Without. - "if (this != &default_instance()) {\n"); + descriptor_->file(), options_, printer, + // With static initializers. + "if (this != default_instance_) {\n", + // Without. + "if (this != &default_instance()) {\n"); // We need to delete all embedded messages. // TODO(kenton): If we make unset messages point at default instances @@ -2119,7 +2120,7 @@ GenerateStructors(io::Printer* printer) { superclass = DependentBaseClassTemplateName(descriptor_) + "<" + classname_ + ">"; } else { - superclass = SuperClassName(descriptor_); + superclass = SuperClassName(descriptor_, options_); } string initializer_with_arena = superclass + "()"; @@ -2127,7 +2128,7 @@ GenerateStructors(io::Printer* printer) { initializer_with_arena += ",\n _extensions_(arena)"; } - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { initializer_with_arena += ",\n _internal_metadata_(arena)"; } else { initializer_with_arena += ",\n _arena_ptr_(arena)"; @@ -2147,7 +2148,7 @@ GenerateStructors(io::Printer* printer) { } string initializer_null; - initializer_null = (UseUnknownFieldSet(descriptor_->file()) ? + initializer_null = (UseUnknownFieldSet(descriptor_->file(), options_) ? ", _internal_metadata_(NULL)" : ", _arena_ptr_(NULL)"); if (IsAnyMessage(descriptor_)) { initializer_null += ", _any_metadata_(&type_url_, &value_)"; @@ -2201,24 +2202,23 @@ GenerateStructors(io::Printer* printer) { if (!field->is_repeated() && field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && (field->containing_oneof() == NULL || - HasDescriptorMethods(descriptor_->file()))) { + HasDescriptorMethods(descriptor_->file(), options_))) { string name; if (field->containing_oneof()) { name = classname_ + "_default_oneof_instance_->"; } name += FieldName(field); PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", - // Without. - " $name$_ = const_cast< $type$*>(\n" - " $type$::internal_default_instance());\n", - // Vars. - "name", name, - "type", FieldMessageTypeName(field)); + descriptor_->file(), options_, printer, + // With static initializers. + " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", + // Without. + " $name$_ = const_cast< $type$*>(\n" + " $type$::internal_default_instance());\n", + // Vars. + "name", name, "type", FieldMessageTypeName(field)); } else if (field->containing_oneof() && - HasDescriptorMethods(descriptor_->file())) { + HasDescriptorMethods(descriptor_->file(), options_)) { field_generators_.get(descriptor_->field(i)) .GenerateConstructorCode(printer); } @@ -2234,10 +2234,10 @@ GenerateStructors(io::Printer* printer) { "classname", classname_, "superclass", superclass, "full_name", descriptor_->full_name()); - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( ",\n _internal_metadata_(NULL)"); - } else if (!UseUnknownFieldSet(descriptor_->file())) { + } else if (!UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print(",\n _arena_ptr_(NULL)"); } if (IsAnyMessage(descriptor_)) { @@ -2285,7 +2285,7 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); // Only generate this member if it's not disabled. - if (HasDescriptorMethods(descriptor_->file()) && + if (HasDescriptorMethods(descriptor_->file(), options_) && !descriptor_->options().no_standard_descriptor_accessor()) { printer->Print( "const ::google::protobuf::Descriptor* $classname$::descriptor() {\n" @@ -2303,14 +2303,14 @@ GenerateStructors(io::Printer* printer) { "classname", classname_); PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " if (default_instance_ == NULL) $adddescriptorsname$();\n", - // Without. - " $adddescriptorsname$();\n", - // Vars. - "adddescriptorsname", - GlobalAddDescriptorsName(descriptor_->file()->name())); + descriptor_->file(), options_, printer, + // With static initializers. + " if (default_instance_ == NULL) $adddescriptorsname$();\n", + // Without. + " $adddescriptorsname$();\n", + // Vars. + "adddescriptorsname", + GlobalAddDescriptorsName(descriptor_->file()->name())); printer->Print( " return *default_instance_;\n" @@ -2352,8 +2352,10 @@ static int popcnt(uint32 n) { void MessageGenerator:: GenerateClear(io::Printer* printer) { - printer->Print("void $classname$::Clear() {\n", - "classname", classname_); + printer->Print( + "void $classname$::Clear() {\n" + "// @@protoc_insertion_point(message_clear_start:$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); // Step 1: Extensions @@ -2390,8 +2392,16 @@ GenerateClear(io::Printer* printer) { // positions of two fields in the Message. // ZR_ zeroes a non-empty range of fields via memset. const char* macros = + "#if defined(__clang__)\n" + "#define ZR_HELPER_(f) \\\n" + " _Pragma(\"clang diagnostic push\") \\\n" + " _Pragma(\"clang diagnostic ignored \\\"-Winvalid-offsetof\\\"\") \\\n" + " __builtin_offsetof($classname$, f) \\\n" + " _Pragma(\"clang diagnostic pop\")\n" + "#else\n" "#define ZR_HELPER_(f) reinterpret_cast(\\\n" - " &reinterpret_cast<$classname$*>(16)->f)\n\n" + " &reinterpret_cast<$classname$*>(16)->f)\n" + "#endif\n\n" "#define ZR_(first, last) do {\\\n" " ::memset(&first, 0,\\\n" " ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\\\n" @@ -2519,7 +2529,7 @@ GenerateClear(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "if (_internal_metadata_.have_unknown_fields()) {\n" " mutable_unknown_fields()->Clear();\n" @@ -2549,10 +2559,13 @@ GenerateOneofClear(io::Printer* printer) { map oneof_vars; oneof_vars["classname"] = classname_; oneof_vars["oneofname"] = descriptor_->oneof_decl(i)->name(); + oneof_vars["full_name"] = descriptor_->full_name(); string message_class; printer->Print(oneof_vars, - "void $classname$::clear_$oneofname$() {\n"); + "void $classname$::clear_$oneofname$() {\n" + "// @@protoc_insertion_point(one_of_clear_start:" + "$full_name$)\n"); printer->Indent(); printer->Print(oneof_vars, "switch($oneofname$_case()) {\n"); @@ -2635,7 +2648,7 @@ GenerateSwap(io::Printer* printer) { "classname", classname_); printer->Indent(); - if (HasGeneratedMethods(descriptor_->file())) { + if (HasGeneratedMethods(descriptor_->file(), options_)) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); field_generators_.get(field).GenerateSwappingCode(printer); @@ -2656,19 +2669,15 @@ GenerateSwap(io::Printer* printer) { } } - if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { - printer->Print( - "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); - } else { - printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); - } - } else { - // Still swap internal_metadata as it may contain more than just - // unknown fields. + // Ignore PreserveUnknownFields here - always swap internal_metadata as it + // may contain more than just unknown fields. + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( - "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); + "_internal_metadata_.Swap(&other->_internal_metadata_);\n"); + } else { + printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n"); } + printer->Print("std::swap(_cached_size_, other->_cached_size_);\n"); if (descriptor_->extension_range_count() > 0) { printer->Print("_extensions_.Swap(&other->_extensions_);\n"); @@ -2683,13 +2692,15 @@ GenerateSwap(io::Printer* printer) { void MessageGenerator:: GenerateMergeFrom(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { // Generate the generalized MergeFrom (aka that which takes in the Message // base class as a parameter). printer->Print( - "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n" - " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", - "classname", classname_); + "void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n" + "// @@protoc_insertion_point(generalized_merge_from_start:" + "$full_name$)\n" + " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); // Cast the message to the proper type. If we find that the message is @@ -2701,11 +2712,15 @@ GenerateMergeFrom(io::Printer* printer) { " ::google::protobuf::internal::DynamicCastToGenerated(\n" " &from);\n" "if (source == NULL) {\n" + "// @@protoc_insertion_point(generalized_merge_from_cast_fail:" + "$full_name$)\n" " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n" "} else {\n" + "// @@protoc_insertion_point(generalized_merge_from_cast_success:" + "$full_name$)\n" " MergeFrom(*source);\n" "}\n", - "classname", classname_); + "classname", classname_, "full_name", descriptor_->full_name()); printer->Outdent(); printer->Print("}\n\n"); @@ -2722,9 +2737,11 @@ GenerateMergeFrom(io::Printer* printer) { // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. printer->Print( - "void $classname$::MergeFrom(const $classname$& from) {\n" - " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", - "classname", classname_); + "void $classname$::MergeFrom(const $classname$& from) {\n" + "// @@protoc_insertion_point(class_specific_merge_from_start:" + "$full_name$)\n" + " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); // Merge Repeated fields. These fields do not require a @@ -2825,7 +2842,7 @@ GenerateMergeFrom(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "if (from._internal_metadata_.have_unknown_fields()) {\n" " mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n" @@ -2844,12 +2861,14 @@ GenerateMergeFrom(io::Printer* printer) { void MessageGenerator:: GenerateCopyFrom(io::Printer* printer) { - if (HasDescriptorMethods(descriptor_->file())) { + if (HasDescriptorMethods(descriptor_->file(), options_)) { // Generate the generalized CopyFrom (aka that which takes in the Message // base class as a parameter). printer->Print( - "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n", - "classname", classname_); + "void $classname$::CopyFrom(const ::google::protobuf::Message& from) {\n" + "// @@protoc_insertion_point(generalized_copy_from_start:" + "$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print( @@ -2863,8 +2882,10 @@ GenerateCopyFrom(io::Printer* printer) { // Generate the class-specific CopyFrom. printer->Print( - "void $classname$::CopyFrom(const $classname$& from) {\n", - "classname", classname_); + "void $classname$::CopyFrom(const $classname$& from) {\n" + "// @@protoc_insertion_point(class_specific_copy_from_start:" + "$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print( @@ -2886,15 +2907,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) { "classname", classname_); PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " return _extensions_.ParseMessageSet(input, default_instance_,\n" - " mutable_unknown_fields());\n", - // Without. - " return _extensions_.ParseMessageSet(input, &default_instance(),\n" - " mutable_unknown_fields());\n", - // Vars. - "classname", classname_); + descriptor_->file(), options_, printer, + // With static initializers. + " return _extensions_.ParseMessageSet(input, default_instance_,\n" + " mutable_unknown_fields());\n", + // Without. + " return _extensions_.ParseMessageSet(input, &default_instance(),\n" + " mutable_unknown_fields());\n", + // Vars. + "classname", classname_); printer->Print( "}\n"); @@ -2904,17 +2925,18 @@ GenerateMergeFromCodedStream(io::Printer* printer) { printer->Print( "bool $classname$::MergePartialFromCodedStream(\n" " ::google::protobuf::io::CodedInputStream* input) {\n" - "#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure\n" + "#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure\n" " ::google::protobuf::uint32 tag;\n", "classname", classname_); - if (!UseUnknownFieldSet(descriptor_->file())) { + if (PreserveUnknownFields(descriptor_) && + !UseUnknownFieldSet(descriptor_->file(), options_)) { // Use LazyStringOutputString to avoid initializing unknown fields string // unless it is actually needed. For the same reason, disable eager refresh // on the CodedOutputStream. printer->Print( " ::google::protobuf::io::LazyStringOutputStream unknown_fields_string(\n" - " google::protobuf::internal::NewPermanentCallback(\n" + " ::google::protobuf::internal::NewPermanentCallback(\n" " &MutableUnknownFieldsFor$classname$, this));\n" " ::google::protobuf::io::CodedOutputStream unknown_fields_stream(\n" " &unknown_fields_string, false);\n", @@ -3136,32 +3158,32 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } printer->Print(") {\n"); if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" - " mutable_unknown_fields()));\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" - " mutable_unknown_fields()));\n"); + descriptor_->file(), options_, printer, + // With static initializers. + " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" + " mutable_unknown_fields()));\n", + // Without. + " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" + " mutable_unknown_fields()));\n"); } else { PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" - " &unknown_fields_stream));\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" - " &unknown_fields_stream));\n"); + descriptor_->file(), options_, printer, + // With static initializers. + " DO_(_extensions_.ParseField(tag, input, default_instance_,\n" + " &unknown_fields_stream));\n", + // Without. + " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n" + " &unknown_fields_stream));\n"); } } else { PrintHandlingOptionalStaticInitializers( - descriptor_->file(), printer, - // With static initializers. - " DO_(_extensions_.ParseField(tag, input, default_instance_);\n", - // Without. - " DO_(_extensions_.ParseField(tag, input, &default_instance());\n"); + descriptor_->file(), options_, printer, + // With static initializers. + " DO_(_extensions_.ParseField(tag, input, default_instance_);\n", + // Without. + " DO_(_extensions_.ParseField(tag, input, &default_instance());\n"); } printer->Print( " continue;\n" @@ -3170,7 +3192,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) { // We really don't recognize this tag. Skip it. if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "DO_(::google::protobuf::internal::WireFormat::SkipField(\n" " input, tag, mutable_unknown_fields()));\n"); @@ -3263,7 +3285,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { " ::google::protobuf::io::CodedOutputStream* output) const {\n" " _extensions_.SerializeMessageSetWithCachedSizes(output);\n", "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file())); + GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); printer->Print( " ::google::protobuf::internal::WireFormat::SerializeUnknownMessageSetItems(\n" " unknown_fields(), output);\n"); @@ -3303,7 +3325,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) { " target =\n" " _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n", "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file())); + GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); printer->Print( " target = ::google::protobuf::internal::WireFormat::\n" " SerializeUnknownMessageSetItemsToArray(\n" @@ -3369,7 +3391,7 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n"); printer->Indent(); if (to_array) { @@ -3436,10 +3458,11 @@ GenerateByteSize(io::Printer* printer) { if (descriptor_->options().message_set_wire_format()) { // Special-case MessageSet. printer->Print( - "int $classname$::ByteSize() const {\n" - " int total_size = _extensions_.MessageSetByteSize();\n", - "classname", classname_); - GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file())); + "int $classname$::ByteSize() const {\n" + "// @@protoc_insertion_point(message_set_byte_size_start:$full_name$)\n" + " int total_size = _extensions_.MessageSetByteSize();\n", + "classname", classname_, "full_name", descriptor_->full_name()); + GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_)); printer->Print( "if (_internal_metadata_.have_unknown_fields()) {\n" " total_size += ::google::protobuf::internal::WireFormat::\n" @@ -3458,8 +3481,10 @@ GenerateByteSize(io::Printer* printer) { // Emit a function (rarely used, we hope) that handles the required fields // by checking for each one individually. printer->Print( - "int $classname$::RequiredFieldsByteSizeFallback() const {\n", - "classname", classname_); + "int $classname$::RequiredFieldsByteSizeFallback() const {\n" + "// @@protoc_insertion_point(required_fields_byte_size_fallback_start:" + "$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print("int total_size = 0;\n"); for (int i = 0; i < descriptor_->field_count(); i++) { @@ -3482,8 +3507,9 @@ GenerateByteSize(io::Printer* printer) { } printer->Print( - "int $classname$::ByteSize() const {\n", - "classname", classname_); + "int $classname$::ByteSize() const {\n" + "// @@protoc_insertion_point(message_byte_size_start:$full_name$)\n", + "classname", classname_, "full_name", descriptor_->full_name()); printer->Indent(); printer->Print( "int total_size = 0;\n" @@ -3659,7 +3685,7 @@ GenerateByteSize(io::Printer* printer) { } if (PreserveUnknownFields(descriptor_)) { - if (UseUnknownFieldSet(descriptor_->file())) { + if (UseUnknownFieldSet(descriptor_->file(), options_)) { printer->Print( "if (_internal_metadata_.have_unknown_fields()) {\n" " total_size +=\n" @@ -3725,8 +3751,8 @@ GenerateIsInitialized(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && - !ShouldIgnoreRequiredFieldCheck(field) && - HasRequiredFields(field->message_type())) { + !ShouldIgnoreRequiredFieldCheck(field, options_) && + HasRequiredFields(field->message_type(), options_)) { if (field->is_repeated()) { printer->Print( "if (!::google::protobuf::internal::AllAreInitialized(this->$name$()))" diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index b4545892..332c0264 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -53,10 +53,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["non_null_ptr_to_name"] = StrCat("this->", (*variables)["name"], "_"); } - (*variables)["stream_writer"] = (*variables)["declared_type"] + - (HasFastArraySerialization(descriptor->message_type()->file()) ? - "MaybeToArray" : - ""); + (*variables)["stream_writer"] = + (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file(), options) + ? "MaybeToArray" + : ""); // NOTE: Escaped here to unblock proto1->proto2 migration. // TODO(liujisi): Extend this to apply for other conflicting methods. (*variables)["release_name"] = @@ -77,11 +78,11 @@ void SetMessageVariables(const FieldDescriptor* descriptor, // =================================================================== -MessageFieldGenerator:: -MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { +MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), + descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)) { SetMessageVariables(descriptor, &variables_, options); } @@ -95,7 +96,7 @@ GeneratePrivateMembers(io::Printer* printer) const { void MessageFieldGenerator:: GenerateGetterDeclaration(io::Printer* printer) const { printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$() const;\n"); } void MessageFieldGenerator:: @@ -105,9 +106,9 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { } // Arena manipulation code is out-of-line in the derived message class. printer->Print(variables_, - "$type$* mutable_$name$()$deprecation$;\n" - "$type$* $release_name$()$deprecation$;\n" - "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + "$deprecated_attr$$type$* mutable_$name$();\n" + "$deprecated_attr$$type$* $release_name$();\n" + "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n"); } void MessageFieldGenerator:: @@ -115,28 +116,28 @@ GenerateAccessorDeclarations(io::Printer* printer) const { if (SupportsArenas(descriptor_)) { printer->Print(variables_, "private:\n" - "void _slow_mutable_$name$()$deprecation$;\n"); + "void _slow_mutable_$name$();\n"); if (SupportsArenas(descriptor_->message_type())) { printer->Print(variables_, "void _slow_set_allocated_$name$(\n" - " ::google::protobuf::Arena* message_arena, $type$** $name$)$deprecation$;\n"); + " ::google::protobuf::Arena* message_arena, $type$** $name$);\n"); } printer->Print(variables_, - "$type$* _slow_$release_name$()$deprecation$;\n" + "$type$* _slow_$release_name$();\n" "public:\n"); } GenerateGetterDeclaration(printer); if (!dependent_field_) { printer->Print(variables_, - "$type$* mutable_$name$()$deprecation$;\n" - "$type$* $release_name$()$deprecation$;\n" - "void set_allocated_$name$($type$* $name$)$deprecation$;\n"); + "$deprecated_attr$$type$* mutable_$name$();\n" + "$deprecated_attr$$type$* $release_name$();\n" + "$deprecated_attr$void set_allocated_$name$($type$* $name$);\n"); } if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "$type$* unsafe_arena_release_$name$()$deprecation$;\n" - "void unsafe_arena_set_allocated_$name$(\n" - " $type$* $name$)$deprecation$;\n"); + "$deprecated_attr$$type$* unsafe_arena_release_$name$();\n" + "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n" + " $type$* $name$);\n"); } } @@ -167,6 +168,7 @@ void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( " }\n" "}\n" "$type$* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" @@ -246,6 +248,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "template \n" "inline $type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" " $clear_hasbit$\n" " if ($this_message$GetArenaNoVirtual() != NULL) {\n" @@ -305,6 +308,7 @@ GenerateDependentInlineAccessorDefinitions(io::Printer* printer) const { "}\n" "template \n" "inline $type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " $dependent_typename$*& $name$_ = $this_message$$name$_;\n" " $dependent_typename$* temp = $name$_;\n" @@ -349,11 +353,11 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_get:$full_name$)\n"); PrintHandlingOptionalStaticInitializers( - variables, descriptor_->file(), printer, - // With static initializers. - " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", - // Without. - " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); + variables, descriptor_->file(), options_, printer, + // With static initializers. + " return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", + // Without. + " return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); printer->Print(variables, "}\n"); if (dependent_field_) { @@ -373,6 +377,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n" "$inline$" "$type$* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " if (GetArenaNoVirtual() != NULL) {\n" " return _slow_$release_name$();\n" @@ -426,6 +431,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, "}\n" "$inline$" "$type$* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " $type$* temp = $name$_;\n" " $name$_ = NULL;\n" @@ -547,7 +553,7 @@ GenerateDependentAccessorDeclarations(io::Printer* printer) const { return; } printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$() const;\n"); MessageFieldGenerator::GenerateDependentAccessorDeclarations(printer); } @@ -560,7 +566,7 @@ GenerateGetterDeclaration(io::Printer* printer) const { return; } printer->Print(variables_, - "const $type$& $name$() const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$() const;\n"); } void MessageOneofFieldGenerator:: @@ -651,6 +657,7 @@ InternalGenerateInlineAccessorDefinitions(const map& variables, "$tmpl$" "$inline$" "$type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if ($this_message$has_$name$()) {\n" " $this_message$clear_has_$oneof_name$();\n" " if ($this_message$GetArenaNoVirtual() != NULL) {\n" @@ -706,6 +713,8 @@ InternalGenerateInlineAccessorDefinitions(const map& variables, " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" "}\n" "$inline$ $type$* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(field_unsafe_arena_release" + ":$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " $type$* temp = $oneof_prefix$$name$_;\n" @@ -744,6 +753,7 @@ InternalGenerateInlineAccessorDefinitions(const map& variables, "$tmpl$" "$inline$" "$type$* $dependent_classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if ($this_message$has_$name$()) {\n" " $this_message$clear_has_$oneof_name$();\n" " $dependent_typename$* temp = $field_member$;\n" @@ -805,12 +815,12 @@ GenerateConstructorCode(io::Printer* printer) const { // =================================================================== -RepeatedMessageFieldGenerator:: -RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor), - dependent_field_(options.proto_h && IsFieldDependent(descriptor)), - dependent_getter_(dependent_field_ && options.safe_boundary_check) { +RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), + descriptor_(descriptor), + dependent_field_(options.proto_h && IsFieldDependent(descriptor)), + dependent_getter_(dependent_field_ && options.safe_boundary_check) { SetMessageVariables(descriptor, &variables_, options); } @@ -825,23 +835,23 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: InternalGenerateTypeDependentAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$* mutable_$name$(int index)$deprecation$;\n" - "$type$* add_$name$()$deprecation$;\n"); + "$deprecated_attr$$type$* mutable_$name$(int index);\n" + "$deprecated_attr$$type$* add_$name$();\n"); if (dependent_getter_) { printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const;\n"); } printer->Print(variables_, - "::google::protobuf::RepeatedPtrField< $type$ >*\n" - " mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$::google::protobuf::RepeatedPtrField< $type$ >*\n" + " mutable_$name$();\n"); } void RepeatedMessageFieldGenerator:: GenerateDependentAccessorDeclarations(io::Printer* printer) const { if (dependent_getter_) { printer->Print(variables_, - "const $type$& $name$(int index) const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$(int index) const;\n"); } if (dependent_field_) { InternalGenerateTypeDependentAccessorDeclarations(printer); @@ -852,15 +862,15 @@ void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { if (!dependent_getter_) { printer->Print(variables_, - "const $type$& $name$(int index) const$deprecation$;\n"); + "$deprecated_attr$const $type$& $name$(int index) const;\n"); } if (!dependent_field_) { InternalGenerateTypeDependentAccessorDeclarations(printer); } if (!dependent_getter_) { printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - " $name$() const$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const;\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h index 35efd0fa..d8d9279c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h @@ -46,8 +46,8 @@ namespace cpp { class MessageFieldGenerator : public FieldGenerator { public: - explicit MessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + MessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~MessageFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -83,8 +83,8 @@ class MessageFieldGenerator : public FieldGenerator { class MessageOneofFieldGenerator : public MessageFieldGenerator { public: - explicit MessageOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + MessageOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~MessageOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -110,8 +110,8 @@ class MessageOneofFieldGenerator : public MessageFieldGenerator { class RepeatedMessageFieldGenerator : public FieldGenerator { public: - explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedMessageFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h index e908362b..ab1d2ed3 100644 --- a/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/src/google/protobuf/compiler/cpp/cpp_options.h @@ -44,11 +44,16 @@ namespace cpp { // Generator options (see generator.cc for a description of each): struct Options { Options() - : safe_boundary_check(false), proto_h(false), annotate_headers(false) {} + : safe_boundary_check(false), + proto_h(false), + annotate_headers(false), + enforce_lite(false) {} + string dllexport_decl; bool safe_boundary_check; bool proto_h; bool annotate_headers; + bool enforce_lite; string annotation_pragma_name; string annotation_guard_name; }; diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc index d1efbfe6..34a41d82 100644 --- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc @@ -44,9 +44,10 @@ #include #include +#include +#include #include #include -#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 9f929d37..650f0381 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -100,10 +100,9 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, // =================================================================== -PrimitiveFieldGenerator:: -PrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +PrimitiveFieldGenerator::PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_, options); } @@ -117,8 +116,8 @@ GeneratePrivateMembers(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$() const$deprecation$;\n" - "void set_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$() const;\n" + "$deprecated_attr$void set_$name$($type$ value);\n"); } void PrimitiveFieldGenerator:: @@ -256,10 +255,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { // =================================================================== -RepeatedPrimitiveFieldGenerator:: -RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_, options); if (descriptor->is_packed()) { @@ -277,7 +275,8 @@ void RepeatedPrimitiveFieldGenerator:: GeneratePrivateMembers(io::Printer* printer) const { printer->Print(variables_, "::google::protobuf::RepeatedField< $type$ > $name$_;\n"); - if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file())) { + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { printer->Print(variables_, "mutable int _$name$_cached_byte_size_;\n"); } @@ -286,14 +285,14 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "$type$ $name$(int index) const$deprecation$;\n" - "void set_$name$(int index, $type$ value)$deprecation$;\n" - "void add_$name$($type$ value)$deprecation$;\n"); + "$deprecated_attr$$type$ $name$(int index) const;\n" + "$deprecated_attr$void set_$name$(int index, $type$ value);\n" + "$deprecated_attr$void add_$name$($type$ value);\n"); printer->Print(variables_, - "const ::google::protobuf::RepeatedField< $type$ >&\n" - " $name$() const$deprecation$;\n" - "::google::protobuf::RepeatedField< $type$ >*\n" - " mutable_$name$()$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedField< $type$ >&\n" + " $name$() const;\n" + "$deprecated_attr$::google::protobuf::RepeatedField< $type$ >*\n" + " mutable_$name$();\n"); } void RepeatedPrimitiveFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index fcd7d684..655ebde4 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -46,8 +46,8 @@ namespace cpp { class PrimitiveFieldGenerator : public FieldGenerator { public: - explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + PrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~PrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -74,8 +74,8 @@ class PrimitiveFieldGenerator : public FieldGenerator { class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { public: - explicit PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + PrimitiveOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~PrimitiveOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -92,8 +92,8 @@ class PrimitiveOneofFieldGenerator : public PrimitiveFieldGenerator { class RepeatedPrimitiveFieldGenerator : public FieldGenerator { public: - explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedPrimitiveFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 6b0821a6..1d743457 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -76,10 +76,9 @@ void SetStringVariables(const FieldDescriptor* descriptor, // =================================================================== -StringFieldGenerator:: -StringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +StringFieldGenerator::StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetStringVariables(descriptor, &variables_, options); } @@ -140,19 +139,19 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "const ::std::string& $name$() const$deprecation$;\n" - "void set_$name$(const ::std::string& value)$deprecation$;\n" - "void set_$name$(const char* value)$deprecation$;\n" - "void set_$name$(const $pointer_type$* value, size_t size)" - "$deprecation$;\n" - "::std::string* mutable_$name$()$deprecation$;\n" - "::std::string* $release_name$()$deprecation$;\n" - "void set_allocated_$name$(::std::string* $name$)$deprecation$;\n"); + "$deprecated_attr$const ::std::string& $name$() const;\n" + "$deprecated_attr$void set_$name$(const ::std::string& value);\n" + "$deprecated_attr$void set_$name$(const char* value);\n" + "$deprecated_attr$void set_$name$(const $pointer_type$* value, size_t size)" + ";\n" + "$deprecated_attr$::std::string* mutable_$name$();\n" + "$deprecated_attr$::std::string* $release_name$();\n" + "$deprecated_attr$void set_allocated_$name$(::std::string* $name$);\n"); if (SupportsArenas(descriptor_)) { printer->Print(variables_, - "::std::string* unsafe_arena_release_$name$()$deprecation$;\n" - "void unsafe_arena_set_allocated_$name$(\n" - " ::std::string* $name$)$deprecation$;\n"); + "$deprecated_attr$::std::string* unsafe_arena_release_$name$();\n" + "$deprecated_attr$void unsafe_arena_set_allocated_$name$(\n" + " ::std::string* $name$);\n"); } @@ -199,10 +198,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n" "}\n" "$inline$ ::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n" "}\n" "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " $clear_hasbit$\n" " return $name$_.UnsafeArenaRelease($default_variable$,\n" @@ -228,7 +229,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " }\n" " $name$_.UnsafeArenaSetAllocated($default_variable$,\n" " $name$, GetArenaNoVirtual());\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" "}\n"); } else { // No-arena case. @@ -261,6 +263,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $name$_.MutableNoArena($default_variable$);\n" "}\n" "$inline$ ::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " $clear_hasbit$\n" " return $name$_.ReleaseNoArena($default_variable$);\n" "}\n" @@ -369,7 +372,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, true, variables_, + descriptor_, options_, true, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } } @@ -378,7 +381,7 @@ void StringFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } printer->Print(variables_, @@ -390,7 +393,7 @@ void StringFieldGenerator:: GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } printer->Print(variables_, @@ -477,6 +480,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_mutable:$full_name$)\n" "}\n" "$inline$ ::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " return $oneof_prefix$$name$_.Release($default_variable$,\n" @@ -486,6 +490,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " }\n" "}\n" "$inline$ ::std::string* $classname$::unsafe_arena_release_$name$() {\n" + " // @@protoc_insertion_point(field_unsafe_arena_release:$full_name$)\n" " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" @@ -519,7 +524,8 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, " "$name$, GetArenaNoVirtual());\n" " }\n" - " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n" + " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:" + "$full_name$)\n" "}\n"); } else { // No-arena case. @@ -572,6 +578,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n" "}\n" "$inline$ ::std::string* $classname$::$release_name$() {\n" + " // @@protoc_insertion_point(field_release:$full_name$)\n" " if (has_$name$()) {\n" " clear_has_$oneof_name$();\n" " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n" @@ -658,7 +665,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, true, variables_, + descriptor_, options_, true, variables_, "this->$name$().data(), this->$name$().length(),\n", printer); } } @@ -666,10 +673,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { // =================================================================== -RepeatedStringFieldGenerator:: -RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options) - : descriptor_(descriptor) { +RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( + const FieldDescriptor* descriptor, const Options& options) + : FieldGenerator(options), descriptor_(descriptor) { SetStringVariables(descriptor, &variables_, options); } @@ -696,24 +702,24 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "const ::std::string& $name$(int index) const$deprecation$;\n" - "::std::string* mutable_$name$(int index)$deprecation$;\n" - "void set_$name$(int index, const ::std::string& value)$deprecation$;\n" - "void set_$name$(int index, const char* value)$deprecation$;\n" + "$deprecated_attr$const ::std::string& $name$(int index) const;\n" + "$deprecated_attr$::std::string* mutable_$name$(int index);\n" + "$deprecated_attr$void set_$name$(int index, const ::std::string& value);\n" + "$deprecated_attr$void set_$name$(int index, const char* value);\n" "" - "void set_$name$(int index, const $pointer_type$* value, size_t size)" - "$deprecation$;\n" - "::std::string* add_$name$()$deprecation$;\n" - "void add_$name$(const ::std::string& value)$deprecation$;\n" - "void add_$name$(const char* value)$deprecation$;\n" - "void add_$name$(const $pointer_type$* value, size_t size)" - "$deprecation$;\n"); + "$deprecated_attr$void set_$name$(" + "int index, const $pointer_type$* value, size_t size);\n" + "$deprecated_attr$::std::string* add_$name$();\n" + "$deprecated_attr$void add_$name$(const ::std::string& value);\n" + "$deprecated_attr$void add_$name$(const char* value);\n" + "$deprecated_attr$void add_$name$(const $pointer_type$* value, size_t size)" + ";\n"); printer->Print(variables_, - "const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" - "$deprecation$;\n" - "::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" - "$deprecation$;\n"); + "$deprecated_attr$const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() " + "const;\n" + "$deprecated_attr$::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" + ";\n"); if (unknown_ctype) { printer->Outdent(); @@ -752,6 +758,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n" "}\n" "$inline$ ::std::string* $classname$::add_$name$() {\n" + " // @@protoc_insertion_point(field_add_mutable:$full_name$)\n" " return $name$_.Add();\n" "}\n" "$inline$ void $classname$::add_$name$(const ::std::string& value) {\n" @@ -807,7 +814,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { " input, this->add_$name$()));\n"); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, true, variables_, + descriptor_, options_, true, variables_, "this->$name$(this->$name$_size() - 1).data(),\n" "this->$name$(this->$name$_size() - 1).length(),\n", printer); @@ -821,7 +828,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Indent(); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$(i).data(), this->$name$(i).length(),\n", printer); } printer->Outdent(); @@ -838,7 +845,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { printer->Indent(); if (descriptor_->type() == FieldDescriptor::TYPE_STRING) { GenerateUtf8CheckCodeForString( - descriptor_, false, variables_, + descriptor_, options_, false, variables_, "this->$name$(i).data(), this->$name$(i).length(),\n", printer); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h index 616e2067..cb4e8772 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h @@ -46,8 +46,8 @@ namespace cpp { class StringFieldGenerator : public FieldGenerator { public: - explicit StringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + StringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~StringFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -79,8 +79,8 @@ class StringFieldGenerator : public FieldGenerator { class StringOneofFieldGenerator : public StringFieldGenerator { public: - explicit StringOneofFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + StringOneofFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~StringOneofFieldGenerator(); // implements FieldGenerator --------------------------------------- @@ -99,8 +99,8 @@ class StringOneofFieldGenerator : public StringFieldGenerator { class RepeatedStringFieldGenerator : public FieldGenerator { public: - explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, - const Options& options); + RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, + const Options& options); ~RepeatedStringFieldGenerator(); // implements FieldGenerator --------------------------------------- diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index 148da883..5d82946d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -1252,7 +1252,7 @@ class GeneratedServiceTest : public testing::Test { foo_(descriptor_->FindMethodByName("Foo")), bar_(descriptor_->FindMethodByName("Bar")), stub_(&mock_channel_), - done_(google::protobuf::internal::NewPermanentCallback(&DoNothing)) {} + done_(::google::protobuf::internal::NewPermanentCallback(&DoNothing)) {} virtual void SetUp() { ASSERT_TRUE(foo_ != NULL); diff --git a/src/google/protobuf/compiler/cpp/metadata_test.cc b/src/google/protobuf/compiler/cpp/metadata_test.cc index 61dc283a..edd30780 100644 --- a/src/google/protobuf/compiler/cpp/metadata_test.cc +++ b/src/google/protobuf/compiler/cpp/metadata_test.cc @@ -41,9 +41,10 @@ #include #include +#include +#include #include #include -#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/importer_unittest.cc b/src/google/protobuf/compiler/importer_unittest.cc index be19aa2e..1b6e9700 100644 --- a/src/google/protobuf/compiler/importer_unittest.cc +++ b/src/google/protobuf/compiler/importer_unittest.cc @@ -32,25 +32,26 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include + #include #include #ifndef _SHARED_PTR_H #include #endif -#include -#include -#include -#include - -#include #include #include #include +#include +#include +#include +#include #include #include #include #include +#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_doc_comment.cc b/src/google/protobuf/compiler/java/java_doc_comment.cc index 663f0c97..0b5caba4 100644 --- a/src/google/protobuf/compiler/java/java_doc_comment.cc +++ b/src/google/protobuf/compiler/java/java_doc_comment.cc @@ -120,9 +120,7 @@ static void WriteDocCommentBodyForLocation( lines.pop_back(); } - printer->Print( - " *\n" - " *

\n");
+    printer->Print(" * 
\n");
     for (int i = 0; i < lines.size(); i++) {
       // Most lines should start with a space.  Watch out for lines that start
       // with a /, since putting that right after the leading asterisk will
@@ -133,7 +131,9 @@ static void WriteDocCommentBodyForLocation(
         printer->Print(" *$line$\n", "line", lines[i]);
       }
     }
-    printer->Print(" * 
\n"); + printer->Print( + " *
\n" + " *\n"); } } @@ -163,12 +163,12 @@ static string FirstLineOf(const string& value) { } void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) { - printer->Print( - "/**\n" - " * Protobuf type {@code $fullname$}\n", - "fullname", EscapeJavadoc(message->full_name())); + printer->Print("/**\n"); WriteDocCommentBody(printer, message); - printer->Print(" */\n"); + printer->Print( + " * Protobuf type {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(message->full_name())); } void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { @@ -176,55 +176,55 @@ void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { // etc., but in practice everyone already knows the difference between these // so it's redundant information. - // We use the field declaration as the first line of the comment, e.g.: + // We start the comment with the main body based on the comments from the + // .proto file (if present). We then end with the field declaration, e.g.: // optional string foo = 5; - // This communicates a lot of information about the field in a small space. // If the field is a group, the debug string might end with {. + printer->Print("/**\n"); + WriteDocCommentBody(printer, field); printer->Print( - "/**\n" " * $def$\n", "def", EscapeJavadoc(FirstLineOf(field->DebugString()))); - WriteDocCommentBody(printer, field); printer->Print(" */\n"); } void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) { - printer->Print( - "/**\n" - " * Protobuf enum {@code $fullname$}\n", - "fullname", EscapeJavadoc(enum_->full_name())); + printer->Print("/**\n"); WriteDocCommentBody(printer, enum_); - printer->Print(" */\n"); + printer->Print( + " * Protobuf enum {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(enum_->full_name())); } void WriteEnumValueDocComment(io::Printer* printer, const EnumValueDescriptor* value) { - printer->Print( - "/**\n" - " * $def$\n", - "def", EscapeJavadoc(FirstLineOf(value->DebugString()))); + printer->Print("/**\n"); WriteDocCommentBody(printer, value); - printer->Print(" */\n"); + printer->Print( + " * $def$\n" + " */\n", + "def", EscapeJavadoc(FirstLineOf(value->DebugString()))); } void WriteServiceDocComment(io::Printer* printer, const ServiceDescriptor* service) { - printer->Print( - "/**\n" - " * Protobuf service {@code $fullname$}\n", - "fullname", EscapeJavadoc(service->full_name())); + printer->Print("/**\n"); WriteDocCommentBody(printer, service); - printer->Print(" */\n"); + printer->Print( + " * Protobuf service {@code $fullname$}\n" + " */\n", + "fullname", EscapeJavadoc(service->full_name())); } void WriteMethodDocComment(io::Printer* printer, const MethodDescriptor* method) { - printer->Print( - "/**\n" - " * $def$\n", - "def", EscapeJavadoc(FirstLineOf(method->DebugString()))); + printer->Print("/**\n"); WriteDocCommentBody(printer, method); - printer->Print(" */\n"); + printer->Print( + " * $def$\n" + " */\n", + "def", EscapeJavadoc(FirstLineOf(method->DebugString()))); } } // namespace java diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 9eea873a..947b80e4 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -92,6 +92,16 @@ void EnumGenerator::Generate(io::Printer* printer) { "classname", descriptor_->name()); printer->Indent(); + bool ordinal_is_index = true; + string index_text = "ordinal()"; + for (int i = 0; i < canonical_values_.size(); i++) { + if (canonical_values_[i]->index() != i) { + ordinal_is_index = false; + index_text = "index"; + break; + } + } + for (int i = 0; i < canonical_values_.size(); i++) { map vars; vars["name"] = canonical_values_[i]->name(); @@ -101,12 +111,21 @@ void EnumGenerator::Generate(io::Printer* printer) { if (canonical_values_[i]->options().deprecated()) { printer->Print("@java.lang.Deprecated\n"); } - printer->Print(vars, - "$name$($index$, $number$),\n"); + if (ordinal_is_index) { + printer->Print(vars, + "$name$($number$),\n"); + } else { + printer->Print(vars, + "$name$($index$, $number$),\n"); + } } if (SupportUnknownEnumValue(descriptor_->file())) { - printer->Print("UNRECOGNIZED(-1, -1),\n"); + if (ordinal_is_index) { + printer->Print("UNRECOGNIZED(-1),\n"); + } else { + printer->Print("UNRECOGNIZED(-1, -1),\n"); + } } printer->Print( @@ -141,11 +160,19 @@ void EnumGenerator::Generate(io::Printer* printer) { "\n" "public final int getNumber() {\n"); if (SupportUnknownEnumValue(descriptor_->file())) { - printer->Print( - " if (index == -1) {\n" - " throw new java.lang.IllegalArgumentException(\n" - " \"Can't get the number of an unknown enum value.\");\n" - " }\n"); + if (ordinal_is_index) { + printer->Print( + " if (this == UNRECOGNIZED) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } else { + printer->Print( + " if (index == -1) {\n" + " throw new java.lang.IllegalArgumentException(\n" + " \"Can't get the number of an unknown enum value.\");\n" + " }\n"); + } } printer->Print( " return value;\n" @@ -200,14 +227,15 @@ void EnumGenerator::Generate(io::Printer* printer) { printer->Print( "public final com.google.protobuf.Descriptors.EnumValueDescriptor\n" " getValueDescriptor() {\n" - " return getDescriptor().getValues().get(index);\n" + " return getDescriptor().getValues().get($index_text$);\n" "}\n" "public final com.google.protobuf.Descriptors.EnumDescriptor\n" " getDescriptorForType() {\n" " return getDescriptor();\n" "}\n" "public static final com.google.protobuf.Descriptors.EnumDescriptor\n" - " getDescriptor() {\n"); + " getDescriptor() {\n", + "index_text", index_text); // TODO(kenton): Cache statically? Note that we can't access descriptors // at module init time because it wouldn't work with descriptor.proto, but @@ -313,16 +341,27 @@ void EnumGenerator::Generate(io::Printer* printer) { "}\n" "\n"); - printer->Print("private final int index;\n"); + if (!ordinal_is_index) { + printer->Print("private final int index;\n"); + } } // ----------------------------------------------------------------- printer->Print( - "private final int value;\n\n" - "private $classname$(int index, int value) {\n", - "classname", descriptor_->name()); - if (HasDescriptorMethods(descriptor_, context_->EnforceLite())) { + "private final int value;\n\n"); + + if (ordinal_is_index) { + printer->Print( + "private $classname$(int value) {\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "private $classname$(int index, int value) {\n", + "classname", descriptor_->name()); + } + if (HasDescriptorMethods(descriptor_, context_->EnforceLite()) && + !ordinal_is_index) { printer->Print(" this.index = index;\n"); } printer->Print( diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc index 5b98637b..908d6db4 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc @@ -262,17 +262,15 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableEnumFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visitInt(has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } else if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - "if (other.$name$_ != $default_number$) {\n" - " set$capitalized_name$Value(other.get$capitalized_name$Value());\n" - "}\n"); + "$name$_ = visitor.visitInt($name$_ != $default_number$, $name$_," + " other.$name$_ != $default_number$, other.$name$_);\n"); } else { GOOGLE_LOG(FATAL) << "Can't reach here."; } @@ -466,14 +464,10 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableEnumOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - if (SupportUnknownEnumValue(descriptor_->file())) { - printer->Print(variables_, - "set$capitalized_name$Value(other.get$capitalized_name$Value());\n"); - } else { - printer->Print(variables_, - "set$capitalized_name$(other.get$capitalized_name$());\n"); - } +GenerateVisitCode(io::Printer* printer) const { + printer->Print(variables_, + "$oneof_name$_ = visitor.visitOneofInt(\n" + " $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n"); } void ImmutableEnumOneofFieldLiteGenerator:: @@ -645,7 +639,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = newIntList($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n"); WriteFieldDocComment(printer, descriptor_); @@ -805,21 +800,9 @@ GenerateInitializationCode(io::Printer* printer) const { } void RepeatedImmutableEnumFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations: - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - "}\n"); + "$name$_= visitor.visitIntList($name$_, other.$name$_);\n"); } void RepeatedImmutableEnumFieldLiteGenerator:: @@ -831,27 +814,23 @@ GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { // Read and store the enum + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" + "}\n"); + if (SupportUnknownEnumValue(descriptor_->file())) { printer->Print(variables_, - "int rawValue = input.readEnum();\n" - "if (!$is_mutable$) {\n" - " $name$_ = newIntList();\n" - "}\n" - "$name$_.addInt(rawValue);\n"); + "$name$_.addInt(input.readEnum());\n"); } else { printer->Print(variables_, "int rawValue = input.readEnum();\n" "$type$ value = $type$.forNumber(rawValue);\n" - "if (value == null) {\n"); - if (PreserveUnknownFields(descriptor_->containing_type())) { - printer->Print(variables_, - " super.mergeVarintField($number$, rawValue);\n"); - } - printer->Print(variables_, + "if (value == null) {\n" + // We store the unknown value in unknown fields. + " super.mergeVarintField($number$, rawValue);\n" "} else {\n" - " if (!$is_mutable$) {\n" - " $name$_ = newIntList();\n" - " }\n" " $name$_.addInt(rawValue);\n" "}\n"); } @@ -859,7 +838,11 @@ GenerateParsingCode(io::Printer* printer) const { void RepeatedImmutableEnumFieldLiteGenerator:: GenerateParsingCodeFromPacked(io::Printer* printer) const { - // Wrap GenerateParsingCode's contents with a while loop. + printer->Print(variables_, + "if (!$is_mutable$) {\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" + "}\n"); printer->Print(variables_, "int length = input.readRawVarint32();\n" @@ -867,7 +850,21 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { "while(input.getBytesUntilLimit() > 0) {\n"); printer->Indent(); - GenerateParsingCode(printer); + // Read and store the enum + if (SupportUnknownEnumValue(descriptor_->file())) { + printer->Print(variables_, + "$name$_.addInt(input.readEnum());\n"); + } else { + printer->Print(variables_, + "int rawValue = input.readEnum();\n" + "$type$ value = $type$.forNumber(rawValue);\n" + "if (value == null) {\n" + // We store the unknown value in unknown fields. + " super.mergeVarintField($number$, rawValue);\n" + "} else {\n" + " $name$_.addInt(rawValue);\n" + "}\n"); + } printer->Outdent(); printer->Print(variables_, diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.h b/src/google/protobuf/compiler/java/java_enum_field_lite.h index 2c41c3e4..9201b8d6 100644 --- a/src/google/protobuf/compiler/java/java_enum_field_lite.h +++ b/src/google/protobuf/compiler/java/java_enum_field_lite.h @@ -67,7 +67,7 @@ class ImmutableEnumFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; @@ -101,7 +101,7 @@ class ImmutableEnumOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -127,7 +127,7 @@ class RepeatedImmutableEnumFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingCodeFromPacked(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index 0e24da24..4dd4f57f 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -105,7 +105,7 @@ class ImmutableFieldLiteGenerator { virtual void GenerateMembers(io::Printer* printer) const = 0; virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; virtual void GenerateInitializationCode(io::Printer* printer) const = 0; - virtual void GenerateMergingCode(io::Printer* printer) const = 0; + virtual void GenerateVisitCode(io::Printer* printer) const = 0; virtual void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const = 0; virtual void GenerateParsingCode(io::Printer* printer) const = 0; diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc index a648f1c2..62f39302 100644 --- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc @@ -182,12 +182,11 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableLazyMessageFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " $name$_.merge(other.$name$_);\n" - " $set_has_field_bit_message$;\n" - "}\n"); + "$name$_ = visitor.visitLazyMessage(\n" + " has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } void ImmutableLazyMessageFieldLiteGenerator:: @@ -362,14 +361,12 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableLazyMessageOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (!($has_oneof_case_message$)) {\n" - " $oneof_name$_ = new $lazy_type$();\n" - "}\n" - "(($lazy_type$) $oneof_name$_).merge(\n" - " ($lazy_type$) other.$oneof_name$_);\n" - "$set_oneof_case_message$;\n"); + "$oneof_name$_ = visitor.visitOneofLazyMessage(\n" + " $has_oneof_case_message$,\n" + " ($lazy_type$) $oneof_name$_,\n" + " ($lazy_type$) other.$oneof_name$_);\n"); } void ImmutableLazyMessageOneofFieldLiteGenerator:: @@ -463,7 +460,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = newProtobufList($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n" "\n"); @@ -678,7 +676,8 @@ void RepeatedImmutableLazyMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = newProtobufList();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n" "$name$_.add(new com.google.protobuf.LazyFieldLite(\n" " extensionRegistry, input.readBytes()));\n"); diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h index e85ec0f3..47ebeb49 100644 --- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h +++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.h @@ -63,7 +63,7 @@ class ImmutableLazyMessageFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -82,7 +82,7 @@ class ImmutableLazyMessageOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc index 17c3646f..2a551ca4 100644 --- a/src/google/protobuf/compiler/java/java_map_field.cc +++ b/src/google/protobuf/compiler/java/java_map_field.cc @@ -215,7 +215,7 @@ GenerateMembers(io::Printer* printer) const { " if ($name$_ == null) {\n" " return com.google.protobuf.MapField$lite$.emptyMapField(\n" " $map_field_parameter$);\n" - " }\n" + " }\n" " return $name$_;\n" "}\n"); if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) { @@ -270,7 +270,7 @@ GenerateBuilderMembers(io::Printer* printer) const { " if ($name$_ == null) {\n" " return com.google.protobuf.MapField$lite$.emptyMapField(\n" " $map_field_parameter$);\n" - " }\n" + " }\n" " return $name$_;\n" "}\n" "private com.google.protobuf.MapField$lite$<$type_parameters$>\n" diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc index 6bdebb0d..b80d4139 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc @@ -374,10 +374,10 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableMapFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print( variables_, - "internalGetMutable$capitalized_name$().mergeFrom(\n" + "$name$_ = visitor.visitMap(internalGetMutable$capitalized_name$(),\n" " other.internalGet$capitalized_name$());\n"); } diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.h b/src/google/protobuf/compiler/java/java_map_field_lite.h index a09cd536..555b5c5b 100644 --- a/src/google/protobuf/compiler/java/java_map_field_lite.h +++ b/src/google/protobuf/compiler/java/java_map_field_lite.h @@ -52,7 +52,7 @@ class ImmutableMapFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index dfd8ad08..4c474a48 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -89,7 +89,6 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor) MessageGenerator::~MessageGenerator() {} // =================================================================== -// TODO(api): Move this class to a separate immutable_message.cc file. ImmutableMessageGenerator::ImmutableMessageGenerator( const Descriptor* descriptor, Context* context) : MessageGenerator(descriptor), context_(context), @@ -1226,7 +1225,8 @@ GenerateParsingConstructor(io::Printer* printer) { "default: {\n" " if (!input.skipField(tag)) {\n" " done = true;\n" // it's an endgroup tag - " }\n" + " }\n"); + printer->Print( " break;\n" "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.cc b/src/google/protobuf/compiler/java/java_message_field_lite.cc index 049679df..14281816 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_field_lite.cc @@ -286,11 +286,9 @@ void ImmutableMessageFieldLiteGenerator:: GenerateInitializationCode(io::Printer* printer) const {} void ImmutableMessageFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " merge$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visitMessage($name$_, other.$name$_);\n"); } void ImmutableMessageFieldLiteGenerator:: @@ -300,11 +298,18 @@ GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const { void ImmutableMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { + // TODO(dweis): Update this code to avoid the builder allocation and instead + // only allocate a submessage that isn't made immutable. Rely on the top + // message calling makeImmutable once done to actually traverse the tree and + // finalize state. This will avoid: + // - transitive builder allocations + // - the extra transitive iteration for streamed fields + // - reallocations for copying repeated fields printer->Print(variables_, - "$type$.Builder subBuilder = null;\n" - "if ($is_field_present_message$) {\n" - " subBuilder = $name$_.toBuilder();\n" - "}\n"); + "$type$.Builder subBuilder = null;\n" + "if ($is_field_present_message$) {\n" + " subBuilder = $name$_.toBuilder();\n" + "}\n"); if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, @@ -504,9 +509,12 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableMessageOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "merge$capitalized_name$(other.get$capitalized_name$());\n"); + "$oneof_name$_ = visitor.visitOneofMessage(\n" + " $has_oneof_case_message$,\n" + " $oneof_name$_,\n" + " other.$oneof_name$_);\n"); } void ImmutableMessageOneofFieldLiteGenerator:: @@ -633,7 +641,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = newProtobufList($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n" "\n"); @@ -851,21 +860,9 @@ GenerateInitializationCode(io::Printer* printer) const { } void RepeatedImmutableMessageFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations (non-nested builder case): - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - "}\n"); + "$name$_= visitor.visitList($name$_, other.$name$_);\n"); } void RepeatedImmutableMessageFieldLiteGenerator:: @@ -878,7 +875,8 @@ void RepeatedImmutableMessageFieldLiteGenerator:: GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = newProtobufList();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n"); if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { diff --git a/src/google/protobuf/compiler/java/java_message_field_lite.h b/src/google/protobuf/compiler/java/java_message_field_lite.h index ae26c06a..61321547 100644 --- a/src/google/protobuf/compiler/java/java_message_field_lite.h +++ b/src/google/protobuf/compiler/java/java_message_field_lite.h @@ -67,7 +67,7 @@ class ImmutableMessageFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; @@ -101,7 +101,7 @@ class ImmutableMessageOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -125,7 +125,7 @@ class RepeatedImmutableMessageFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc index 14cc908b..d4d2593a 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.cc +++ b/src/google/protobuf/compiler/java/java_message_lite.cc @@ -199,7 +199,7 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Indent(); - GenerateParsingConstructor(printer); + GenerateConstructor(printer); // Nested types for (int i = 0; i < descriptor_->enum_type_count(); i++) { @@ -322,10 +322,6 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { GenerateMessageSerializationMethods(printer); - if (HasEqualsAndHashCode(descriptor_)) { - GenerateEqualsAndHashCode(printer); - } - GenerateParseFromMethods(printer); GenerateBuilder(printer); @@ -342,16 +338,8 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { " com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,\n" " Object arg0, Object arg1) {\n" " switch (method) {\n" - " case PARSE_PARTIAL_FROM: {\n" - " return new $classname$(" - " (com.google.protobuf.CodedInputStream) arg0,\n" - " (com.google.protobuf.ExtensionRegistryLite) arg1);\n" - " }\n" - " case NEW_INSTANCE: {\n" - " return new $classname$(\n" - " com.google.protobuf.Internal.EMPTY_CODED_INPUT_STREAM,\n" - " com.google.protobuf.ExtensionRegistryLite\n" - " .getEmptyRegistry());\n" + " case NEW_MUTABLE_INSTANCE: {\n" + " return new $classname$();\n" " }\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); @@ -382,10 +370,18 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "}\n" - "case MERGE_FROM: {\n"); + "case VISIT: {\n"); printer->Indent(); - GenerateDynamicMethodMergeFrom(printer); + GenerateDynamicMethodVisit(printer); + printer->Outdent(); + + printer->Print( + "}\n" + "case MERGE_FROM_STREAM: {\n"); + + printer->Indent(); + GenerateDynamicMethodMergeFromStream(printer); printer->Outdent(); printer->Print( @@ -433,11 +429,8 @@ void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) { printer->Print( "static {\n" - " DEFAULT_INSTANCE = new $classname$(\n" - " com.google.protobuf.Internal\n" - " .EMPTY_CODED_INPUT_STREAM,\n" - " com.google.protobuf.ExtensionRegistryLite\n" - " .getEmptyRegistry());\n" + " DEFAULT_INSTANCE = new $classname$();\n" + " DEFAULT_INSTANCE.makeImmutable();\n" "}\n" "\n", "classname", descriptor_->name()); @@ -802,11 +795,13 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodIsInitialized( void ImmutableMessageLiteGenerator::GenerateDynamicMethodMakeImmutable( io::Printer* printer) { + // Output generation code for each field. for (int i = 0; i < descriptor_->field_count(); i++) { field_generators_.get(descriptor_->field(i)) .GenerateDynamicMethodMakeImmutableCode(printer); } + printer->Print( "return null;\n"); } @@ -821,19 +816,17 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodNewBuilder( // =================================================================== -void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( +void ImmutableMessageLiteGenerator::GenerateDynamicMethodVisit( io::Printer* printer) { printer->Print( - // Optimization: If other is the default instance, we know none of its - // fields are set so we can skip the merge. - "if (arg0 == $classname$.getDefaultInstance()) return this;\n" - "$classname$ other = ($classname$) arg0;\n", + "Visitor visitor = (Visitor) arg0;\n" + "$classname$ other = ($classname$) arg1;\n", "classname", name_resolver_->GetImmutableClassName(descriptor_)); for (int i = 0; i < descriptor_->field_count(); i++) { if (!descriptor_->field(i)->containing_oneof()) { field_generators_.get( - descriptor_->field(i)).GenerateMergingCode(printer); + descriptor_->field(i)).GenerateVisitCode(printer); } } @@ -852,7 +845,7 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( "field_name", ToUpper(field->name())); printer->Indent(); - field_generators_.get(field).GenerateMergingCode(printer); + field_generators_.get(field).GenerateVisitCode(printer); printer->Print( "break;\n"); printer->Outdent(); @@ -861,26 +854,52 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( } printer->Print( "case $cap_oneof_name$_NOT_SET: {\n" + " visitor.visitOneofNotSet($oneof_name$Case_ != 0);\n" " break;\n" "}\n", "cap_oneof_name", ToUpper(context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name)); + descriptor_->oneof_decl(i))->name), + "oneof_name", + context_->GetOneofGeneratorInfo( + descriptor_->oneof_decl(i))->name); printer->Outdent(); printer->Print( "}\n"); } - // if message type has extensions - if (descriptor_->extension_range_count() > 0) { + printer->Print( + "if (visitor == com.google.protobuf.GeneratedMessageLite.MergeFromVisitor\n" + " .INSTANCE) {\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->oneof_decl_count(); ++i) { + const OneofDescriptor* field = descriptor_->oneof_decl(i); printer->Print( - "this.mergeExtensionFields(other);\n"); + "if (other.$oneof_name$Case_ != 0) {\n" + " $oneof_name$Case_ = other.$oneof_name$Case_;\n" + "}\n", + "oneof_name", context_->GetOneofGeneratorInfo(field)->name); } - if (PreserveUnknownFields(descriptor_)) { - printer->Print( - "this.mergeUnknownFields(other.unknownFields);\n"); + if (GenerateHasBits(descriptor_)) { + // Integers for bit fields. + int totalBits = 0; + for (int i = 0; i < descriptor_->field_count(); i++) { + totalBits += field_generators_.get(descriptor_->field(i)) + .GetNumBitsForMessage(); + } + int totalInts = (totalBits + 31) / 32; + + for (int i = 0; i < totalInts; i++) { + printer->Print( + "$bit_field_name$ |= other.$bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } } + printer->Outdent(); + printer->Print( + "}\n"); + printer->Print( "return this;\n"); @@ -888,227 +907,13 @@ void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFrom( // =================================================================== -namespace { -bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) { - if (field->is_repeated()) { - return false; - } - if (SupportFieldPresence(field->file())) { - return true; - } - return GetJavaType(field) == JAVATYPE_MESSAGE && - field->containing_oneof() == NULL; -} -} // namespace - -void ImmutableMessageLiteGenerator:: -GenerateEqualsAndHashCode(io::Printer* printer) { - printer->Print( - "@java.lang.Override\n" - "public boolean equals(final java.lang.Object obj) {\n"); - printer->Indent(); - printer->Print( - "if (obj == this) {\n" - " return true;\n" - "}\n" - "if (!(obj instanceof $classname$)) {\n" - " return super.equals(obj);\n" - "}\n" - "$classname$ other = ($classname$) obj;\n" - "\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - - printer->Print("boolean result = true;\n"); - // Compare non-oneofs. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (field->containing_oneof() == NULL) { - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { - printer->Print( - "result = result && (has$name$() == other.has$name$());\n" - "if (has$name$()) {\n", - "name", info->capitalized_name); - printer->Indent(); - } - field_generators_.get(field).GenerateEqualsCode(printer); - if (check_has_bits) { - printer->Outdent(); - printer->Print( - "}\n"); - } - } - } - - // Compare oneofs. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "result = result && get$oneof_capitalized_name$Case().equals(\n" - " other.get$oneof_capitalized_name$Case());\n", - "oneof_capitalized_name", - context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->capitalized_name); - printer->Print( - "if (!result) return false;\n" - "switch ($oneof_name$Case_) {\n", - "oneof_name", - context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); - printer->Print( - "case $field_number$:\n", - "field_number", - SimpleItoa(field->number())); - printer->Indent(); - field_generators_.get(field).GenerateEqualsCode(printer); - printer->Print("break;\n"); - printer->Outdent(); - } - printer->Print( - "case 0:\n" - "default:\n"); - printer->Outdent(); - printer->Print("}\n"); - } - - if (PreserveUnknownFields(descriptor_)) { - // Always consider unknown fields for equality. This will sometimes return - // false for non-canonical ordering when running in LITE_RUNTIME but it's - // the best we can do. - printer->Print( - "result = result && unknownFields.equals(other.unknownFields);\n"); - } - printer->Print( - "return result;\n"); - printer->Outdent(); - printer->Print( - "}\n" - "\n"); - - printer->Print( - "@java.lang.Override\n" - "public int hashCode() {\n"); - printer->Indent(); - printer->Print( - "if (memoizedHashCode != 0) {\n"); - printer->Indent(); - printer->Print( - "return memoizedHashCode;\n"); - printer->Outdent(); - printer->Print( - "}\n" - "int hash = 41;\n"); - - // Include the hash of the class so that two objects with different types - // but the same field values will probably have different hashes. - printer->Print("hash = (19 * hash) + $classname$.class.hashCode();\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); - - // hashCode non-oneofs. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = descriptor_->field(i); - if (field->containing_oneof() == NULL) { - const FieldGeneratorInfo* info = context_->GetFieldGeneratorInfo(field); - bool check_has_bits = CheckHasBitsForEqualsAndHashCode(field); - if (check_has_bits) { - printer->Print( - "if (has$name$()) {\n", - "name", info->capitalized_name); - printer->Indent(); - } - field_generators_.get(field).GenerateHashCode(printer); - if (check_has_bits) { - printer->Outdent(); - printer->Print("}\n"); - } - } - } - - // hashCode oneofs. - for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { - printer->Print( - "switch ($oneof_name$Case_) {\n", - "oneof_name", - context_->GetOneofGeneratorInfo( - descriptor_->oneof_decl(i))->name); - printer->Indent(); - for (int j = 0; j < descriptor_->oneof_decl(i)->field_count(); j++) { - const FieldDescriptor* field = descriptor_->oneof_decl(i)->field(j); - printer->Print( - "case $field_number$:\n", - "field_number", - SimpleItoa(field->number())); - printer->Indent(); - field_generators_.get(field).GenerateHashCode(printer); - printer->Print("break;\n"); - printer->Outdent(); - } - printer->Print( - "case 0:\n" - "default:\n"); - printer->Outdent(); - printer->Print("}\n"); - } - - printer->Print( - "hash = (29 * hash) + unknownFields.hashCode();\n"); - printer->Print( - "memoizedHashCode = hash;\n" - "return hash;\n"); - printer->Outdent(); - printer->Print( - "}\n" - "\n"); -} - -// =================================================================== - -void ImmutableMessageLiteGenerator:: -GenerateExtensionRegistrationCode(io::Printer* printer) { - for (int i = 0; i < descriptor_->extension_count(); i++) { - ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) - .GenerateRegistrationCode(printer); - } - - for (int i = 0; i < descriptor_->nested_type_count(); i++) { - ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) - .GenerateExtensionRegistrationCode(printer); - } -} - -// =================================================================== -void ImmutableMessageLiteGenerator:: -GenerateParsingConstructor(io::Printer* printer) { - google::protobuf::scoped_array sorted_fields( - SortFieldsByNumber(descriptor_)); - - printer->Print( - "private $classname$(\n" - " com.google.protobuf.CodedInputStream input,\n" - " com.google.protobuf.ExtensionRegistryLite extensionRegistry) {\n", - "classname", descriptor_->name()); - printer->Indent(); - - // Initialize all fields to default. - GenerateInitializers(printer); - - // Use builder bits to track mutable repeated fields. - int totalBuilderBits = 0; - for (int i = 0; i < descriptor_->field_count(); i++) { - const ImmutableFieldLiteGenerator& field = - field_generators_.get(descriptor_->field(i)); - totalBuilderBits += field.GetNumBitsForBuilder(); - } - int totalBuilderInts = (totalBuilderBits + 31) / 32; - for (int i = 0; i < totalBuilderInts; i++) { - printer->Print("int mutable_$bit_field_name$ = 0;\n", - "bit_field_name", GetBitFieldName(i)); - } - +void ImmutableMessageLiteGenerator::GenerateDynamicMethodMergeFromStream( + io::Printer* printer) { printer->Print( + "com.google.protobuf.CodedInputStream input =\n" + " (com.google.protobuf.CodedInputStream) arg0;\n" + "com.google.protobuf.ExtensionRegistryLite extensionRegistry =\n" + " (com.google.protobuf.ExtensionRegistryLite) arg1;\n" "try {\n"); printer->Indent(); @@ -1156,6 +961,8 @@ GenerateParsingConstructor(io::Printer* printer) { "}\n"); } + google::protobuf::scoped_array sorted_fields( + SortFieldsByNumber(descriptor_)); for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; uint32 tag = WireFormatLite::MakeTag(field->number(), @@ -1209,19 +1016,54 @@ GenerateParsingConstructor(io::Printer* printer) { "} finally {\n"); printer->Indent(); - // Make repeated field list immutable. - for (int i = 0; i < descriptor_->field_count(); i++) { - const FieldDescriptor* field = sorted_fields[i]; - field_generators_.get(field).GenerateParsingDoneCode(printer); + printer->Outdent(); + printer->Print( + "}\n"); // finally +} + +// =================================================================== + +namespace { +bool CheckHasBitsForEqualsAndHashCode(const FieldDescriptor* field) { + if (field->is_repeated()) { + return false; + } + if (SupportFieldPresence(field->file())) { + return true; + } + return GetJavaType(field) == JAVATYPE_MESSAGE && + field->containing_oneof() == NULL; +} +} // namespace + +// =================================================================== + +void ImmutableMessageLiteGenerator:: +GenerateExtensionRegistrationCode(io::Printer* printer) { + for (int i = 0; i < descriptor_->extension_count(); i++) { + ImmutableExtensionLiteGenerator(descriptor_->extension(i), context_) + .GenerateRegistrationCode(printer); } + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + ImmutableMessageLiteGenerator(descriptor_->nested_type(i), context_) + .GenerateExtensionRegistrationCode(printer); + } +} + +// =================================================================== +void ImmutableMessageLiteGenerator:: +GenerateConstructor(io::Printer* printer) { printer->Print( - "doneParsing();\n"); + "private $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + + // Initialize all fields to default. + GenerateInitializers(printer); - printer->Outdent(); printer->Outdent(); printer->Print( - " }\n" // finally "}\n"); } diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h index c8ee99bd..292c1c56 100644 --- a/src/google/protobuf/compiler/java/java_message_lite.h +++ b/src/google/protobuf/compiler/java/java_message_lite.h @@ -70,12 +70,13 @@ class ImmutableMessageLiteGenerator : public MessageGenerator { void GenerateBuilder(io::Printer* printer); void GenerateDynamicMethodIsInitialized(io::Printer* printer); void GenerateDynamicMethodMakeImmutable(io::Printer* printer); - void GenerateDynamicMethodMergeFrom(io::Printer* printer); + void GenerateDynamicMethodVisit(io::Printer* printer); + void GenerateDynamicMethodMergeFromStream(io::Printer* printer); void GenerateDynamicMethodNewBuilder(io::Printer* printer); void GenerateInitializers(io::Printer* printer); void GenerateEqualsAndHashCode(io::Printer* printer); void GenerateParser(io::Printer* printer); - void GenerateParsingConstructor(io::Printer* printer); + void GenerateConstructor(io::Printer* printer); Context* context_; ClassNameResolver* name_resolver_; diff --git a/src/google/protobuf/compiler/java/java_plugin_unittest.cc b/src/google/protobuf/compiler/java/java_plugin_unittest.cc index fe527623..3e4910c8 100644 --- a/src/google/protobuf/compiler/java/java_plugin_unittest.cc +++ b/src/google/protobuf/compiler/java/java_plugin_unittest.cc @@ -44,9 +44,10 @@ #include #include +#include +#include #include #include -#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc index d277e4f3..690dad12 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc @@ -86,9 +86,6 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, case JAVATYPE_BOOLEAN: (*variables)["field_list_type"] = "com.google.protobuf.Internal." + capitalized_type + "List"; - (*variables)["new_list"] = "new" + capitalized_type + "List"; - (*variables)["new_list_with_capacity"] = - "new" + capitalized_type + "ListWithCapacity"; (*variables)["empty_list"] = "empty" + capitalized_type + "List()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; @@ -98,19 +95,21 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["name"] + "_.add" + capitalized_type; (*variables)["repeated_set"] = (*variables)["name"] + "_.set" + capitalized_type; + (*variables)["visit_type"] = capitalized_type; + (*variables)["visit_type_list"] = "visit" + capitalized_type + "List"; break; default: (*variables)["field_list_type"] = "com.google.protobuf.Internal.ProtobufList<" + (*variables)["boxed_type"] + ">"; - (*variables)["new_list"] = "newProtobufList"; - (*variables)["new_list_with_capacity"] = "newProtobufListWithCapacity"; (*variables)["empty_list"] = "emptyProtobufList()"; (*variables)["make_name_unmodifiable"] = (*variables)["name"] + "_.makeImmutable()"; (*variables)["repeated_get"] = (*variables)["name"] + "_.get"; (*variables)["repeated_add"] = (*variables)["name"] + "_.add"; (*variables)["repeated_set"] = (*variables)["name"] + "_.set"; + (*variables)["visit_type"] = "ByteString"; + (*variables)["visit_type_list"] = "visitList"; } if (IsReferenceType(GetJavaType(descriptor))) { @@ -297,17 +296,16 @@ GenerateBuilderClearCode(io::Printer* printer) const { } void ImmutablePrimitiveFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { printer->Print(variables_, - "if (other.has$capitalized_name$()) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visit$visit_type$(\n" + " has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } else { printer->Print(variables_, - "if (other.get$capitalized_name$() != $default$) {\n" - " set$capitalized_name$(other.get$capitalized_name$());\n" - "}\n"); + "$name$_ = visitor.visit$visit_type$($name$_ != $default$, $name$_,\n" + " other.$name$_ != $default$, other.$name$_);\n"); } } @@ -539,9 +537,10 @@ GenerateBuildingCode(io::Printer* printer) const { } void ImmutablePrimitiveOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "set$capitalized_name$(other.get$capitalized_name$());\n"); + "$oneof_name$_ = visitor.visitOneof$visit_type$(\n" + " $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n"); } void ImmutablePrimitiveOneofFieldLiteGenerator:: @@ -641,7 +640,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = $new_list$($name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n"); @@ -742,21 +742,9 @@ GenerateBuilderClearCode(io::Printer* printer) const { } void RepeatedImmutablePrimitiveFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations: - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - "}\n"); + "$name$_= visitor.$visit_type_list$($name$_, other.$name$_);\n"); } void RepeatedImmutablePrimitiveFieldLiteGenerator:: @@ -777,7 +765,8 @@ GenerateParsingCode(io::Printer* printer) const { // TODO(dweis): Scan the input buffer to count and ensure capacity. printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = $new_list$();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n" "$repeated_add$(input.read$capitalized_type$());\n"); } @@ -794,10 +783,13 @@ GenerateParsingCodeFromPacked(io::Printer* printer) const { // TODO(dweis): Scan the input buffer to count, then initialize // appropriately. printer->Print(variables_, - " $name$_ = $new_list$();\n"); + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n"); } else { printer->Print(variables_, - " $name$_ = $new_list_with_capacity$(length/$fixed_size$);\n"); + " final int currentSize = $name$_.size();\n" + " $name$_ = $name$_.mutableCopyWithCapacity(\n" + " currentSize + (length/$fixed_size$));\n"); } // TODO(dweis): Scan the input buffer to count and ensure capacity. diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.h b/src/google/protobuf/compiler/java/java_primitive_field_lite.h index ad603c2a..6cfbbb98 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field_lite.h +++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.h @@ -69,7 +69,7 @@ class ImmutablePrimitiveFieldLiteGenerator void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; void GenerateBuilderClearCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -105,7 +105,7 @@ class ImmutablePrimitiveOneofFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -130,7 +130,7 @@ class RepeatedImmutablePrimitiveFieldLiteGenerator void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; void GenerateBuilderClearCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.cc b/src/google/protobuf/compiler/java/java_string_field_lite.cc index 9012ab5e..0b92c021 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.cc +++ b/src/google/protobuf/compiler/java/java_string_field_lite.cc @@ -299,20 +299,16 @@ GenerateInitializationCode(io::Printer* printer) const { } void ImmutableStringFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { +GenerateVisitCode(io::Printer* printer) const { if (SupportFieldPresence(descriptor_->file())) { - // 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_, - "if (other.has$capitalized_name$()) {\n" - " $set_has_field_bit_message$\n" - " $name$_ = other.$name$_;\n" - "}\n"); + "$name$_ = visitor.visitString(\n" + " has$capitalized_name$(), $name$_,\n" + " other.has$capitalized_name$(), other.$name$_);\n"); } else { printer->Print(variables_, - "if (!other.get$capitalized_name$().isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - "}\n"); + "$name$_ = visitor.visitString(!$name$_.isEmpty(), $name$_,\n" + " !other.$name$_.isEmpty(), other.$name$_);\n"); } } @@ -519,12 +515,10 @@ GenerateBuilderMembers(io::Printer* printer) const { } void ImmutableStringOneofFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // Allow a slight breach of abstraction here in order to avoid forcing - // all string fields to Strings when copying fields from a Message. +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "$set_oneof_case_message$;\n" - "$oneof_name$_ = other.$oneof_name$_;\n"); + "$oneof_name$_ = visitor.visitOneofString(\n" + " $has_oneof_case_message$, $oneof_name$_, other.$oneof_name$_);\n"); } void ImmutableStringOneofFieldLiteGenerator:: @@ -645,8 +639,8 @@ GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private void ensure$capitalized_name$IsMutable() {\n" " if (!$is_mutable$) {\n" - " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList(\n" - " $name$_);\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" " }\n" "}\n"); @@ -773,21 +767,9 @@ GenerateInitializationCode(io::Printer* printer) const { } void RepeatedImmutableStringFieldLiteGenerator:: -GenerateMergingCode(io::Printer* printer) const { - // The code below does two optimizations: - // 1. If the other list is empty, there's nothing to do. This ensures we - // don't allocate a new array if we already have an immutable one. - // 2. If the other list is non-empty and our current list is empty, we can - // reuse the other list which is guaranteed to be immutable. +GenerateVisitCode(io::Printer* printer) const { printer->Print(variables_, - "if (!other.$name$_.isEmpty()) {\n" - " if ($name$_.isEmpty()) {\n" - " $name$_ = other.$name$_;\n" - " } else {\n" - " ensure$capitalized_name$IsMutable();\n" - " $name$_.addAll(other.$name$_);\n" - " }\n" - "}\n"); + "$name$_= visitor.visitList($name$_, other.$name$_);\n"); } void RepeatedImmutableStringFieldLiteGenerator:: @@ -811,7 +793,8 @@ GenerateParsingCode(io::Printer* printer) const { } printer->Print(variables_, "if (!$is_mutable$) {\n" - " $name$_ = com.google.protobuf.GeneratedMessageLite.newProtobufList();\n" + " $name$_ =\n" + " com.google.protobuf.GeneratedMessageLite.mutableCopy($name$_);\n" "}\n"); printer->Print(variables_, "$name$_.add(s);\n"); diff --git a/src/google/protobuf/compiler/java/java_string_field_lite.h b/src/google/protobuf/compiler/java/java_string_field_lite.h index 4d9b4bd7..4148aa4d 100644 --- a/src/google/protobuf/compiler/java/java_string_field_lite.h +++ b/src/google/protobuf/compiler/java/java_string_field_lite.h @@ -68,7 +68,7 @@ class ImmutableStringFieldLiteGenerator : public ImmutableFieldLiteGenerator { void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; @@ -103,7 +103,7 @@ class ImmutableStringOneofFieldLiteGenerator private: void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; @@ -126,7 +126,7 @@ class RepeatedImmutableStringFieldLiteGenerator void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; void GenerateInitializationCode(io::Printer* printer) const; - void GenerateMergingCode(io::Printer* printer) const; + void GenerateVisitCode(io::Printer* printer) const; void GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; void GenerateParsingDoneCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index 534a5b5b..3de61e80 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -1909,7 +1909,7 @@ void Generator::GenerateClassToObject(const GeneratorOptions& options, printer->Print( " if (includeInstance) {\n" - " obj.$$jspbMessageInstance = msg\n" + " obj.$$jspbMessageInstance = msg;\n" " }\n" " return obj;\n" "};\n" @@ -3032,8 +3032,7 @@ bool Generator::GenerateAll(const vector& files, const google::protobuf::FileDescriptor* file = files[i]; string filename = options.output_dir + "/" + GetJSFilename(file->name()); - scoped_ptr output( - context->Open(filename)); + google::protobuf::scoped_ptr output(context->Open(filename)); GOOGLE_CHECK(output.get()); io::Printer printer(output.get(), '$'); diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index a2da8eee..e9d50a1d 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -240,6 +240,7 @@ CodeGeneratorRequest* CodeGeneratorRequest::New(::google::protobuf::Arena* arena } void CodeGeneratorRequest::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorRequest) if (has_parameter()) { parameter_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -253,7 +254,7 @@ void CodeGeneratorRequest::Clear() { bool CodeGeneratorRequest::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorRequest) for (;;) { @@ -412,6 +413,7 @@ void CodeGeneratorRequest::SerializeWithCachedSizes( } int CodeGeneratorRequest::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorRequest) int total_size = 0; // optional string parameter = 2; @@ -448,18 +450,22 @@ int CodeGeneratorRequest::ByteSize() const { } void CodeGeneratorRequest::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const CodeGeneratorRequest* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorRequest) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorRequest) MergeFrom(*source); } } void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorRequest) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); file_to_generate_.MergeFrom(from.file_to_generate_); proto_file_.MergeFrom(from.proto_file_); @@ -475,12 +481,14 @@ void CodeGeneratorRequest::MergeFrom(const CodeGeneratorRequest& from) { } void CodeGeneratorRequest::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest) if (&from == this) return; Clear(); MergeFrom(from); } void CodeGeneratorRequest::CopyFrom(const CodeGeneratorRequest& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorRequest) if (&from == this) return; Clear(); MergeFrom(from); @@ -545,6 +553,7 @@ void CodeGeneratorRequest::clear_file_to_generate() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } ::std::string* CodeGeneratorRequest::add_file_to_generate() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) return file_to_generate_.Add(); } void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { @@ -610,6 +619,7 @@ void CodeGeneratorRequest::clear_parameter() { return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* CodeGeneratorRequest::release_parameter() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter) clear_has_parameter(); return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -728,6 +738,7 @@ CodeGeneratorResponse_File* CodeGeneratorResponse_File::New(::google::protobuf:: } void CodeGeneratorResponse_File::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (_has_bits_[0 / 32] & 7u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -747,7 +758,7 @@ void CodeGeneratorResponse_File::Clear() { bool CodeGeneratorResponse_File::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse.File) for (;;) { @@ -912,6 +923,7 @@ void CodeGeneratorResponse_File::SerializeWithCachedSizes( } int CodeGeneratorResponse_File::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse.File) int total_size = 0; if (_has_bits_[0 / 32] & 7u) { @@ -949,18 +961,22 @@ int CodeGeneratorResponse_File::ByteSize() const { } void CodeGeneratorResponse_File::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const CodeGeneratorResponse_File* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorResponse.File) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse.File) MergeFrom(*source); } } void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -982,12 +998,14 @@ void CodeGeneratorResponse_File::MergeFrom(const CodeGeneratorResponse_File& fro } void CodeGeneratorResponse_File::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (&from == this) return; Clear(); MergeFrom(from); } void CodeGeneratorResponse_File::CopyFrom(const CodeGeneratorResponse_File& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse.File) if (&from == this) return; Clear(); MergeFrom(from); @@ -1088,6 +1106,7 @@ CodeGeneratorResponse* CodeGeneratorResponse::New(::google::protobuf::Arena* are } void CodeGeneratorResponse::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.compiler.CodeGeneratorResponse) if (has_error()) { error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1100,7 +1119,7 @@ void CodeGeneratorResponse::Clear() { bool CodeGeneratorResponse::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.compiler.CodeGeneratorResponse) for (;;) { @@ -1219,6 +1238,7 @@ void CodeGeneratorResponse::SerializeWithCachedSizes( } int CodeGeneratorResponse::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.compiler.CodeGeneratorResponse) int total_size = 0; // optional string error = 1; @@ -1248,18 +1268,22 @@ int CodeGeneratorResponse::ByteSize() const { } void CodeGeneratorResponse::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const CodeGeneratorResponse* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.compiler.CodeGeneratorResponse) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.compiler.CodeGeneratorResponse) MergeFrom(*source); } } void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.compiler.CodeGeneratorResponse) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); file_.MergeFrom(from.file_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -1274,12 +1298,14 @@ void CodeGeneratorResponse::MergeFrom(const CodeGeneratorResponse& from) { } void CodeGeneratorResponse::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse) if (&from == this) return; Clear(); MergeFrom(from); } void CodeGeneratorResponse::CopyFrom(const CodeGeneratorResponse& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.compiler.CodeGeneratorResponse) if (&from == this) return; Clear(); MergeFrom(from); @@ -1353,6 +1379,7 @@ void CodeGeneratorResponse_File::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* CodeGeneratorResponse_File::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1406,6 +1433,7 @@ void CodeGeneratorResponse_File::clear_insertion_point() { return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* CodeGeneratorResponse_File::release_insertion_point() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) clear_has_insertion_point(); return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1459,6 +1487,7 @@ void CodeGeneratorResponse_File::clear_content() { return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* CodeGeneratorResponse_File::release_content() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content) clear_has_content(); return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1516,6 +1545,7 @@ void CodeGeneratorResponse::clear_error() { return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* CodeGeneratorResponse::release_error() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error) clear_has_error(); return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 0a03e979..510202f0 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -437,6 +437,7 @@ inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* va // @@protoc_insertion_point(field_set_pointer:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) } inline ::std::string* CodeGeneratorRequest::add_file_to_generate() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.compiler.CodeGeneratorRequest.file_to_generate) return file_to_generate_.Add(); } inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { @@ -502,6 +503,7 @@ inline ::std::string* CodeGeneratorRequest::mutable_parameter() { return parameter_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* CodeGeneratorRequest::release_parameter() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorRequest.parameter) clear_has_parameter(); return parameter_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -589,6 +591,7 @@ inline ::std::string* CodeGeneratorResponse_File::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* CodeGeneratorResponse_File::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -642,6 +645,7 @@ inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { return insertion_point_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.insertion_point) clear_has_insertion_point(); return insertion_point_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -695,6 +699,7 @@ inline ::std::string* CodeGeneratorResponse_File::mutable_content() { return content_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* CodeGeneratorResponse_File::release_content() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.File.content) clear_has_content(); return content_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -752,6 +757,7 @@ inline ::std::string* CodeGeneratorResponse::mutable_error() { return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* CodeGeneratorResponse::release_error() { + // @@protoc_insertion_point(field_release:google.protobuf.compiler.CodeGeneratorResponse.error) clear_has_error(); return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/compiler/python/python_plugin_unittest.cc b/src/google/protobuf/compiler/python/python_plugin_unittest.cc index e82bbae7..23f2449c 100644 --- a/src/google/protobuf/compiler/python/python_plugin_unittest.cc +++ b/src/google/protobuf/compiler/python/python_plugin_unittest.cc @@ -44,9 +44,10 @@ #include #include +#include +#include #include #include -#include namespace google { namespace protobuf { diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index 78a34617..56e11fa9 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -357,13 +357,20 @@ void DeleteAllowedProto3Extendee() { void InitAllowedProto3Extendee() { allowed_proto3_extendees_ = new set; - allowed_proto3_extendees_->insert("google.protobuf.FileOptions"); - allowed_proto3_extendees_->insert("google.protobuf.MessageOptions"); - allowed_proto3_extendees_->insert("google.protobuf.FieldOptions"); - allowed_proto3_extendees_->insert("google.protobuf.EnumOptions"); - allowed_proto3_extendees_->insert("google.protobuf.EnumValueOptions"); - allowed_proto3_extendees_->insert("google.protobuf.ServiceOptions"); - allowed_proto3_extendees_->insert("google.protobuf.MethodOptions"); + const char* kOptionNames[] = { + "FileOptions", "MessageOptions", "FieldOptions", "EnumOptions", + "EnumValueOptions", "ServiceOptions", "MethodOptions"}; + for (int i = 0; i < GOOGLE_ARRAYSIZE(kOptionNames); ++i) { + // descriptor.proto has a different package name in opensource. We allow + // both so the opensource protocol compiler can also compile internal + // proto3 files with custom options. See: b/27567912 + allowed_proto3_extendees_->insert(string("google.protobuf.") + + kOptionNames[i]); + // Split the word to trick the opensource processing scripts so they + // will keep the origial package name. + allowed_proto3_extendees_->insert(string("proto") + "2." + kOptionNames[i]); + } + google::protobuf::internal::OnShutdown(&DeleteAllowedProto3Extendee); } @@ -2766,6 +2773,9 @@ class DescriptorBuilder { private: friend class OptionInterpreter; + // Non-recursive part of BuildFile functionality. + const FileDescriptor* BuildFileImpl(const FileDescriptorProto& proto); + const DescriptorPool* pool_; DescriptorPool::Tables* tables_; // for convenience DescriptorPool::ErrorCollector* error_collector_; @@ -3834,7 +3844,11 @@ const FileDescriptor* DescriptorBuilder::BuildFile( } tables_->pending_files_.pop_back(); } + return BuildFileImpl(proto); +} +const FileDescriptor* DescriptorBuilder::BuildFileImpl( + const FileDescriptorProto& proto) { // Checkpoint the tables so that we can roll back if something goes wrong. tables_->AddCheckpoint(); @@ -5113,11 +5127,6 @@ void DescriptorBuilder::ValidateProto3( for (int i = 0; i < file->enum_type_count(); ++i) { ValidateProto3Enum(file->enum_types_ + i, proto.enum_type(i)); } - if (IsLite(file)) { - AddError(file->name(), proto, - DescriptorPool::ErrorCollector::OTHER, - "Lite runtime is not supported in proto3."); - } } static string ToLowercaseWithoutUnderscores(const string& name) { diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 1338537e..50d1cc6e 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -944,6 +944,7 @@ FileDescriptorSet* FileDescriptorSet::New(::google::protobuf::Arena* arena) cons } void FileDescriptorSet::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorSet) file_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { @@ -953,7 +954,7 @@ void FileDescriptorSet::Clear() { bool FileDescriptorSet::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorSet) for (;;) { @@ -1034,6 +1035,7 @@ void FileDescriptorSet::SerializeWithCachedSizes( } int FileDescriptorSet::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorSet) int total_size = 0; // repeated .google.protobuf.FileDescriptorProto file = 1; @@ -1056,18 +1058,22 @@ int FileDescriptorSet::ByteSize() const { } void FileDescriptorSet::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorSet) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FileDescriptorSet* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileDescriptorSet) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileDescriptorSet) MergeFrom(*source); } } void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorSet) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); file_.MergeFrom(from.file_); if (from._internal_metadata_.have_unknown_fields()) { @@ -1076,12 +1082,14 @@ void FileDescriptorSet::MergeFrom(const FileDescriptorSet& from) { } void FileDescriptorSet::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileDescriptorSet) if (&from == this) return; Clear(); MergeFrom(from); } void FileDescriptorSet::CopyFrom(const FileDescriptorSet& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorSet) if (&from == this) return; Clear(); MergeFrom(from); @@ -1235,6 +1243,7 @@ FileDescriptorProto* FileDescriptorProto::New(::google::protobuf::Arena* arena) } void FileDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FileDescriptorProto) if (_has_bits_[0 / 32] & 3u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -1269,7 +1278,7 @@ void FileDescriptorProto::Clear() { bool FileDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FileDescriptorProto) for (;;) { @@ -1704,6 +1713,7 @@ void FileDescriptorProto::SerializeWithCachedSizes( } int FileDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -1816,18 +1826,22 @@ int FileDescriptorProto::ByteSize() const { } void FileDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FileDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileDescriptorProto) MergeFrom(*source); } } void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); dependency_.MergeFrom(from.dependency_); public_dependency_.MergeFrom(from.public_dependency_); @@ -1864,12 +1878,14 @@ void FileDescriptorProto::MergeFrom(const FileDescriptorProto& from) { } void FileDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void FileDescriptorProto::CopyFrom(const FileDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -1960,6 +1976,7 @@ void FileDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2013,6 +2030,7 @@ void FileDescriptorProto::clear_package() { return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileDescriptorProto::release_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package) clear_has_package(); return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2055,6 +2073,7 @@ void FileDescriptorProto::clear_dependency() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency) } ::std::string* FileDescriptorProto::add_dependency() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency) return dependency_.Add(); } void FileDescriptorProto::add_dependency(const ::std::string& value) { @@ -2287,6 +2306,7 @@ const ::google::protobuf::FileOptions& FileDescriptorProto::options() const { return options_; } ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options) clear_has_options(); ::google::protobuf::FileOptions* temp = options_; options_ = NULL; @@ -2330,6 +2350,7 @@ const ::google::protobuf::SourceCodeInfo& FileDescriptorProto::source_code_info( return source_code_info_; } ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info) clear_has_source_code_info(); ::google::protobuf::SourceCodeInfo* temp = source_code_info_; source_code_info_ = NULL; @@ -2386,6 +2407,7 @@ void FileDescriptorProto::clear_syntax() { return syntax_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileDescriptorProto::release_syntax() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax) clear_has_syntax(); return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2468,6 +2490,7 @@ DescriptorProto_ExtensionRange* DescriptorProto_ExtensionRange::New(::google::pr } void DescriptorProto_ExtensionRange::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ExtensionRange) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -2489,7 +2512,7 @@ void DescriptorProto_ExtensionRange::Clear() { bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ExtensionRange) for (;;) { @@ -2590,6 +2613,7 @@ void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( } int DescriptorProto_ExtensionRange::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ExtensionRange) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -2620,18 +2644,22 @@ int DescriptorProto_ExtensionRange::ByteSize() const { } void DescriptorProto_ExtensionRange::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DescriptorProto_ExtensionRange* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto.ExtensionRange) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto.ExtensionRange) MergeFrom(*source); } } void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRange& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_start()) { @@ -2647,12 +2675,14 @@ void DescriptorProto_ExtensionRange::MergeFrom(const DescriptorProto_ExtensionRa } void DescriptorProto_ExtensionRange::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (&from == this) return; Clear(); MergeFrom(from); } void DescriptorProto_ExtensionRange::CopyFrom(const DescriptorProto_ExtensionRange& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ExtensionRange) if (&from == this) return; Clear(); MergeFrom(from); @@ -2751,6 +2781,7 @@ DescriptorProto_ReservedRange* DescriptorProto_ReservedRange::New(::google::prot } void DescriptorProto_ReservedRange::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto.ReservedRange) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -2772,7 +2803,7 @@ void DescriptorProto_ReservedRange::Clear() { bool DescriptorProto_ReservedRange::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto.ReservedRange) for (;;) { @@ -2873,6 +2904,7 @@ void DescriptorProto_ReservedRange::SerializeWithCachedSizes( } int DescriptorProto_ReservedRange::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto.ReservedRange) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -2903,18 +2935,22 @@ int DescriptorProto_ReservedRange::ByteSize() const { } void DescriptorProto_ReservedRange::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto.ReservedRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DescriptorProto_ReservedRange* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto.ReservedRange) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto.ReservedRange) MergeFrom(*source); } } void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRange& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto.ReservedRange) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_start()) { @@ -2930,12 +2966,14 @@ void DescriptorProto_ReservedRange::MergeFrom(const DescriptorProto_ReservedRang } void DescriptorProto_ReservedRange::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto.ReservedRange) if (&from == this) return; Clear(); MergeFrom(from); } void DescriptorProto_ReservedRange::CopyFrom(const DescriptorProto_ReservedRange& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto.ReservedRange) if (&from == this) return; Clear(); MergeFrom(from); @@ -3046,6 +3084,7 @@ DescriptorProto* DescriptorProto::New(::google::protobuf::Arena* arena) const { } void DescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DescriptorProto) if (_has_bits_[0 / 32] & 129u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -3070,7 +3109,7 @@ void DescriptorProto::Clear() { bool DescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DescriptorProto) for (;;) { @@ -3429,6 +3468,7 @@ void DescriptorProto::SerializeWithCachedSizes( } int DescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 129u) { @@ -3522,18 +3562,22 @@ int DescriptorProto::ByteSize() const { } void DescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DescriptorProto) MergeFrom(*source); } } void DescriptorProto::MergeFrom(const DescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); field_.MergeFrom(from.field_); extension_.MergeFrom(from.extension_); @@ -3558,12 +3602,14 @@ void DescriptorProto::MergeFrom(const DescriptorProto& from) { } void DescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void DescriptorProto::CopyFrom(const DescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -3756,6 +3802,7 @@ void DescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* DescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3976,6 +4023,7 @@ const ::google::protobuf::MessageOptions& DescriptorProto::options() const { return options_; } ::google::protobuf::MessageOptions* DescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options) clear_has_options(); ::google::protobuf::MessageOptions* temp = options_; options_ = NULL; @@ -4051,6 +4099,7 @@ void DescriptorProto::clear_reserved_name() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name) } ::std::string* DescriptorProto::add_reserved_name() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name) return reserved_name_.Add(); } void DescriptorProto::add_reserved_name(const ::std::string& value) { @@ -4245,6 +4294,7 @@ FieldDescriptorProto* FieldDescriptorProto::New(::google::protobuf::Arena* arena } void FieldDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldDescriptorProto) if (_has_bits_[0 / 32] & 255u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -4279,7 +4329,7 @@ void FieldDescriptorProto::Clear() { bool FieldDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FieldDescriptorProto) for (;;) { @@ -4660,6 +4710,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( } int FieldDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 255u) { @@ -4746,18 +4797,22 @@ int FieldDescriptorProto::ByteSize() const { } void FieldDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FieldDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldDescriptorProto) MergeFrom(*source); } } void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -4804,12 +4859,14 @@ void FieldDescriptorProto::MergeFrom(const FieldDescriptorProto& from) { } void FieldDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void FieldDescriptorProto::CopyFrom(const FieldDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -4894,6 +4951,7 @@ void FieldDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5021,6 +5079,7 @@ void FieldDescriptorProto::clear_type_name() { return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_type_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name) clear_has_type_name(); return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5074,6 +5133,7 @@ void FieldDescriptorProto::clear_extendee() { return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_extendee() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee) clear_has_extendee(); return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5127,6 +5187,7 @@ void FieldDescriptorProto::clear_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value) clear_has_default_value(); return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5204,6 +5265,7 @@ void FieldDescriptorProto::clear_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FieldDescriptorProto::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name) clear_has_json_name(); return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5244,6 +5306,7 @@ const ::google::protobuf::FieldOptions& FieldDescriptorProto::options() const { return options_; } ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options) clear_has_options(); ::google::protobuf::FieldOptions* temp = options_; options_ = NULL; @@ -5329,6 +5392,7 @@ OneofDescriptorProto* OneofDescriptorProto::New(::google::protobuf::Arena* arena } void OneofDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofDescriptorProto) if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5340,7 +5404,7 @@ void OneofDescriptorProto::Clear() { bool OneofDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.OneofDescriptorProto) for (;;) { @@ -5429,6 +5493,7 @@ void OneofDescriptorProto::SerializeWithCachedSizes( } int OneofDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto) int total_size = 0; // optional string name = 1; @@ -5450,18 +5515,22 @@ int OneofDescriptorProto::ByteSize() const { } void OneofDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.OneofDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const OneofDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.OneofDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.OneofDescriptorProto) MergeFrom(*source); } } void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -5475,12 +5544,14 @@ void OneofDescriptorProto::MergeFrom(const OneofDescriptorProto& from) { } void OneofDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.OneofDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void OneofDescriptorProto::CopyFrom(const OneofDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -5553,6 +5624,7 @@ void OneofDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* OneofDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5640,6 +5712,7 @@ EnumDescriptorProto* EnumDescriptorProto::New(::google::protobuf::Arena* arena) } void EnumDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumDescriptorProto) if (_has_bits_[0 / 32] & 5u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -5657,7 +5730,7 @@ void EnumDescriptorProto::Clear() { bool EnumDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumDescriptorProto) for (;;) { @@ -5802,6 +5875,7 @@ void EnumDescriptorProto::SerializeWithCachedSizes( } int EnumDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 5u) { @@ -5840,18 +5914,22 @@ int EnumDescriptorProto::ByteSize() const { } void EnumDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumDescriptorProto) MergeFrom(*source); } } void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); value_.MergeFrom(from.value_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -5869,12 +5947,14 @@ void EnumDescriptorProto::MergeFrom(const EnumDescriptorProto& from) { } void EnumDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void EnumDescriptorProto::CopyFrom(const EnumDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -5953,6 +6033,7 @@ void EnumDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* EnumDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6023,6 +6104,7 @@ const ::google::protobuf::EnumOptions& EnumDescriptorProto::options() const { return options_; } ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumOptions* temp = options_; options_ = NULL; @@ -6114,6 +6196,7 @@ EnumValueDescriptorProto* EnumValueDescriptorProto::New(::google::protobuf::Aren } void EnumValueDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueDescriptorProto) if (_has_bits_[0 / 32] & 7u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -6131,7 +6214,7 @@ void EnumValueDescriptorProto::Clear() { bool EnumValueDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueDescriptorProto) for (;;) { @@ -6271,6 +6354,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( } int EnumValueDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 7u) { @@ -6308,18 +6392,22 @@ int EnumValueDescriptorProto::ByteSize() const { } void EnumValueDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumValueDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValueDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValueDescriptorProto) MergeFrom(*source); } } void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -6339,12 +6427,14 @@ void EnumValueDescriptorProto::MergeFrom(const EnumValueDescriptorProto& from) { } void EnumValueDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValueDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void EnumValueDescriptorProto::CopyFrom(const EnumValueDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -6422,6 +6512,7 @@ void EnumValueDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* EnumValueDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6486,6 +6577,7 @@ const ::google::protobuf::EnumValueOptions& EnumValueDescriptorProto::options() return options_; } ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumValueOptions* temp = options_; options_ = NULL; @@ -6576,6 +6668,7 @@ ServiceDescriptorProto* ServiceDescriptorProto::New(::google::protobuf::Arena* a } void ServiceDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceDescriptorProto) if (_has_bits_[0 / 32] & 5u) { if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -6593,7 +6686,7 @@ void ServiceDescriptorProto::Clear() { bool ServiceDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.ServiceDescriptorProto) for (;;) { @@ -6738,6 +6831,7 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( } int ServiceDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 5u) { @@ -6776,18 +6870,22 @@ int ServiceDescriptorProto::ByteSize() const { } void ServiceDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const ServiceDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ServiceDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ServiceDescriptorProto) MergeFrom(*source); } } void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); method_.MergeFrom(from.method_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -6805,12 +6903,14 @@ void ServiceDescriptorProto::MergeFrom(const ServiceDescriptorProto& from) { } void ServiceDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ServiceDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void ServiceDescriptorProto::CopyFrom(const ServiceDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -6889,6 +6989,7 @@ void ServiceDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* ServiceDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6959,6 +7060,7 @@ const ::google::protobuf::ServiceOptions& ServiceDescriptorProto::options() cons return options_; } ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options) clear_has_options(); ::google::protobuf::ServiceOptions* temp = options_; options_ = NULL; @@ -7058,6 +7160,7 @@ MethodDescriptorProto* MethodDescriptorProto::New(::google::protobuf::Arena* are } void MethodDescriptorProto::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodDescriptorProto) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -7093,7 +7196,7 @@ void MethodDescriptorProto::Clear() { bool MethodDescriptorProto::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.MethodDescriptorProto) for (;;) { @@ -7334,6 +7437,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( } int MethodDescriptorProto::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodDescriptorProto) int total_size = 0; if (_has_bits_[0 / 32] & 63u) { @@ -7388,18 +7492,22 @@ int MethodDescriptorProto::ByteSize() const { } void MethodDescriptorProto::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const MethodDescriptorProto* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MethodDescriptorProto) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MethodDescriptorProto) MergeFrom(*source); } } void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodDescriptorProto) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name()) { @@ -7430,12 +7538,14 @@ void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) { } void MethodDescriptorProto::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MethodDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); } void MethodDescriptorProto::CopyFrom(const MethodDescriptorProto& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodDescriptorProto) if (&from == this) return; Clear(); MergeFrom(from); @@ -7516,6 +7626,7 @@ void MethodDescriptorProto::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* MethodDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7569,6 +7680,7 @@ void MethodDescriptorProto::clear_input_type() { return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* MethodDescriptorProto::release_input_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type) clear_has_input_type(); return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7622,6 +7734,7 @@ void MethodDescriptorProto::clear_output_type() { return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* MethodDescriptorProto::release_output_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type) clear_has_output_type(); return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7662,6 +7775,7 @@ const ::google::protobuf::MethodOptions& MethodDescriptorProto::options() const return options_; } ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options) clear_has_options(); ::google::protobuf::MethodOptions* temp = options_; options_ = NULL; @@ -7849,6 +7963,7 @@ FileOptions* FileOptions::New(::google::protobuf::Arena* arena) const { } void FileOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FileOptions) _extensions_.Clear(); #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -7893,7 +8008,7 @@ void FileOptions::Clear() { bool FileOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FileOptions) for (;;) { @@ -8409,6 +8524,7 @@ void FileOptions::SerializeWithCachedSizes( } int FileOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FileOptions) int total_size = 0; if (_has_bits_[0 / 32] & 255u) { @@ -8518,18 +8634,22 @@ int FileOptions::ByteSize() const { } void FileOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FileOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FileOptions* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FileOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FileOptions) MergeFrom(*source); } } void FileOptions::MergeFrom(const FileOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FileOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -8590,12 +8710,14 @@ void FileOptions::MergeFrom(const FileOptions& from) { } void FileOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FileOptions) if (&from == this) return; Clear(); MergeFrom(from); } void FileOptions::CopyFrom(const FileOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FileOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -8685,6 +8807,7 @@ void FileOptions::clear_java_package() { return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_java_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package) clear_has_java_package(); return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -8738,6 +8861,7 @@ void FileOptions::clear_java_outer_classname() { return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_java_outer_classname() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname) clear_has_java_outer_classname(); return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -8888,6 +9012,7 @@ void FileOptions::clear_go_package() { return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_go_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package) clear_has_go_package(); return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -9061,6 +9186,7 @@ void FileOptions::clear_objc_class_prefix() { return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_objc_class_prefix() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix) clear_has_objc_class_prefix(); return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -9114,6 +9240,7 @@ void FileOptions::clear_csharp_namespace() { return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* FileOptions::release_csharp_namespace() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace) clear_has_csharp_namespace(); return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -9231,6 +9358,7 @@ MessageOptions* MessageOptions::New(::google::protobuf::Arena* arena) const { } void MessageOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.MessageOptions) _extensions_.Clear(); #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -9254,7 +9382,7 @@ void MessageOptions::Clear() { bool MessageOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.MessageOptions) for (;;) { @@ -9448,6 +9576,7 @@ void MessageOptions::SerializeWithCachedSizes( } int MessageOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MessageOptions) int total_size = 0; if (_has_bits_[0 / 32] & 15u) { @@ -9494,18 +9623,22 @@ int MessageOptions::ByteSize() const { } void MessageOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MessageOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const MessageOptions* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MessageOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MessageOptions) MergeFrom(*source); } } void MessageOptions::MergeFrom(const MessageOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MessageOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -9529,12 +9662,14 @@ void MessageOptions::MergeFrom(const MessageOptions& from) { } void MessageOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MessageOptions) if (&from == this) return; Clear(); MergeFrom(from); } void MessageOptions::CopyFrom(const MessageOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MessageOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -9824,6 +9959,7 @@ FieldOptions* FieldOptions::New(::google::protobuf::Arena* arena) const { } void FieldOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldOptions) _extensions_.Clear(); #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -9850,7 +9986,7 @@ void FieldOptions::Clear() { bool FieldOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FieldOptions) for (;;) { @@ -10108,6 +10244,7 @@ void FieldOptions::SerializeWithCachedSizes( } int FieldOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldOptions) int total_size = 0; if (_has_bits_[0 / 32] & 63u) { @@ -10166,18 +10303,22 @@ int FieldOptions::ByteSize() const { } void FieldOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FieldOptions* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldOptions) MergeFrom(*source); } } void FieldOptions::MergeFrom(const FieldOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -10207,12 +10348,14 @@ void FieldOptions::MergeFrom(const FieldOptions& from) { } void FieldOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldOptions) if (&from == this) return; Clear(); MergeFrom(from); } void FieldOptions::CopyFrom(const FieldOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -10500,6 +10643,7 @@ EnumOptions* EnumOptions::New(::google::protobuf::Arena* arena) const { } void EnumOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumOptions) _extensions_.Clear(); #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -10523,7 +10667,7 @@ void EnumOptions::Clear() { bool EnumOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumOptions) for (;;) { @@ -10667,6 +10811,7 @@ void EnumOptions::SerializeWithCachedSizes( } int EnumOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumOptions) int total_size = 0; if (_has_bits_[0 / 32] & 3u) { @@ -10703,18 +10848,22 @@ int EnumOptions::ByteSize() const { } void EnumOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumOptions* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumOptions) MergeFrom(*source); } } void EnumOptions::MergeFrom(const EnumOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -10732,12 +10881,14 @@ void EnumOptions::MergeFrom(const EnumOptions& from) { } void EnumOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumOptions) if (&from == this) return; Clear(); MergeFrom(from); } void EnumOptions::CopyFrom(const EnumOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -10921,6 +11072,7 @@ EnumValueOptions* EnumValueOptions::New(::google::protobuf::Arena* arena) const } void EnumValueOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValueOptions) _extensions_.Clear(); deprecated_ = false; uninterpreted_option_.Clear(); @@ -10932,7 +11084,7 @@ void EnumValueOptions::Clear() { bool EnumValueOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumValueOptions) for (;;) { @@ -11051,6 +11203,7 @@ void EnumValueOptions::SerializeWithCachedSizes( } int EnumValueOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValueOptions) int total_size = 0; // optional bool deprecated = 1 [default = false]; @@ -11080,18 +11233,22 @@ int EnumValueOptions::ByteSize() const { } void EnumValueOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValueOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumValueOptions* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValueOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValueOptions) MergeFrom(*source); } } void EnumValueOptions::MergeFrom(const EnumValueOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValueOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -11106,12 +11263,14 @@ void EnumValueOptions::MergeFrom(const EnumValueOptions& from) { } void EnumValueOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValueOptions) if (&from == this) return; Clear(); MergeFrom(from); } void EnumValueOptions::CopyFrom(const EnumValueOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValueOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -11270,6 +11429,7 @@ ServiceOptions* ServiceOptions::New(::google::protobuf::Arena* arena) const { } void ServiceOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.ServiceOptions) _extensions_.Clear(); deprecated_ = false; uninterpreted_option_.Clear(); @@ -11281,7 +11441,7 @@ void ServiceOptions::Clear() { bool ServiceOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.ServiceOptions) for (;;) { @@ -11400,6 +11560,7 @@ void ServiceOptions::SerializeWithCachedSizes( } int ServiceOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ServiceOptions) int total_size = 0; // optional bool deprecated = 33 [default = false]; @@ -11429,18 +11590,22 @@ int ServiceOptions::ByteSize() const { } void ServiceOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ServiceOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const ServiceOptions* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ServiceOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ServiceOptions) MergeFrom(*source); } } void ServiceOptions::MergeFrom(const ServiceOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ServiceOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -11455,12 +11620,14 @@ void ServiceOptions::MergeFrom(const ServiceOptions& from) { } void ServiceOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ServiceOptions) if (&from == this) return; Clear(); MergeFrom(from); } void ServiceOptions::CopyFrom(const ServiceOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ServiceOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -11619,6 +11786,7 @@ MethodOptions* MethodOptions::New(::google::protobuf::Arena* arena) const { } void MethodOptions::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.MethodOptions) _extensions_.Clear(); deprecated_ = false; uninterpreted_option_.Clear(); @@ -11630,7 +11798,7 @@ void MethodOptions::Clear() { bool MethodOptions::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.MethodOptions) for (;;) { @@ -11749,6 +11917,7 @@ void MethodOptions::SerializeWithCachedSizes( } int MethodOptions::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.MethodOptions) int total_size = 0; // optional bool deprecated = 33 [default = false]; @@ -11778,18 +11947,22 @@ int MethodOptions::ByteSize() const { } void MethodOptions::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.MethodOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const MethodOptions* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.MethodOptions) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.MethodOptions) MergeFrom(*source); } } void MethodOptions::MergeFrom(const MethodOptions& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.MethodOptions) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); uninterpreted_option_.MergeFrom(from.uninterpreted_option_); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { @@ -11804,12 +11977,14 @@ void MethodOptions::MergeFrom(const MethodOptions& from) { } void MethodOptions::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.MethodOptions) if (&from == this) return; Clear(); MergeFrom(from); } void MethodOptions::CopyFrom(const MethodOptions& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.MethodOptions) if (&from == this) return; Clear(); MergeFrom(from); @@ -11971,6 +12146,7 @@ UninterpretedOption_NamePart* UninterpretedOption_NamePart::New(::google::protob } void UninterpretedOption_NamePart::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption.NamePart) if (_has_bits_[0 / 32] & 3u) { if (has_name_part()) { name_part_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -11985,7 +12161,7 @@ void UninterpretedOption_NamePart::Clear() { bool UninterpretedOption_NamePart::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption.NamePart) for (;;) { @@ -12099,6 +12275,7 @@ void UninterpretedOption_NamePart::SerializeWithCachedSizes( } int UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const { +// @@protoc_insertion_point(required_fields_byte_size_fallback_start:google.protobuf.UninterpretedOption.NamePart) int total_size = 0; if (has_name_part()) { @@ -12116,6 +12293,7 @@ int UninterpretedOption_NamePart::RequiredFieldsByteSizeFallback() const { return total_size; } int UninterpretedOption_NamePart::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption.NamePart) int total_size = 0; if (((_has_bits_[0] & 0x00000003) ^ 0x00000003) == 0) { // All required fields are present. @@ -12142,18 +12320,22 @@ int UninterpretedOption_NamePart::ByteSize() const { } void UninterpretedOption_NamePart::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption.NamePart) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UninterpretedOption_NamePart* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UninterpretedOption.NamePart) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UninterpretedOption.NamePart) MergeFrom(*source); } } void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption.NamePart) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { if (from.has_name_part()) { @@ -12170,12 +12352,14 @@ void UninterpretedOption_NamePart::MergeFrom(const UninterpretedOption_NamePart& } void UninterpretedOption_NamePart::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UninterpretedOption.NamePart) if (&from == this) return; Clear(); MergeFrom(from); } void UninterpretedOption_NamePart::CopyFrom(const UninterpretedOption_NamePart& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption.NamePart) if (&from == this) return; Clear(); MergeFrom(from); @@ -12288,6 +12472,7 @@ UninterpretedOption* UninterpretedOption::New(::google::protobuf::Arena* arena) } void UninterpretedOption::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UninterpretedOption) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -12321,7 +12506,7 @@ void UninterpretedOption::Clear() { bool UninterpretedOption::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UninterpretedOption) for (;;) { @@ -12579,6 +12764,7 @@ void UninterpretedOption::SerializeWithCachedSizes( } int UninterpretedOption::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UninterpretedOption) int total_size = 0; if (_has_bits_[1 / 32] & 126u) { @@ -12643,18 +12829,22 @@ int UninterpretedOption::ByteSize() const { } void UninterpretedOption::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UninterpretedOption) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UninterpretedOption* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UninterpretedOption) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UninterpretedOption) MergeFrom(*source); } } void UninterpretedOption::MergeFrom(const UninterpretedOption& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UninterpretedOption) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); name_.MergeFrom(from.name_); if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { @@ -12686,12 +12876,14 @@ void UninterpretedOption::MergeFrom(const UninterpretedOption& from) { } void UninterpretedOption::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UninterpretedOption) if (&from == this) return; Clear(); MergeFrom(from); } void UninterpretedOption::CopyFrom(const UninterpretedOption& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UninterpretedOption) if (&from == this) return; Clear(); MergeFrom(from); @@ -12771,6 +12963,7 @@ void UninterpretedOption_NamePart::clear_name_part() { return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption_NamePart::release_name_part() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part) clear_has_name_part(); return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -12882,6 +13075,7 @@ void UninterpretedOption::clear_identifier_value() { return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption::release_identifier_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value) clear_has_identifier_value(); return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13007,6 +13201,7 @@ void UninterpretedOption::clear_string_value() { return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value) clear_has_string_value(); return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13060,6 +13255,7 @@ void UninterpretedOption::clear_aggregate_value() { return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* UninterpretedOption::release_aggregate_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value) clear_has_aggregate_value(); return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13148,6 +13344,7 @@ SourceCodeInfo_Location* SourceCodeInfo_Location::New(::google::protobuf::Arena* } void SourceCodeInfo_Location::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo.Location) if (_has_bits_[0 / 32] & 12u) { if (has_leading_comments()) { leading_comments_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -13167,7 +13364,7 @@ void SourceCodeInfo_Location::Clear() { bool SourceCodeInfo_Location::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo.Location) for (;;) { @@ -13417,6 +13614,7 @@ void SourceCodeInfo_Location::SerializeWithCachedSizes( } int SourceCodeInfo_Location::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo.Location) int total_size = 0; if (_has_bits_[2 / 32] & 12u) { @@ -13488,18 +13686,22 @@ int SourceCodeInfo_Location::ByteSize() const { } void SourceCodeInfo_Location::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo.Location) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const SourceCodeInfo_Location* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceCodeInfo.Location) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceCodeInfo.Location) MergeFrom(*source); } } void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo.Location) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); path_.MergeFrom(from.path_); span_.MergeFrom(from.span_); @@ -13520,12 +13722,14 @@ void SourceCodeInfo_Location::MergeFrom(const SourceCodeInfo_Location& from) { } void SourceCodeInfo_Location::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceCodeInfo.Location) if (&from == this) return; Clear(); MergeFrom(from); } void SourceCodeInfo_Location::CopyFrom(const SourceCodeInfo_Location& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo.Location) if (&from == this) return; Clear(); MergeFrom(from); @@ -13624,6 +13828,7 @@ SourceCodeInfo* SourceCodeInfo::New(::google::protobuf::Arena* arena) const { } void SourceCodeInfo::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceCodeInfo) location_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { @@ -13633,7 +13838,7 @@ void SourceCodeInfo::Clear() { bool SourceCodeInfo::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.SourceCodeInfo) for (;;) { @@ -13714,6 +13919,7 @@ void SourceCodeInfo::SerializeWithCachedSizes( } int SourceCodeInfo::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceCodeInfo) int total_size = 0; // repeated .google.protobuf.SourceCodeInfo.Location location = 1; @@ -13736,18 +13942,22 @@ int SourceCodeInfo::ByteSize() const { } void SourceCodeInfo::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const SourceCodeInfo* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceCodeInfo) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceCodeInfo) MergeFrom(*source); } } void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); location_.MergeFrom(from.location_); if (from._internal_metadata_.have_unknown_fields()) { @@ -13756,12 +13966,14 @@ void SourceCodeInfo::MergeFrom(const SourceCodeInfo& from) { } void SourceCodeInfo::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); } void SourceCodeInfo::CopyFrom(const SourceCodeInfo& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); @@ -13894,6 +14106,7 @@ void SourceCodeInfo_Location::clear_leading_comments() { return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* SourceCodeInfo_Location::release_leading_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments) clear_has_leading_comments(); return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13947,6 +14160,7 @@ void SourceCodeInfo_Location::clear_trailing_comments() { return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* SourceCodeInfo_Location::release_trailing_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments) clear_has_trailing_comments(); return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -13989,6 +14203,7 @@ void SourceCodeInfo_Location::clear_leading_detached_comments() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) } ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) return leading_detached_comments_.Add(); } void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) { @@ -14122,6 +14337,7 @@ GeneratedCodeInfo_Annotation* GeneratedCodeInfo_Annotation::New(::google::protob } void GeneratedCodeInfo_Annotation::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo.Annotation) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -14149,7 +14365,7 @@ void GeneratedCodeInfo_Annotation::Clear() { bool GeneratedCodeInfo_Annotation::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo.Annotation) for (;;) { @@ -14330,6 +14546,7 @@ void GeneratedCodeInfo_Annotation::SerializeWithCachedSizes( } int GeneratedCodeInfo_Annotation::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo.Annotation) int total_size = 0; if (_has_bits_[1 / 32] & 14u) { @@ -14384,18 +14601,22 @@ int GeneratedCodeInfo_Annotation::ByteSize() const { } void GeneratedCodeInfo_Annotation::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const GeneratedCodeInfo_Annotation* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.GeneratedCodeInfo.Annotation) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.GeneratedCodeInfo.Annotation) MergeFrom(*source); } } void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); path_.MergeFrom(from.path_); if (from._has_bits_[1 / 32] & (0xffu << (1 % 32))) { @@ -14416,12 +14637,14 @@ void GeneratedCodeInfo_Annotation::MergeFrom(const GeneratedCodeInfo_Annotation& } void GeneratedCodeInfo_Annotation::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (&from == this) return; Clear(); MergeFrom(from); } void GeneratedCodeInfo_Annotation::CopyFrom(const GeneratedCodeInfo_Annotation& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo.Annotation) if (&from == this) return; Clear(); MergeFrom(from); @@ -14519,6 +14742,7 @@ GeneratedCodeInfo* GeneratedCodeInfo::New(::google::protobuf::Arena* arena) cons } void GeneratedCodeInfo::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.GeneratedCodeInfo) annotation_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { @@ -14528,7 +14752,7 @@ void GeneratedCodeInfo::Clear() { bool GeneratedCodeInfo::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.GeneratedCodeInfo) for (;;) { @@ -14609,6 +14833,7 @@ void GeneratedCodeInfo::SerializeWithCachedSizes( } int GeneratedCodeInfo::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.GeneratedCodeInfo) int total_size = 0; // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1; @@ -14631,18 +14856,22 @@ int GeneratedCodeInfo::ByteSize() const { } void GeneratedCodeInfo::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.GeneratedCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const GeneratedCodeInfo* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.GeneratedCodeInfo) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.GeneratedCodeInfo) MergeFrom(*source); } } void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.GeneratedCodeInfo) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); annotation_.MergeFrom(from.annotation_); if (from._internal_metadata_.have_unknown_fields()) { @@ -14651,12 +14880,14 @@ void GeneratedCodeInfo::MergeFrom(const GeneratedCodeInfo& from) { } void GeneratedCodeInfo::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.GeneratedCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); } void GeneratedCodeInfo::CopyFrom(const GeneratedCodeInfo& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.GeneratedCodeInfo) if (&from == this) return; Clear(); MergeFrom(from); @@ -14759,6 +14990,7 @@ void GeneratedCodeInfo_Annotation::clear_source_file() { return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* GeneratedCodeInfo_Annotation::release_source_file() { + // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file) clear_has_source_file(); return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 9f15bf27..92a0a3a7 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -993,24 +993,42 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa // nested types ---------------------------------------------------- typedef FieldDescriptorProto_Type Type; - static const Type TYPE_DOUBLE = FieldDescriptorProto_Type_TYPE_DOUBLE; - static const Type TYPE_FLOAT = FieldDescriptorProto_Type_TYPE_FLOAT; - static const Type TYPE_INT64 = FieldDescriptorProto_Type_TYPE_INT64; - static const Type TYPE_UINT64 = FieldDescriptorProto_Type_TYPE_UINT64; - static const Type TYPE_INT32 = FieldDescriptorProto_Type_TYPE_INT32; - static const Type TYPE_FIXED64 = FieldDescriptorProto_Type_TYPE_FIXED64; - static const Type TYPE_FIXED32 = FieldDescriptorProto_Type_TYPE_FIXED32; - static const Type TYPE_BOOL = FieldDescriptorProto_Type_TYPE_BOOL; - static const Type TYPE_STRING = FieldDescriptorProto_Type_TYPE_STRING; - static const Type TYPE_GROUP = FieldDescriptorProto_Type_TYPE_GROUP; - static const Type TYPE_MESSAGE = FieldDescriptorProto_Type_TYPE_MESSAGE; - static const Type TYPE_BYTES = FieldDescriptorProto_Type_TYPE_BYTES; - static const Type TYPE_UINT32 = FieldDescriptorProto_Type_TYPE_UINT32; - static const Type TYPE_ENUM = FieldDescriptorProto_Type_TYPE_ENUM; - static const Type TYPE_SFIXED32 = FieldDescriptorProto_Type_TYPE_SFIXED32; - static const Type TYPE_SFIXED64 = FieldDescriptorProto_Type_TYPE_SFIXED64; - static const Type TYPE_SINT32 = FieldDescriptorProto_Type_TYPE_SINT32; - static const Type TYPE_SINT64 = FieldDescriptorProto_Type_TYPE_SINT64; + static const Type TYPE_DOUBLE = + FieldDescriptorProto_Type_TYPE_DOUBLE; + static const Type TYPE_FLOAT = + FieldDescriptorProto_Type_TYPE_FLOAT; + static const Type TYPE_INT64 = + FieldDescriptorProto_Type_TYPE_INT64; + static const Type TYPE_UINT64 = + FieldDescriptorProto_Type_TYPE_UINT64; + static const Type TYPE_INT32 = + FieldDescriptorProto_Type_TYPE_INT32; + static const Type TYPE_FIXED64 = + FieldDescriptorProto_Type_TYPE_FIXED64; + static const Type TYPE_FIXED32 = + FieldDescriptorProto_Type_TYPE_FIXED32; + static const Type TYPE_BOOL = + FieldDescriptorProto_Type_TYPE_BOOL; + static const Type TYPE_STRING = + FieldDescriptorProto_Type_TYPE_STRING; + static const Type TYPE_GROUP = + FieldDescriptorProto_Type_TYPE_GROUP; + static const Type TYPE_MESSAGE = + FieldDescriptorProto_Type_TYPE_MESSAGE; + static const Type TYPE_BYTES = + FieldDescriptorProto_Type_TYPE_BYTES; + static const Type TYPE_UINT32 = + FieldDescriptorProto_Type_TYPE_UINT32; + static const Type TYPE_ENUM = + FieldDescriptorProto_Type_TYPE_ENUM; + static const Type TYPE_SFIXED32 = + FieldDescriptorProto_Type_TYPE_SFIXED32; + static const Type TYPE_SFIXED64 = + FieldDescriptorProto_Type_TYPE_SFIXED64; + static const Type TYPE_SINT32 = + FieldDescriptorProto_Type_TYPE_SINT32; + static const Type TYPE_SINT64 = + FieldDescriptorProto_Type_TYPE_SINT64; static inline bool Type_IsValid(int value) { return FieldDescriptorProto_Type_IsValid(value); } @@ -1033,9 +1051,12 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa } typedef FieldDescriptorProto_Label Label; - static const Label LABEL_OPTIONAL = FieldDescriptorProto_Label_LABEL_OPTIONAL; - static const Label LABEL_REQUIRED = FieldDescriptorProto_Label_LABEL_REQUIRED; - static const Label LABEL_REPEATED = FieldDescriptorProto_Label_LABEL_REPEATED; + static const Label LABEL_OPTIONAL = + FieldDescriptorProto_Label_LABEL_OPTIONAL; + static const Label LABEL_REQUIRED = + FieldDescriptorProto_Label_LABEL_REQUIRED; + static const Label LABEL_REPEATED = + FieldDescriptorProto_Label_LABEL_REPEATED; static inline bool Label_IsValid(int value) { return FieldDescriptorProto_Label_IsValid(value); } @@ -1868,9 +1889,12 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef FileOptions_OptimizeMode OptimizeMode; - static const OptimizeMode SPEED = FileOptions_OptimizeMode_SPEED; - static const OptimizeMode CODE_SIZE = FileOptions_OptimizeMode_CODE_SIZE; - static const OptimizeMode LITE_RUNTIME = FileOptions_OptimizeMode_LITE_RUNTIME; + static const OptimizeMode SPEED = + FileOptions_OptimizeMode_SPEED; + static const OptimizeMode CODE_SIZE = + FileOptions_OptimizeMode_CODE_SIZE; + static const OptimizeMode LITE_RUNTIME = + FileOptions_OptimizeMode_LITE_RUNTIME; static inline bool OptimizeMode_IsValid(int value) { return FileOptions_OptimizeMode_IsValid(value); } @@ -2288,9 +2312,12 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef FieldOptions_CType CType; - static const CType STRING = FieldOptions_CType_STRING; - static const CType CORD = FieldOptions_CType_CORD; - static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; + static const CType STRING = + FieldOptions_CType_STRING; + static const CType CORD = + FieldOptions_CType_CORD; + static const CType STRING_PIECE = + FieldOptions_CType_STRING_PIECE; static inline bool CType_IsValid(int value) { return FieldOptions_CType_IsValid(value); } @@ -2313,9 +2340,12 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { } typedef FieldOptions_JSType JSType; - static const JSType JS_NORMAL = FieldOptions_JSType_JS_NORMAL; - static const JSType JS_STRING = FieldOptions_JSType_JS_STRING; - static const JSType JS_NUMBER = FieldOptions_JSType_JS_NUMBER; + static const JSType JS_NORMAL = + FieldOptions_JSType_JS_NORMAL; + static const JSType JS_STRING = + FieldOptions_JSType_JS_STRING; + static const JSType JS_NUMBER = + FieldOptions_JSType_JS_NUMBER; static inline bool JSType_IsValid(int value) { return FieldOptions_JSType_IsValid(value); } @@ -3686,6 +3716,7 @@ inline ::std::string* FileDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3739,6 +3770,7 @@ inline ::std::string* FileDescriptorProto::mutable_package() { return package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileDescriptorProto::release_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.package) clear_has_package(); return package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3781,6 +3813,7 @@ inline void FileDescriptorProto::set_dependency(int index, const char* value, si // @@protoc_insertion_point(field_set_pointer:google.protobuf.FileDescriptorProto.dependency) } inline ::std::string* FileDescriptorProto::add_dependency() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FileDescriptorProto.dependency) return dependency_.Add(); } inline void FileDescriptorProto::add_dependency(const ::std::string& value) { @@ -4013,6 +4046,7 @@ inline ::google::protobuf::FileOptions* FileDescriptorProto::mutable_options() { return options_; } inline ::google::protobuf::FileOptions* FileDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.options) clear_has_options(); ::google::protobuf::FileOptions* temp = options_; options_ = NULL; @@ -4056,6 +4090,7 @@ inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::mutable_source_c return source_code_info_; } inline ::google::protobuf::SourceCodeInfo* FileDescriptorProto::release_source_code_info() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.source_code_info) clear_has_source_code_info(); ::google::protobuf::SourceCodeInfo* temp = source_code_info_; source_code_info_ = NULL; @@ -4112,6 +4147,7 @@ inline ::std::string* FileDescriptorProto::mutable_syntax() { return syntax_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileDescriptorProto::release_syntax() { + // @@protoc_insertion_point(field_release:google.protobuf.FileDescriptorProto.syntax) clear_has_syntax(); return syntax_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4273,6 +4309,7 @@ inline ::std::string* DescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* DescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4493,6 +4530,7 @@ inline ::google::protobuf::MessageOptions* DescriptorProto::mutable_options() { return options_; } inline ::google::protobuf::MessageOptions* DescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.DescriptorProto.options) clear_has_options(); ::google::protobuf::MessageOptions* temp = options_; options_ = NULL; @@ -4568,6 +4606,7 @@ inline void DescriptorProto::set_reserved_name(int index, const char* value, siz // @@protoc_insertion_point(field_set_pointer:google.protobuf.DescriptorProto.reserved_name) } inline ::std::string* DescriptorProto::add_reserved_name() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.DescriptorProto.reserved_name) return reserved_name_.Add(); } inline void DescriptorProto::add_reserved_name(const ::std::string& value) { @@ -4637,6 +4676,7 @@ inline ::std::string* FieldDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4764,6 +4804,7 @@ inline ::std::string* FieldDescriptorProto::mutable_type_name() { return type_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_type_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.type_name) clear_has_type_name(); return type_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4817,6 +4858,7 @@ inline ::std::string* FieldDescriptorProto::mutable_extendee() { return extendee_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_extendee() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.extendee) clear_has_extendee(); return extendee_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4870,6 +4912,7 @@ inline ::std::string* FieldDescriptorProto::mutable_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.default_value) clear_has_default_value(); return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4947,6 +4990,7 @@ inline ::std::string* FieldDescriptorProto::mutable_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FieldDescriptorProto::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.json_name) clear_has_json_name(); return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4987,6 +5031,7 @@ inline ::google::protobuf::FieldOptions* FieldDescriptorProto::mutable_options() return options_; } inline ::google::protobuf::FieldOptions* FieldDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.FieldDescriptorProto.options) clear_has_options(); ::google::protobuf::FieldOptions* temp = options_; options_ = NULL; @@ -5047,6 +5092,7 @@ inline ::std::string* OneofDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* OneofDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5104,6 +5150,7 @@ inline ::std::string* EnumDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* EnumDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5174,6 +5221,7 @@ inline ::google::protobuf::EnumOptions* EnumDescriptorProto::mutable_options() { return options_; } inline ::google::protobuf::EnumOptions* EnumDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumOptions* temp = options_; options_ = NULL; @@ -5234,6 +5282,7 @@ inline ::std::string* EnumValueDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* EnumValueDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5298,6 +5347,7 @@ inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::mutable_o return options_; } inline ::google::protobuf::EnumValueOptions* EnumValueDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValueDescriptorProto.options) clear_has_options(); ::google::protobuf::EnumValueOptions* temp = options_; options_ = NULL; @@ -5358,6 +5408,7 @@ inline ::std::string* ServiceDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* ServiceDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5428,6 +5479,7 @@ inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::mutable_optio return options_; } inline ::google::protobuf::ServiceOptions* ServiceDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.ServiceDescriptorProto.options) clear_has_options(); ::google::protobuf::ServiceOptions* temp = options_; options_ = NULL; @@ -5488,6 +5540,7 @@ inline ::std::string* MethodDescriptorProto::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* MethodDescriptorProto::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.name) clear_has_name(); return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5541,6 +5594,7 @@ inline ::std::string* MethodDescriptorProto::mutable_input_type() { return input_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* MethodDescriptorProto::release_input_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.input_type) clear_has_input_type(); return input_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5594,6 +5648,7 @@ inline ::std::string* MethodDescriptorProto::mutable_output_type() { return output_type_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* MethodDescriptorProto::release_output_type() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.output_type) clear_has_output_type(); return output_type_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5634,6 +5689,7 @@ inline ::google::protobuf::MethodOptions* MethodDescriptorProto::mutable_options return options_; } inline ::google::protobuf::MethodOptions* MethodDescriptorProto::release_options() { + // @@protoc_insertion_point(field_release:google.protobuf.MethodDescriptorProto.options) clear_has_options(); ::google::protobuf::MethodOptions* temp = options_; options_ = NULL; @@ -5742,6 +5798,7 @@ inline ::std::string* FileOptions::mutable_java_package() { return java_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_java_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_package) clear_has_java_package(); return java_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5795,6 +5852,7 @@ inline ::std::string* FileOptions::mutable_java_outer_classname() { return java_outer_classname_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_java_outer_classname() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.java_outer_classname) clear_has_java_outer_classname(); return java_outer_classname_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -5945,6 +6003,7 @@ inline ::std::string* FileOptions::mutable_go_package() { return go_package_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_go_package() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.go_package) clear_has_go_package(); return go_package_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6118,6 +6177,7 @@ inline ::std::string* FileOptions::mutable_objc_class_prefix() { return objc_class_prefix_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_objc_class_prefix() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.objc_class_prefix) clear_has_objc_class_prefix(); return objc_class_prefix_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6171,6 +6231,7 @@ inline ::std::string* FileOptions::mutable_csharp_namespace() { return csharp_namespace_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* FileOptions::release_csharp_namespace() { + // @@protoc_insertion_point(field_release:google.protobuf.FileOptions.csharp_namespace) clear_has_csharp_namespace(); return csharp_namespace_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6824,6 +6885,7 @@ inline ::std::string* UninterpretedOption_NamePart::mutable_name_part() { return name_part_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption_NamePart::release_name_part() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.NamePart.name_part) clear_has_name_part(); return name_part_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -6935,6 +6997,7 @@ inline ::std::string* UninterpretedOption::mutable_identifier_value() { return identifier_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption::release_identifier_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.identifier_value) clear_has_identifier_value(); return identifier_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7060,6 +7123,7 @@ inline ::std::string* UninterpretedOption::mutable_string_value() { return string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.string_value) clear_has_string_value(); return string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7113,6 +7177,7 @@ inline ::std::string* UninterpretedOption::mutable_aggregate_value() { return aggregate_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* UninterpretedOption::release_aggregate_value() { + // @@protoc_insertion_point(field_release:google.protobuf.UninterpretedOption.aggregate_value) clear_has_aggregate_value(); return aggregate_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7230,6 +7295,7 @@ inline ::std::string* SourceCodeInfo_Location::mutable_leading_comments() { return leading_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* SourceCodeInfo_Location::release_leading_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.leading_comments) clear_has_leading_comments(); return leading_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7283,6 +7349,7 @@ inline ::std::string* SourceCodeInfo_Location::mutable_trailing_comments() { return trailing_comments_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* SourceCodeInfo_Location::release_trailing_comments() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceCodeInfo.Location.trailing_comments) clear_has_trailing_comments(); return trailing_comments_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -7325,6 +7392,7 @@ inline void SourceCodeInfo_Location::set_leading_detached_comments(int index, co // @@protoc_insertion_point(field_set_pointer:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) } inline ::std::string* SourceCodeInfo_Location::add_leading_detached_comments() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.SourceCodeInfo.Location.leading_detached_comments) return leading_detached_comments_.Add(); } inline void SourceCodeInfo_Location::add_leading_detached_comments(const ::std::string& value) { @@ -7458,6 +7526,7 @@ inline ::std::string* GeneratedCodeInfo_Annotation::mutable_source_file() { return source_file_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* GeneratedCodeInfo_Annotation::release_source_file() { + // @@protoc_insertion_point(field_release:google.protobuf.GeneratedCodeInfo.Annotation.source_file) clear_has_source_file(); return source_file_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index e4720a7e..f937b9ea 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -5740,18 +5740,6 @@ TEST_F(ValidationErrorTest, ValidateProto3Enum) { "}"); } -TEST_F(ValidationErrorTest, ValidateProto3LiteRuntime) { - // Lite runtime is not supported in proto3. - BuildFileWithErrors( - "name: 'foo.proto' " - "syntax: 'proto3' " - "options { " - " optimize_for: LITE_RUNTIME " - "} ", - "foo.proto: foo.proto: OTHER: Lite runtime is not supported " - "in proto3.\n"); -} - TEST_F(ValidationErrorTest, ValidateProto3Group) { BuildFileWithErrors( "name: 'foo.proto' " diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc index c71ce663..42c2f7dc 100644 --- a/src/google/protobuf/duration.pb.cc +++ b/src/google/protobuf/duration.pb.cc @@ -179,6 +179,7 @@ Duration* Duration::New(::google::protobuf::Arena* arena) const { } void Duration::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Duration) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -196,7 +197,7 @@ void Duration::Clear() { bool Duration::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Duration) for (;;) { @@ -288,6 +289,7 @@ void Duration::SerializeWithCachedSizes( } int Duration::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Duration) int total_size = 0; // optional int64 seconds = 1; @@ -311,18 +313,22 @@ int Duration::ByteSize() const { } void Duration::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Duration) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Duration* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Duration) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Duration) MergeFrom(*source); } } void Duration::MergeFrom(const Duration& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Duration) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.seconds() != 0) { set_seconds(from.seconds()); @@ -333,12 +339,14 @@ void Duration::MergeFrom(const Duration& from) { } void Duration::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Duration) if (&from == this) return; Clear(); MergeFrom(from); } void Duration::CopyFrom(const Duration& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Duration) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc index 4550921b..dcf84263 100644 --- a/src/google/protobuf/empty.pb.cc +++ b/src/google/protobuf/empty.pb.cc @@ -186,11 +186,12 @@ Empty* Empty::New(::google::protobuf::Arena* arena) const { } void Empty::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Empty) } bool Empty::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Empty) for (;;) { @@ -228,6 +229,7 @@ void Empty::SerializeWithCachedSizes( } int Empty::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Empty) int total_size = 0; GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); @@ -237,28 +239,34 @@ int Empty::ByteSize() const { } void Empty::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Empty) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Empty* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Empty) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Empty) MergeFrom(*source); } } void Empty::MergeFrom(const Empty& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Empty) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); } void Empty::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Empty) if (&from == this) return; Clear(); MergeFrom(from); } void Empty::CopyFrom(const Empty& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Empty) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc index 01a6ce56..c49ebceb 100644 --- a/src/google/protobuf/field_mask.pb.cc +++ b/src/google/protobuf/field_mask.pb.cc @@ -175,12 +175,13 @@ FieldMask* FieldMask::New(::google::protobuf::Arena* arena) const { } void FieldMask::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FieldMask) paths_.Clear(); } bool FieldMask::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FieldMask) for (;;) { @@ -262,6 +263,7 @@ void FieldMask::SerializeWithCachedSizes( } int FieldMask::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FieldMask) int total_size = 0; // repeated string paths = 1; @@ -278,29 +280,35 @@ int FieldMask::ByteSize() const { } void FieldMask::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FieldMask) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FieldMask* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FieldMask) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FieldMask) MergeFrom(*source); } } void FieldMask::MergeFrom(const FieldMask& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FieldMask) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); paths_.MergeFrom(from.paths_); } void FieldMask::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FieldMask) if (&from == this) return; Clear(); MergeFrom(from); } void FieldMask::CopyFrom(const FieldMask& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FieldMask) if (&from == this) return; Clear(); MergeFrom(from); @@ -361,6 +369,7 @@ void FieldMask::clear_paths() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths) } ::std::string* FieldMask::add_paths() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths) return paths_.Add(); } void FieldMask::add_paths(const ::std::string& value) { diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h index 7189fd79..f5e0b655 100644 --- a/src/google/protobuf/field_mask.pb.h +++ b/src/google/protobuf/field_mask.pb.h @@ -164,6 +164,7 @@ inline void FieldMask::set_paths(int index, const char* value, size_t size) { // @@protoc_insertion_point(field_set_pointer:google.protobuf.FieldMask.paths) } inline ::std::string* FieldMask::add_paths() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.FieldMask.paths) return paths_.Add(); } inline void FieldMask::add_paths(const ::std::string& value) { diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto index b1657f5f..6af6dbe8 100644 --- a/src/google/protobuf/field_mask.proto +++ b/src/google/protobuf/field_mask.proto @@ -88,7 +88,7 @@ option java_generate_equals_and_hash = true; // operation applies to all fields (as if a FieldMask of all fields // had been specified). // -// Note that a field mask does not necessarily applies to the +// Note that a field mask does not necessarily apply to the // top-level response message. In case of a REST get operation, the // field mask applies directly to the response, but in case of a REST // list operation, the mask instead applies to each individual message diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index eee024ee..2313181c 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -412,6 +412,15 @@ void GeneratedMessageReflection::SwapField( #undef SWAP_ARRAYS case FieldDescriptor::CPPTYPE_STRING: + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw(message1, field)-> + Swap >( + MutableRaw(message2, field)); + break; + } + break; case FieldDescriptor::CPPTYPE_MESSAGE: if (IsMapFieldInApi(field)) { MutableRaw(message1, field)-> @@ -447,16 +456,50 @@ void GeneratedMessageReflection::SwapField( SWAP_VALUES(ENUM , int ); #undef SWAP_VALUES case FieldDescriptor::CPPTYPE_MESSAGE: - std::swap(*MutableRaw(message1, field), - *MutableRaw(message2, field)); + if (GetArena(message1) == GetArena(message2)) { + std::swap(*MutableRaw(message1, field), + *MutableRaw(message2, field)); + } else { + Message** sub_msg1 = MutableRaw(message1, field); + Message** sub_msg2 = MutableRaw(message2, field); + if (*sub_msg1 == NULL && *sub_msg2 == NULL) break; + if (*sub_msg1 && *sub_msg2) { + (*sub_msg1)->GetReflection()->Swap(*sub_msg1, *sub_msg2); + break; + } + if (*sub_msg1 == NULL) { + *sub_msg1 = (*sub_msg2)->New(message1->GetArena()); + (*sub_msg1)->CopyFrom(**sub_msg2); + ClearField(message2, field); + } else { + *sub_msg2 = (*sub_msg1)->New(message2->GetArena()); + (*sub_msg2)->CopyFrom(**sub_msg1); + ClearField(message1, field); + } + } break; case FieldDescriptor::CPPTYPE_STRING: switch (field->options().ctype()) { default: // TODO(kenton): Support other string reps. case FieldOptions::STRING: - MutableRaw(message1, field)->Swap( - MutableRaw(message2, field)); + { + Arena* arena1 = GetArena(message1); + Arena* arena2 = GetArena(message2); + ArenaStringPtr* string1 = + MutableRaw(message1, field); + ArenaStringPtr* string2 = + MutableRaw(message2, field); + if (arena1 == arena2) { + string1->Swap(string2); + } else { + const string* default_ptr = + &DefaultRaw(field).Get(NULL); + const string temp = string1->Get(default_ptr); + string1->Set(default_ptr, string2->Get(default_ptr), arena1); + string2->Set(default_ptr, temp, arena2); + } + } break; } break; @@ -1752,7 +1795,8 @@ bool GeneratedMessageReflection::InsertOrLookupMapValue( "InsertOrLookupMapValue", "Field is not a map field."); val->SetType(field->message_type()->FindFieldByName("value")->cpp_type()); - return MutableRaw(message, field)->InsertMapValue(key, val); + return MutableRaw(message, field)->InsertOrLookupMapValue( + key, val); } bool GeneratedMessageReflection::DeleteMapValue( diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 9ef78710..15fc802c 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -582,7 +582,16 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { // which the offsets of the direct fields of a class are non-constant. // Fields inherited from superclasses *can* have non-constant offsets, // but that's not what this macro will be used for. -// +#if defined(__clang__) +// For Clang we use __builtin_offsetof() and suppress the warning, +// to avoid Control Flow Integrity and UBSan vptr sanitizers from +// crashing while trying to validate the invalid reinterpet_casts. +#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ + __builtin_offsetof(TYPE, FIELD) \ + _Pragma("clang diagnostic pop") +#else // Note that we calculate relative to the pointer value 16 here since if we // just use zero, GCC complains about dereferencing a NULL pointer. We // choose 16 rather than some other number just in case the compiler would @@ -592,6 +601,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { reinterpret_cast( \ &reinterpret_cast(16)->FIELD) - \ reinterpret_cast(16)) +#endif #define PROTO2_GENERATED_DEFAULT_ONEOF_FIELD_OFFSET(ONEOF, FIELD) \ static_cast( \ diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 78c8d7ff..4475556a 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -42,8 +42,8 @@ #include #include - #include + namespace google { namespace protobuf { @@ -63,6 +63,8 @@ namespace internal { #undef DEPRECATED_PROTOBUF_FIELD #define PROTOBUF_DEPRECATED +#define PROTOBUF_DEPRECATED_ATTR + // Constants for special floating point values. LIBPROTOBUF_EXPORT double Infinity(); diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index f10d4670..a8108e45 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index cc7430ec..9d81ccfb 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -175,7 +175,7 @@ class LIBPROTOBUF_EXPORT LazyStringOutputStream : public StringOutputStream { int64 ByteCount() const; private: - const scoped_ptr > callback_; + const google::protobuf::scoped_ptr > callback_; bool string_is_set_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyStringOutputStream); diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index 8c7358c1..a9db8872 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -63,8 +63,9 @@ #endif #include -#include +#include #include +#include #if HAVE_ZLIB #include @@ -72,7 +73,6 @@ #include #include -#include #include #include #include diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index 023ed971..bb0b14f9 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -614,11 +614,12 @@ class Map { !defined(GOOGLE_PROTOBUF_OS_EMSCRIPTEN) template void construct(NodeType* p, Args&&... args) { - // Clang 3.6 doesn't compile static casting to void* directly. (Issue #1266) - // According C++ standard 5.2.9/1: "The static_cast operator shall not cast - // away constness". So first the maybe const pointer is casted to const void* and - // after the const void* is const casted. - new (const_cast(static_cast(p))) NodeType(std::forward(args)...); + // Clang 3.6 doesn't compile static casting to void* directly. (Issue + // #1266) According C++ standard 5.2.9/1: "The static_cast operator shall + // not cast away constness". So first the maybe const pointer is casted to + // const void* and after the const void* is const casted. + new (const_cast(static_cast(p))) + NodeType(std::forward(args)...); } template @@ -804,6 +805,8 @@ class Map { // Advance through buckets, looking for the first that isn't empty. // If nothing non-empty is found then leave node_ == NULL. void SearchFrom(size_type start_bucket) { + GOOGLE_DCHECK(m_->index_of_first_non_null_ == m_->num_buckets_ || + m_->table_[m_->index_of_first_non_null_] != NULL); node_ = NULL; for (bucket_index_ = start_bucket; bucket_index_ < m_->num_buckets_; bucket_index_++) { @@ -989,7 +992,7 @@ class Map { void erase(iterator it) { GOOGLE_DCHECK_EQ(it.m_, this); const bool is_list = it.revalidate_if_necessary(); - const size_type b = it.bucket_index_; + size_type b = it.bucket_index_; Node* const item = it.node_; if (is_list) { GOOGLE_DCHECK(TableEntryIsNonEmptyList(b)); @@ -1001,15 +1004,18 @@ class Map { Tree* tree = static_cast(table_[b]); tree->erase(it.tree_it_); if (tree->empty()) { + // Force b to be the minimum of b and b ^ 1. This is important + // only because we want index_of_first_non_null_ to be correct. + b &= ~static_cast(1); DestroyTree(tree); - table_[b] = table_[b ^ 1] = NULL; + table_[b] = table_[b + 1] = NULL; } } DestroyNode(item); --num_elements_; if (GOOGLE_PREDICT_FALSE(b == index_of_first_non_null_)) { while (index_of_first_non_null_ < num_buckets_ && - table_[index_of_first_non_null_] == 0) { + table_[index_of_first_non_null_] == NULL) { ++index_of_first_non_null_; } } @@ -1045,6 +1051,8 @@ class Map { // Requires count(*KeyPtrFromNodePtr(node)) == 0 and that b is the correct // bucket. num_elements_ is not modified. iterator InsertUnique(size_type b, Node* node) { + GOOGLE_DCHECK(index_of_first_non_null_ == num_buckets_ || + table_[index_of_first_non_null_] != NULL); // In practice, the code that led to this point may have already // determined whether we are inserting into an empty list, a short list, // or whatever. But it's probably cheap enough to recompute that here; @@ -1057,11 +1065,16 @@ class Map { if (GOOGLE_PREDICT_FALSE(TableEntryIsTooLong(b))) { TreeConvert(b); result = InsertUniqueInTree(b, node); + GOOGLE_DCHECK_EQ(result.bucket_index_, b & ~static_cast(1)); } else { - result = InsertUniqueInList(b, node); + // Insert into a pre-existing list. This case cannot modify + // index_of_first_non_null_, so we skip the code to update it. + return InsertUniqueInList(b, node); } } else { - result = InsertUniqueInTree(b, node); + // Insert into a pre-existing tree. This case cannot modify + // index_of_first_non_null_, so we skip the code to update it. + return InsertUniqueInTree(b, node); } index_of_first_non_null_ = std::min(index_of_first_non_null_, result.bucket_index_); @@ -1137,7 +1150,7 @@ class Map { num_buckets_ = new_num_buckets; table_ = CreateEmptyTable(num_buckets_); const size_type start = index_of_first_non_null_; - index_of_first_non_null_ = 0; + index_of_first_non_null_ = num_buckets_; for (size_type i = start; i < old_table_size; i++) { if (TableEntryIsNonEmptyList(old_table, i)) { TransferList(old_table, i); @@ -1189,10 +1202,10 @@ class Map { return TableEntryIsList(table_, b); } static bool TableEntryIsEmpty(void* const* table, size_type b) { - return table[b] == 0; + return table[b] == NULL; } static bool TableEntryIsNonEmptyList(void* const* table, size_type b) { - return table[b] != 0 && table[b] != table[b ^ 1]; + return table[b] != NULL && table[b] != table[b ^ 1]; } static bool TableEntryIsTree(void* const* table, size_type b) { return !TableEntryIsEmpty(table, b) && @@ -1250,7 +1263,7 @@ class Map { size_type BucketNumber(const Key& k) const { // We inherit from hasher, so one-arg operator() provides a hash function. - size_type h = (*this)(k); + size_type h = (*const_cast(this))(k); // To help prevent people from making assumptions about the hash function, // we use the seed differently depending on NDEBUG. The default hash // function, the seeding, etc., are all likely to change in the future. diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc index eddc95c4..49f91818 100644 --- a/src/google/protobuf/map_field.cc +++ b/src/google/protobuf/map_field.cc @@ -178,18 +178,19 @@ bool DynamicMapField::ContainsMapKey( return iter != map.end(); } -bool DynamicMapField::InsertMapValue( +bool DynamicMapField::InsertOrLookupMapValue( const MapKey& map_key, MapValueRef* val) { - bool result = false; - - MapValueRef& map_val = (*MutableMap())[map_key]; - // If map_val.data_ is not set, it is newly inserted by map_[map_key]. - if (map_val.data_ == NULL) { - result = true; + // Always use mutable map because users may change the map value by + // MapValueRef. + Map* map = MutableMap(); + Map::iterator iter = map->find(map_key); + if (iter == map->end()) { + // Insert + MapValueRef& map_val = (*map)[map_key]; const FieldDescriptor* val_des = default_entry_->GetDescriptor()->FindFieldByName("value"); map_val.SetType(val_des->cpp_type()); - // Allocate momery for the inserted MapValueRef, and initialize to + // Allocate memory for the inserted MapValueRef, and initialize to // default value. switch (val_des->cpp_type()) { #define HANDLE_TYPE(CPPTYPE, TYPE) \ @@ -216,9 +217,13 @@ bool DynamicMapField::InsertMapValue( break; } } + val->CopyFrom(map_val); + return true; } - val->CopyFrom(map_val); - return result; + // map_key is already in the map. Make sure (*map)[map_key] is not called. + // [] may reorder the map and iterators. + val->CopyFrom(iter->second); + return false; } bool DynamicMapField::DeleteMapValue(const MapKey& map_key) { diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 9130166b..4b46f3aa 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -87,7 +87,8 @@ class LIBPROTOBUF_EXPORT MapFieldBase { // Pure virtual map APIs for Map Reflection. virtual bool ContainsMapKey(const MapKey& map_key) const = 0; - virtual bool InsertMapValue(const MapKey& map_key, MapValueRef* val) = 0; + virtual bool InsertOrLookupMapValue( + const MapKey& map_key, MapValueRef* val) = 0; virtual bool DeleteMapValue(const MapKey& map_key) = 0; virtual bool EqualIterator(const MapIterator& a, const MapIterator& b) const = 0; @@ -251,7 +252,7 @@ class MapField : public TypeDefinedMapFieldBase, // Implement MapFieldBase bool ContainsMapKey(const MapKey& map_key) const; - bool InsertMapValue(const MapKey& map_key, MapValueRef* val); + bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val); bool DeleteMapValue(const MapKey& map_key); // Accessors @@ -302,7 +303,7 @@ class LIBPROTOBUF_EXPORT DynamicMapField: public TypeDefinedMapFieldBase& GetMap() const; diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index f116697c..01c9b89a 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -262,16 +262,22 @@ template bool MapField::InsertMapValue(const MapKey& map_key, - MapValueRef* val) { + default_enum_value>::InsertOrLookupMapValue( + const MapKey& map_key, + MapValueRef* val) { + // Always use mutable map because users may change the map value by + // MapValueRef. Map* map = MutableMap(); - bool result = false; const Key& key = UnwrapMapKey(map_key); - if (map->end() == map->find(key)) { - result = true; + typename Map::iterator iter = map->find(key); + if (map->end() == iter) { + val->SetValue(&((*map)[key])); + return true; } - val->SetValue(&((*map)[key])); - return result; + // Key is already in the map. Make sure (*map)[key] is not called. + // [] may reorder the map and iterators. + val->SetValue(&(iter->second)); + return false; } template map(false); // This test uses new-style maps only. const int kTestSize = 250000; - for (int i = 0; i < kTestSize; i++) { - map[i] = i; + // Create a random-looking map of size n. Use non-negative integer keys. + uint32 frog = 123983; + int last_key = 0; + int counter = 0; + while (map.size() < kTestSize) { + frog *= static_cast(k0); + frog ^= frog >> 17; + frog += counter++; + last_key = + static_cast(frog) >= 0 ? static_cast(frog) : last_key ^ 1; + GOOGLE_DCHECK_GE(last_key, 0); + map[last_key] = last_key ^ 1; } vector times; // We're going to do map.erase(map.begin()) over and over again. But, @@ -384,11 +399,6 @@ TEST_P(MapImplTest, HashFlood) { EXPECT_LE(x1, x0 * 20); } -// Arbitrary odd integers for creating test data. -static int k0 = 812398771; -static int k1 = 1312938717; -static int k2 = 1321555333; - template static void TestValidityForAllKeysExcept(int key_to_avoid, const T& check_map, diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index fe124c45..9d7b64f7 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -361,6 +361,11 @@ void GenericTypeHandler::Merge(const MessageLite& from, MessageLite* to) { to->CheckTypeAndMergeFrom(from); } +template<> +void GenericTypeHandler::Merge(const string& from, + string* to) { + *to = from; +} } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index deeb7d50..1961bc48 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -626,6 +626,13 @@ inline void* GenericTypeHandler::GetMaybeArenaPointer( template <> void GenericTypeHandler::Merge(const MessageLite& from, MessageLite* to); +template<> +inline void GenericTypeHandler::Clear(string* value) { + value->clear(); +} +template<> +void GenericTypeHandler::Merge(const string& from, + string* to); // Declarations of the specialization as we cannot define them here, as the // header that defines ProtocolMessage depends on types defined in this header. diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc index f2eb7ae7..c67cd102 100644 --- a/src/google/protobuf/source_context.pb.cc +++ b/src/google/protobuf/source_context.pb.cc @@ -177,12 +177,13 @@ SourceContext* SourceContext::New(::google::protobuf::Arena* arena) const { } void SourceContext::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.SourceContext) file_name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } bool SourceContext::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.SourceContext) for (;;) { @@ -262,6 +263,7 @@ void SourceContext::SerializeWithCachedSizes( } int SourceContext::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.SourceContext) int total_size = 0; // optional string file_name = 1; @@ -278,18 +280,22 @@ int SourceContext::ByteSize() const { } void SourceContext::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.SourceContext) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const SourceContext* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.SourceContext) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.SourceContext) MergeFrom(*source); } } void SourceContext::MergeFrom(const SourceContext& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.SourceContext) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.file_name().size() > 0) { @@ -298,12 +304,14 @@ void SourceContext::MergeFrom(const SourceContext& from) { } void SourceContext::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.SourceContext) if (&from == this) return; Clear(); MergeFrom(from); } void SourceContext::CopyFrom(const SourceContext& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.SourceContext) if (&from == this) return; Clear(); MergeFrom(from); @@ -365,6 +373,7 @@ void SourceContext::clear_file_name() { return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* SourceContext::release_file_name() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name) return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h index 02e11460..ccfd365b 100644 --- a/src/google/protobuf/source_context.pb.h +++ b/src/google/protobuf/source_context.pb.h @@ -160,6 +160,7 @@ inline ::std::string* SourceContext::mutable_file_name() { return file_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* SourceContext::release_file_name() { + // @@protoc_insertion_point(field_release:google.protobuf.SourceContext.file_name) return file_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc index 9e5b086b..11ccabbf 100644 --- a/src/google/protobuf/struct.pb.cc +++ b/src/google/protobuf/struct.pb.cc @@ -282,12 +282,13 @@ Struct* Struct::New(::google::protobuf::Arena* arena) const { } void Struct::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Struct) fields_.Clear(); } bool Struct::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Struct) for (;;) { @@ -385,6 +386,7 @@ void Struct::SerializeWithCachedSizes( } int Struct::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Struct) int total_size = 0; // map fields = 1; @@ -407,29 +409,35 @@ int Struct::ByteSize() const { } void Struct::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Struct) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Struct* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Struct) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Struct) MergeFrom(*source); } } void Struct::MergeFrom(const Struct& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Struct) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); fields_.MergeFrom(from.fields_); } void Struct::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Struct) if (&from == this) return; Clear(); MergeFrom(from); } void Struct::CopyFrom(const Struct& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Struct) if (&from == this) return; Clear(); MergeFrom(from); @@ -562,6 +570,7 @@ Value* Value::New(::google::protobuf::Arena* arena) const { } void Value::clear_kind() { +// @@protoc_insertion_point(one_of_clear_start:google.protobuf.Value) switch(kind_case()) { case kNullValue: { // No need to clear @@ -596,12 +605,13 @@ void Value::clear_kind() { void Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Value) clear_kind(); } bool Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Value) for (;;) { @@ -813,6 +823,7 @@ void Value::SerializeWithCachedSizes( } int Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Value) int total_size = 0; switch (kind_case()) { @@ -864,18 +875,22 @@ int Value::ByteSize() const { } void Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Value* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Value) MergeFrom(*source); } } void Value::MergeFrom(const Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); switch (from.kind_case()) { case kNullValue: { @@ -909,12 +924,14 @@ void Value::MergeFrom(const Value& from) { } void Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Value) if (&from == this) return; Clear(); MergeFrom(from); } void Value::CopyFrom(const Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1065,6 +1082,7 @@ void Value::clear_string_value() { return kind_.string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Value::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value) if (has_string_value()) { clear_has_kind(); return kind_.string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -1143,6 +1161,7 @@ void Value::clear_struct_value() { return kind_.struct_value_; } ::google::protobuf::Struct* Value::release_struct_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value) if (has_struct_value()) { clear_has_kind(); ::google::protobuf::Struct* temp = kind_.struct_value_; @@ -1190,6 +1209,7 @@ void Value::clear_list_value() { return kind_.list_value_; } ::google::protobuf::ListValue* Value::release_list_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value) if (has_list_value()) { clear_has_kind(); ::google::protobuf::ListValue* temp = kind_.list_value_; @@ -1284,12 +1304,13 @@ ListValue* ListValue::New(::google::protobuf::Arena* arena) const { } void ListValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.ListValue) values_.Clear(); } bool ListValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.ListValue) for (;;) { @@ -1361,6 +1382,7 @@ void ListValue::SerializeWithCachedSizes( } int ListValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.ListValue) int total_size = 0; // repeated .google.protobuf.Value values = 1; @@ -1378,29 +1400,35 @@ int ListValue::ByteSize() const { } void ListValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.ListValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const ListValue* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.ListValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.ListValue) MergeFrom(*source); } } void ListValue::MergeFrom(const ListValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.ListValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); values_.MergeFrom(from.values_); } void ListValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.ListValue) if (&from == this) return; Clear(); MergeFrom(from); } void ListValue::CopyFrom(const ListValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.ListValue) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h index 0527c812..6a4764a7 100644 --- a/src/google/protobuf/struct.pb.h +++ b/src/google/protobuf/struct.pb.h @@ -550,6 +550,7 @@ inline ::std::string* Value::mutable_string_value() { return kind_.string_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Value::release_string_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.string_value) if (has_string_value()) { clear_has_kind(); return kind_.string_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); @@ -628,6 +629,7 @@ inline ::google::protobuf::Struct* Value::mutable_struct_value() { return kind_.struct_value_; } inline ::google::protobuf::Struct* Value::release_struct_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.struct_value) if (has_struct_value()) { clear_has_kind(); ::google::protobuf::Struct* temp = kind_.struct_value_; @@ -675,6 +677,7 @@ inline ::google::protobuf::ListValue* Value::mutable_list_value() { return kind_.list_value_; } inline ::google::protobuf::ListValue* Value::release_list_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Value.list_value) if (has_list_value()) { clear_has_kind(); ::google::protobuf::ListValue* temp = kind_.list_value_; diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 1ed74391..c0dfd53f 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -1785,14 +1785,12 @@ void TextFormat::Printer::PrintFieldValue( ? reflection->GetRepeatedStringReference( message, field, index, &scratch) : reflection->GetStringReference(message, field, &scratch); - int64 size = value.size(); - if (truncate_string_field_longer_than_ > 0) { - size = std::min(truncate_string_field_longer_than_, - static_cast(value.size())); - } - string truncated_value(value.substr(0, size) + "......"); const string* value_to_print = &value; - if (size < value.size()) { + string truncated_value; + if (truncate_string_field_longer_than_ > 0 && + truncate_string_field_longer_than_ < value.size()) { + truncated_value = value.substr(0, truncate_string_field_longer_than_) + + "......"; value_to_print = &truncated_value; } if (field->type() == FieldDescriptor::TYPE_STRING) { diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index f97658fd..58aa3f8d 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -53,10 +54,10 @@ #include #include #include -#include #include #include #include +#include namespace google { diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc index 1393cc95..9b8eeba2 100644 --- a/src/google/protobuf/timestamp.pb.cc +++ b/src/google/protobuf/timestamp.pb.cc @@ -193,6 +193,7 @@ Timestamp* Timestamp::New(::google::protobuf::Arena* arena) const { } void Timestamp::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Timestamp) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -210,7 +211,7 @@ void Timestamp::Clear() { bool Timestamp::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Timestamp) for (;;) { @@ -302,6 +303,7 @@ void Timestamp::SerializeWithCachedSizes( } int Timestamp::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Timestamp) int total_size = 0; // optional int64 seconds = 1; @@ -325,18 +327,22 @@ int Timestamp::ByteSize() const { } void Timestamp::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Timestamp) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Timestamp* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Timestamp) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Timestamp) MergeFrom(*source); } } void Timestamp::MergeFrom(const Timestamp& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Timestamp) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.seconds() != 0) { set_seconds(from.seconds()); @@ -347,12 +353,14 @@ void Timestamp::MergeFrom(const Timestamp& from) { } void Timestamp::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Timestamp) if (&from == this) return; Clear(); MergeFrom(from); } void Timestamp::CopyFrom(const Timestamp& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Timestamp) if (&from == this) return; Clear(); MergeFrom(from); diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc index 7b47b3bd..d4737528 100644 --- a/src/google/protobuf/type.pb.cc +++ b/src/google/protobuf/type.pb.cc @@ -359,6 +359,7 @@ Type* Type::New(::google::protobuf::Arena* arena) const { } void Type::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Type) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; @@ -370,7 +371,7 @@ void Type::Clear() { bool Type::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Type) for (;;) { @@ -603,6 +604,7 @@ void Type::SerializeWithCachedSizes( } int Type::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Type) int total_size = 0; // optional string name = 1; @@ -655,18 +657,22 @@ int Type::ByteSize() const { } void Type::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Type) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Type* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Type) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Type) MergeFrom(*source); } } void Type::MergeFrom(const Type& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Type) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); fields_.MergeFrom(from.fields_); oneofs_.MergeFrom(from.oneofs_); @@ -684,12 +690,14 @@ void Type::MergeFrom(const Type& from) { } void Type::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Type) if (&from == this) return; Clear(); MergeFrom(from); } void Type::CopyFrom(const Type& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Type) if (&from == this) return; Clear(); MergeFrom(from); @@ -756,6 +764,7 @@ void Type::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Type::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -828,6 +837,7 @@ void Type::clear_oneofs() { // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs) } ::std::string* Type::add_oneofs() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs) return oneofs_.Add(); } void Type::add_oneofs(const ::std::string& value) { @@ -904,6 +914,7 @@ const ::google::protobuf::SourceContext& Type::source_context() const { return source_context_; } ::google::protobuf::SourceContext* Type::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -1104,6 +1115,7 @@ Field* Field::New(::google::protobuf::Arena* arena) const { } void Field::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Field) #define ZR_HELPER_(f) reinterpret_cast(\ &reinterpret_cast(16)->f) @@ -1128,7 +1140,7 @@ void Field::Clear() { bool Field::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Field) for (;;) { @@ -1483,6 +1495,7 @@ void Field::SerializeWithCachedSizes( } int Field::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Field) int total_size = 0; // optional .google.protobuf.Field.Kind kind = 1; @@ -1559,18 +1572,22 @@ int Field::ByteSize() const { } void Field::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Field) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Field* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Field) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Field) MergeFrom(*source); } } void Field::MergeFrom(const Field& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Field) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); options_.MergeFrom(from.options_); if (from.kind() != 0) { @@ -1607,12 +1624,14 @@ void Field::MergeFrom(const Field& from) { } void Field::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Field) if (&from == this) return; Clear(); MergeFrom(from); } void Field::CopyFrom(const Field& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Field) if (&from == this) return; Clear(); MergeFrom(from); @@ -1725,6 +1744,7 @@ void Field::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1768,6 +1788,7 @@ void Field::clear_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1869,6 +1890,7 @@ void Field::clear_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name) return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1912,6 +1934,7 @@ void Field::clear_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Field::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value) return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2003,6 +2026,7 @@ Enum* Enum::New(::google::protobuf::Arena* arena) const { } void Enum::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Enum) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && source_context_ != NULL) delete source_context_; source_context_ = NULL; @@ -2013,7 +2037,7 @@ void Enum::Clear() { bool Enum::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Enum) for (;;) { @@ -2206,6 +2230,7 @@ void Enum::SerializeWithCachedSizes( } int Enum::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Enum) int total_size = 0; // optional string name = 1; @@ -2251,18 +2276,22 @@ int Enum::ByteSize() const { } void Enum::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Enum) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Enum* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Enum) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Enum) MergeFrom(*source); } } void Enum::MergeFrom(const Enum& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Enum) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); enumvalue_.MergeFrom(from.enumvalue_); options_.MergeFrom(from.options_); @@ -2279,12 +2308,14 @@ void Enum::MergeFrom(const Enum& from) { } void Enum::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Enum) if (&from == this) return; Clear(); MergeFrom(from); } void Enum::CopyFrom(const Enum& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Enum) if (&from == this) return; Clear(); MergeFrom(from); @@ -2350,6 +2381,7 @@ void Enum::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Enum::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2444,6 +2476,7 @@ const ::google::protobuf::SourceContext& Enum::source_context() const { return source_context_; } ::google::protobuf::SourceContext* Enum::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -2547,6 +2580,7 @@ EnumValue* EnumValue::New(::google::protobuf::Arena* arena) const { } void EnumValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.EnumValue) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); number_ = 0; options_.Clear(); @@ -2554,7 +2588,7 @@ void EnumValue::Clear() { bool EnumValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.EnumValue) for (;;) { @@ -2689,6 +2723,7 @@ void EnumValue::SerializeWithCachedSizes( } int EnumValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.EnumValue) int total_size = 0; // optional string name = 1; @@ -2720,18 +2755,22 @@ int EnumValue::ByteSize() const { } void EnumValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.EnumValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const EnumValue* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.EnumValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.EnumValue) MergeFrom(*source); } } void EnumValue::MergeFrom(const EnumValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.EnumValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); options_.MergeFrom(from.options_); if (from.name().size() > 0) { @@ -2744,12 +2783,14 @@ void EnumValue::MergeFrom(const EnumValue& from) { } void EnumValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.EnumValue) if (&from == this) return; Clear(); MergeFrom(from); } void EnumValue::CopyFrom(const EnumValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.EnumValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2813,6 +2854,7 @@ void EnumValue::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* EnumValue::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -2944,6 +2986,7 @@ Option* Option::New(::google::protobuf::Arena* arena) const { } void Option::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Option) name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); if (GetArenaNoVirtual() == NULL && value_ != NULL) delete value_; value_ = NULL; @@ -2951,7 +2994,7 @@ void Option::Clear() { bool Option::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Option) for (;;) { @@ -3057,6 +3100,7 @@ void Option::SerializeWithCachedSizes( } int Option::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Option) int total_size = 0; // optional string name = 1; @@ -3080,18 +3124,22 @@ int Option::ByteSize() const { } void Option::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Option) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Option* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Option) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Option) MergeFrom(*source); } } void Option::MergeFrom(const Option& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Option) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.name().size() > 0) { @@ -3103,12 +3151,14 @@ void Option::MergeFrom(const Option& from) { } void Option::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Option) if (&from == this) return; Clear(); MergeFrom(from); } void Option::CopyFrom(const Option& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Option) if (&from == this) return; Clear(); MergeFrom(from); @@ -3171,6 +3221,7 @@ void Option::clear_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } ::std::string* Option::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -3205,6 +3256,7 @@ const ::google::protobuf::Any& Option::value() const { return value_; } ::google::protobuf::Any* Option::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.value) ::google::protobuf::Any* temp = value_; value_ = NULL; diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h index 76fe8a65..4255fa8c 100644 --- a/src/google/protobuf/type.pb.h +++ b/src/google/protobuf/type.pb.h @@ -328,25 +328,44 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef Field_Kind Kind; - static const Kind TYPE_UNKNOWN = Field_Kind_TYPE_UNKNOWN; - static const Kind TYPE_DOUBLE = Field_Kind_TYPE_DOUBLE; - static const Kind TYPE_FLOAT = Field_Kind_TYPE_FLOAT; - static const Kind TYPE_INT64 = Field_Kind_TYPE_INT64; - static const Kind TYPE_UINT64 = Field_Kind_TYPE_UINT64; - static const Kind TYPE_INT32 = Field_Kind_TYPE_INT32; - static const Kind TYPE_FIXED64 = Field_Kind_TYPE_FIXED64; - static const Kind TYPE_FIXED32 = Field_Kind_TYPE_FIXED32; - static const Kind TYPE_BOOL = Field_Kind_TYPE_BOOL; - static const Kind TYPE_STRING = Field_Kind_TYPE_STRING; - static const Kind TYPE_GROUP = Field_Kind_TYPE_GROUP; - static const Kind TYPE_MESSAGE = Field_Kind_TYPE_MESSAGE; - static const Kind TYPE_BYTES = Field_Kind_TYPE_BYTES; - static const Kind TYPE_UINT32 = Field_Kind_TYPE_UINT32; - static const Kind TYPE_ENUM = Field_Kind_TYPE_ENUM; - static const Kind TYPE_SFIXED32 = Field_Kind_TYPE_SFIXED32; - static const Kind TYPE_SFIXED64 = Field_Kind_TYPE_SFIXED64; - static const Kind TYPE_SINT32 = Field_Kind_TYPE_SINT32; - static const Kind TYPE_SINT64 = Field_Kind_TYPE_SINT64; + static const Kind TYPE_UNKNOWN = + Field_Kind_TYPE_UNKNOWN; + static const Kind TYPE_DOUBLE = + Field_Kind_TYPE_DOUBLE; + static const Kind TYPE_FLOAT = + Field_Kind_TYPE_FLOAT; + static const Kind TYPE_INT64 = + Field_Kind_TYPE_INT64; + static const Kind TYPE_UINT64 = + Field_Kind_TYPE_UINT64; + static const Kind TYPE_INT32 = + Field_Kind_TYPE_INT32; + static const Kind TYPE_FIXED64 = + Field_Kind_TYPE_FIXED64; + static const Kind TYPE_FIXED32 = + Field_Kind_TYPE_FIXED32; + static const Kind TYPE_BOOL = + Field_Kind_TYPE_BOOL; + static const Kind TYPE_STRING = + Field_Kind_TYPE_STRING; + static const Kind TYPE_GROUP = + Field_Kind_TYPE_GROUP; + static const Kind TYPE_MESSAGE = + Field_Kind_TYPE_MESSAGE; + static const Kind TYPE_BYTES = + Field_Kind_TYPE_BYTES; + static const Kind TYPE_UINT32 = + Field_Kind_TYPE_UINT32; + static const Kind TYPE_ENUM = + Field_Kind_TYPE_ENUM; + static const Kind TYPE_SFIXED32 = + Field_Kind_TYPE_SFIXED32; + static const Kind TYPE_SFIXED64 = + Field_Kind_TYPE_SFIXED64; + static const Kind TYPE_SINT32 = + Field_Kind_TYPE_SINT32; + static const Kind TYPE_SINT64 = + Field_Kind_TYPE_SINT64; static inline bool Kind_IsValid(int value) { return Field_Kind_IsValid(value); } @@ -369,10 +388,14 @@ class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message { } typedef Field_Cardinality Cardinality; - static const Cardinality CARDINALITY_UNKNOWN = Field_Cardinality_CARDINALITY_UNKNOWN; - static const Cardinality CARDINALITY_OPTIONAL = Field_Cardinality_CARDINALITY_OPTIONAL; - static const Cardinality CARDINALITY_REQUIRED = Field_Cardinality_CARDINALITY_REQUIRED; - static const Cardinality CARDINALITY_REPEATED = Field_Cardinality_CARDINALITY_REPEATED; + static const Cardinality CARDINALITY_UNKNOWN = + Field_Cardinality_CARDINALITY_UNKNOWN; + static const Cardinality CARDINALITY_OPTIONAL = + Field_Cardinality_CARDINALITY_OPTIONAL; + static const Cardinality CARDINALITY_REQUIRED = + Field_Cardinality_CARDINALITY_REQUIRED; + static const Cardinality CARDINALITY_REPEATED = + Field_Cardinality_CARDINALITY_REPEATED; static inline bool Cardinality_IsValid(int value) { return Field_Cardinality_IsValid(value); } @@ -865,6 +888,7 @@ inline ::std::string* Type::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Type::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -937,6 +961,7 @@ inline void Type::set_oneofs(int index, const char* value, size_t size) { // @@protoc_insertion_point(field_set_pointer:google.protobuf.Type.oneofs) } inline ::std::string* Type::add_oneofs() { + // @@protoc_insertion_point(field_add_mutable:google.protobuf.Type.oneofs) return oneofs_.Add(); } inline void Type::add_oneofs(const ::std::string& value) { @@ -1013,6 +1038,7 @@ inline ::google::protobuf::SourceContext* Type::mutable_source_context() { return source_context_; } inline ::google::protobuf::SourceContext* Type::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Type.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -1119,6 +1145,7 @@ inline ::std::string* Field::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1162,6 +1189,7 @@ inline ::std::string* Field::mutable_type_url() { return type_url_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_type_url() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.type_url) return type_url_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1263,6 +1291,7 @@ inline ::std::string* Field::mutable_json_name() { return json_name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_json_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.json_name) return json_name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1306,6 +1335,7 @@ inline ::std::string* Field::mutable_default_value() { return default_value_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Field::release_default_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Field.default_value) return default_value_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1353,6 +1383,7 @@ inline ::std::string* Enum::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Enum::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1447,6 +1478,7 @@ inline ::google::protobuf::SourceContext* Enum::mutable_source_context() { return source_context_; } inline ::google::protobuf::SourceContext* Enum::release_source_context() { + // @@protoc_insertion_point(field_release:google.protobuf.Enum.source_context) ::google::protobuf::SourceContext* temp = source_context_; source_context_ = NULL; @@ -1511,6 +1543,7 @@ inline ::std::string* EnumValue::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* EnumValue::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.EnumValue.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1602,6 +1635,7 @@ inline ::std::string* Option::mutable_name() { return name_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } inline ::std::string* Option::release_name() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.name) return name_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -1636,6 +1670,7 @@ inline ::google::protobuf::Any* Option::mutable_value() { return value_; } inline ::google::protobuf::Any* Option::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.Option.value) ::google::protobuf::Any* temp = value_; value_ = NULL; diff --git a/src/google/protobuf/util/field_comparator.cc b/src/google/protobuf/util/field_comparator.cc index 9f613265..60b8b8a5 100644 --- a/src/google/protobuf/util/field_comparator.cc +++ b/src/google/protobuf/util/field_comparator.cc @@ -92,7 +92,27 @@ FieldComparator::ComparisonResult DefaultFieldComparator::Compare( case FieldDescriptor::CPPTYPE_INT64: COMPARE_FIELD(Int64); case FieldDescriptor::CPPTYPE_STRING: - COMPARE_FIELD(String); + if (field->is_repeated()) { + // Allocate scratch strings to store the result if a conversion is + // needed. + string scratch1; + string scratch2; + return ResultFromBoolean( + CompareString(*field, reflection_1->GetRepeatedStringReference( + message_1, field, index_1, &scratch1), + reflection_2->GetRepeatedStringReference( + message_2, field, index_2, &scratch2))); + } else { + // Allocate scratch strings to store the result if a conversion is + // needed. + string scratch1; + string scratch2; + return ResultFromBoolean(CompareString( + *field, + reflection_1->GetStringReference(message_1, field, &scratch1), + reflection_2->GetStringReference(message_2, field, &scratch2))); + } + break; case FieldDescriptor::CPPTYPE_UINT32: COMPARE_FIELD(UInt32); case FieldDescriptor::CPPTYPE_UINT64: diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc index 297c011a..1f3781a4 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource.cc @@ -70,6 +70,9 @@ using util::Status; using util::StatusOr; namespace { + +static int kDefaultMaxRecursionDepth = 64; + // Finds a field with the given number. NULL if none found. const google::protobuf::Field* FindFieldByNumber( const google::protobuf::Type& type, int number); @@ -116,7 +119,9 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( typeinfo_(TypeInfo::NewTypeInfo(type_resolver)), own_typeinfo_(true), type_(type), - use_lower_camel_for_enums_(false) { + use_lower_camel_for_enums_(false), + recursion_depth_(0), + max_recursion_depth_(kDefaultMaxRecursionDepth) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; } @@ -127,7 +132,9 @@ ProtoStreamObjectSource::ProtoStreamObjectSource( typeinfo_(typeinfo), own_typeinfo_(false), type_(type), - use_lower_camel_for_enums_(false) { + use_lower_camel_for_enums_(false), + recursion_depth_(0), + max_recursion_depth_(kDefaultMaxRecursionDepth) { GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL."; } @@ -741,7 +748,9 @@ Status ProtoStreamObjectSource::RenderField( if (use_type_renderer) { RETURN_IF_ERROR((*type_renderer)(this, *type, field_name, ow)); } else { + RETURN_IF_ERROR(IncrementRecursionDepth(type->name(), field_name)); RETURN_IF_ERROR(WriteMessage(*type, field_name, 0, true, ow)); + --recursion_depth_; } if (!stream_->ConsumedEntireMessage()) { return Status(util::error::INVALID_ARGUMENT, @@ -1037,6 +1046,17 @@ std::pair ProtoStreamObjectSource::ReadSecondsAndNanos( return std::pair(signed_seconds, signed_nanos); } +Status ProtoStreamObjectSource::IncrementRecursionDepth( + StringPiece type_name, StringPiece field_name) const { + if (++recursion_depth_ > max_recursion_depth_) { + return Status( + util::error::INVALID_ARGUMENT, + StrCat("Message too deep. Max recursion depth reached for type '", + type_name, "', field '", field_name, "'")); + } + return Status::OK; +} + namespace { // TODO(skarvaje): Speed this up by not doing a linear scan. const google::protobuf::Field* FindFieldByNumber( diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h index 17e03b73..d7d4347b 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource.h +++ b/src/google/protobuf/util/internal/protostream_objectsource.h @@ -110,6 +110,13 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { use_lower_camel_for_enums_ = value; } + // Sets the max recursion depth of proto message to be deserialized. Proto + // messages over this depth will fail to be deserialized. + // Default value is 64. + void set_max_recursion_depth(int max_depth) { + max_recursion_depth_ = max_depth; + } + protected: // Writes a proto2 Message to the ObjectWriter. When the given end_tag is // found this method will complete, allowing it to be used for parsing both @@ -251,6 +258,12 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { std::pair ReadSecondsAndNanos( const google::protobuf::Type& type) const; + // Helper function to check recursion depth and increment it. It will return + // Status::OK if the current depth is allowed. Otherwise an error is returned. + // type_name and field_name are used for error reporting. + util::Status IncrementRecursionDepth(StringPiece type_name, + StringPiece field_name) const; + // Input stream to read from. Ownership rests with the caller. google::protobuf::io::CodedInputStream* stream_; @@ -268,6 +281,12 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectSource : public ObjectSource { // Whether to render enums using lowerCamelCase. Defaults to false. bool use_lower_camel_for_enums_; + // Tracks current recursion depth. + mutable int recursion_depth_; + + // Maximum allowed recursion depth. + int max_recursion_depth_; + GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource); }; diff --git a/src/google/protobuf/util/internal/protostream_objectsource_test.cc b/src/google/protobuf/util/internal/protostream_objectsource_test.cc index 1b32c803..3f6fdf97 100644 --- a/src/google/protobuf/util/internal/protostream_objectsource_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectsource_test.cc @@ -70,6 +70,7 @@ using google::protobuf::testing::Author; using google::protobuf::testing::BadAuthor; using google::protobuf::testing::BadNestedBook; using google::protobuf::testing::Book; +using google::protobuf::testing::Cyclic; using google::protobuf::testing::Book_Label; using google::protobuf::testing::NestedBook; using google::protobuf::testing::PackedPrimitive; @@ -120,6 +121,7 @@ class ProtostreamObjectSourceTest google::protobuf::scoped_ptr os( helper_.NewProtoSource(&in_stream, GetTypeUrl(descriptor))); if (use_lower_camel_for_enums_) os->set_use_lower_camel_for_enums(true); + os->set_max_recursion_depth(64); return os->WriteTo(&mock_); } @@ -491,6 +493,33 @@ TEST_P(ProtostreamObjectSourceTest, EnumCaseIsUnchangedByDefault) { DoTest(book, Book::descriptor()); } +TEST_P(ProtostreamObjectSourceTest, CyclicMessageDepthTest) { + Cyclic cyclic; + cyclic.set_m_int(123); + + Book* book = cyclic.mutable_m_book(); + book->set_title("book title"); + Cyclic* current = cyclic.mutable_m_cyclic(); + Author* current_author = cyclic.add_m_author(); + for (int i = 0; i < 63; ++i) { + Author* next = current_author->add_friend_(); + next->set_id(i); + next->set_name(StrCat("author_name_", i)); + next->set_alive(true); + current_author = next; + } + + // Recursive message with depth (65) > max (max is 64). + for (int i = 0; i < 64; ++i) { + Cyclic* next = current->mutable_m_cyclic(); + next->set_m_str(StrCat("count_", i)); + current = next; + } + + Status status = ExecuteTest(cyclic, Cyclic::descriptor()); + EXPECT_EQ(util::error::INVALID_ARGUMENT, status.error_code()); +} + class ProtostreamObjectSourceMapsTest : public ProtostreamObjectSourceTest { protected: ProtostreamObjectSourceMapsTest() { diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc index 94ddb428..97a7909a 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc @@ -182,7 +182,8 @@ ProtoStreamObjectWriter::AnyWriter::AnyWriter(ProtoStreamObjectWriter* parent) data_(), output_(&data_), depth_(0), - has_injected_value_message_(false) {} + is_well_known_type_(false), + well_known_type_render_(NULL) {} ProtoStreamObjectWriter::AnyWriter::~AnyWriter() {} @@ -200,10 +201,19 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { parent_->master_type_.name())); invalid_ = true; } - } else if (!has_injected_value_message_ || depth_ != 1 || name != "value") { - // We don't propagate to ow_ StartObject("value") calls for nested Anys or - // Struct at depth 1 as they are nested one level deep with an injected + } else if (is_well_known_type_ && depth_ == 1) { + // For well-known types, the only other field besides "@type" should be a // "value" field. + if (name != "value" && !invalid_) { + parent_->InvalidValue("Any", + "Expect a \"value\" field for well-known types."); + invalid_ = true; + } + ow_->StartObject(""); + } else { + // Forward the call to the child writer if: + // 1. the type is not a well-known type. + // 2. or, we are in a nested Any, Struct, or Value object. ow_->StartObject(name); } } @@ -211,10 +221,9 @@ void ProtoStreamObjectWriter::AnyWriter::StartObject(StringPiece name) { bool ProtoStreamObjectWriter::AnyWriter::EndObject() { --depth_; // As long as depth_ >= 0, we know we haven't reached the end of Any. - // Propagate these EndObject() calls to the contained ow_. If we are in a - // nested Any or Struct type, ignore the second to last EndObject call (depth_ - // == -1) - if (ow_ != NULL && (!has_injected_value_message_ || depth_ >= 0)) { + // Propagate these EndObject() calls to the contained ow_. For regular + // message types, we propagate the end of Any as well. + if (ow_ != NULL && (depth_ >= 0 || !is_well_known_type_)) { ow_->EndObject(); } // A negative depth_ implies that we have reached the end of Any @@ -236,6 +245,13 @@ void ProtoStreamObjectWriter::AnyWriter::StartList(StringPiece name) { parent_->master_type_.name())); invalid_ = true; } + } else if (is_well_known_type_ && depth_ == 1) { + if (name != "value" && !invalid_) { + parent_->InvalidValue("Any", + "Expect a \"value\" field for well-known types."); + invalid_ = true; + } + ow_->StartList(""); } else { ow_->StartList(name); } @@ -266,17 +282,27 @@ void ProtoStreamObjectWriter::AnyWriter::RenderDataPiece( parent_->master_type_.name())); invalid_ = true; } - } else { - // Check to see if the data needs to be rendered with well-known-type - // renderer. - const TypeRenderer* type_renderer = - FindTypeRenderer(GetFullTypeWithUrl(ow_->master_type_.name())); - if (type_renderer) { - Status status = (*type_renderer)(ow_.get(), value); - if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); - } else { - ow_->RenderDataPiece(name, value); + } else if (depth_ == 0 && is_well_known_type_) { + if (name != "value" && !invalid_) { + parent_->InvalidValue("Any", + "Expect a \"value\" field for well-known types."); + invalid_ = true; } + if (well_known_type_render_ == NULL) { + // Only Any and Struct don't have a special type render but both of + // them expect a JSON object (i.e., a StartObject() call). + if (!invalid_) { + parent_->InvalidValue("Any", "Expect a JSON object."); + invalid_ = true; + } + } else { + ow_->ProtoWriter::StartObject(""); + Status status = (*well_known_type_render_)(ow_.get(), value); + if (!status.ok()) ow_->InvalidValue("Any", status.error_message()); + ow_->ProtoWriter::EndObject(); + } + } else { + ow_->RenderDataPiece(name, value); } } @@ -305,19 +331,31 @@ void ProtoStreamObjectWriter::AnyWriter::StartAny(const DataPiece& value) { // At this point, type is never null. const google::protobuf::Type* type = resolved_type.ValueOrDie(); - // If this is the case of an Any in an Any or Struct in an Any, we need to - // expect a StartObject call with "value" while we're at depth_ 0, which we - // should ignore (not propagate to our nested object writer). We also need to - // ignore the second-to-last EndObject call, and not propagate that either. - if (type->name() == kAnyType || type->name() == kStructType) { - has_injected_value_message_ = true; + well_known_type_render_ = FindTypeRenderer(type_url_); + if (well_known_type_render_ != NULL || + // Explicitly list Any and Struct here because they don't have a + // custom renderer. + type->name() == kAnyType || type->name() == kStructType) { + is_well_known_type_ = true; } // Create our object writer and initialize it with the first StartObject // call. ow_.reset(new ProtoStreamObjectWriter(parent_->typeinfo(), *type, &output_, parent_->listener())); - ow_->StartObject(""); + + // Don't call StartObject() for well-known types yet. Depending on the + // type of actual data, we may not need to call StartObject(). For + // example: + // { + // "@type": "type.googleapis.com/google.protobuf.Value", + // "value": [1, 2, 3], + // } + // With the above JSON representation, we will only call StartList() on the + // contained ow_. + if (!is_well_known_type_) { + ow_->StartObject(""); + } } void ProtoStreamObjectWriter::AnyWriter::WriteAny() { @@ -861,7 +899,7 @@ Status ProtoStreamObjectWriter::RenderFieldMask(ProtoStreamObjectWriter* ow, // conversions as much as possible. Because ToSnakeCase sometimes returns the // wrong value. google::protobuf::scoped_ptr > callback( - google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow)); + ::google::protobuf::internal::NewPermanentCallback(&RenderOneFieldPath, ow)); return DecodeCompactFieldMaskPaths(data.str(), callback.get()); } @@ -986,6 +1024,7 @@ ProtoStreamObjectWriter* ProtoStreamObjectWriter::RenderDataPiece( // not of the google.protobuf.NullType type, we do nothing. if (data.type() == DataPiece::TYPE_NULL && field->type_url() != kStructNullValueTypeUrl) { + Pop(); return this; } diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h index 96ea3f2b..e1162d43 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter.h +++ b/src/google/protobuf/util/internal/protostream_objectwriter.h @@ -167,9 +167,14 @@ class LIBPROTOBUF_EXPORT ProtoStreamObjectWriter : public ProtoWriter { // The depth within the Any, so we can track when we're done. int depth_; - // True if the message type contained in Any has a special "value" message - // injected. This is true for well-known message types like Any or Struct. - bool has_injected_value_message_; + // True if the type is a well-known type. Well-known types in Any + // has a special formating: + // { + // "@type": "type.googleapis.com/google.protobuf.XXX", + // "value": , + // } + bool is_well_known_type_; + TypeRenderer* well_known_type_render_; }; // Represents an item in a stack of items used to keep state between diff --git a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc index 41eaebc0..9a0dcde1 100644 --- a/src/google/protobuf/util/internal/protostream_objectwriter_test.cc +++ b/src/google/protobuf/util/internal/protostream_objectwriter_test.cc @@ -1413,6 +1413,8 @@ class ProtoStreamObjectWriterAnyTest : public BaseProtoStreamObjectWriterTest { descriptors.push_back(google::protobuf::DoubleValue::descriptor()); descriptors.push_back(google::protobuf::Timestamp::descriptor()); descriptors.push_back(google::protobuf::Any::descriptor()); + descriptors.push_back(google::protobuf::Value::descriptor()); + descriptors.push_back(google::protobuf::Struct::descriptor()); ResetTypeInfo(descriptors); } }; @@ -1621,6 +1623,222 @@ TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypeErrorTest) { CheckOutput(any); } +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "value": "abc" +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedPrimitiveValue) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + ::google::protobuf::Value value; + value.set_string_value("abc"); + any->PackFrom(value); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->RenderString("value", "abc") + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "value": { +// "foo": "abc" +// } +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedObjectValue) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + ::google::protobuf::Value value; + (*value.mutable_struct_value()->mutable_fields())["foo"].set_string_value( + "abc"); + any->PackFrom(value); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartObject("value") + ->RenderString("foo", "abc") + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "value": ["hello"], +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWithNestedArrayValue) { + AnyOut out; + ::google::protobuf::Any* any = out.mutable_any(); + + ::google::protobuf::Value value; + value.mutable_list_value()->add_values()->set_string_value("hello"); + any->PackFrom(value); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartList("value") + ->RenderString("", "hello") + ->EndList() + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(out); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "not_value": "" +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, + AnyWellKnownTypesNoValueFieldForPrimitive) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Expect a \"value\" field for well-known types."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->RenderString("not_value", "") + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "not_value": {} +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForObject) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Expect a \"value\" field for well-known types."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartObject("not_value") + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Value", +// "not_value": [], +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesNoValueFieldForArray) { + EXPECT_CALL( + listener_, + InvalidValue( + _, StringPiece("Any"), + StringPiece("Expect a \"value\" field for well-known types."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Value"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Value") + ->StartList("not_value") + ->EndList() + ->EndObject() + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Struct", +// "value": "", +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForStruct) { + EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), + StringPiece("Expect a JSON object."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Struct"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Struct") + ->RenderString("value", "") + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + +// Test the following case: +// +// { +// "any": { +// "@type": "type.googleapis.com/google.protobuf.Any", +// "value": "", +// } +// } +TEST_P(ProtoStreamObjectWriterAnyTest, AnyWellKnownTypesExpectObjectForAny) { + EXPECT_CALL(listener_, InvalidValue(_, StringPiece("Any"), + StringPiece("Expect a JSON object."))); + AnyOut any; + google::protobuf::Any* any_type = any.mutable_any(); + any_type->set_type_url("type.googleapis.com/google.protobuf.Any"); + + ow_->StartObject("") + ->StartObject("any") + ->RenderString("@type", "type.googleapis.com/google.protobuf.Any") + ->RenderString("value", "") + ->EndObject() + ->EndObject(); + CheckOutput(any); +} + class ProtoStreamObjectWriterFieldMaskTest : public BaseProtoStreamObjectWriterTest { protected: diff --git a/src/google/protobuf/util/internal/testdata/books.proto b/src/google/protobuf/util/internal/testdata/books.proto index 101a2bf0..1cbbba47 100644 --- a/src/google/protobuf/util/internal/testdata/books.proto +++ b/src/google/protobuf/util/internal/testdata/books.proto @@ -176,3 +176,12 @@ message NestedBook { message BadNestedBook { repeated uint32 book = 1 [packed=true]; // Packed to optional message. } + +// A recursively defined message. +message Cyclic { + optional int32 m_int = 1; + optional string m_str = 2; + optional Book m_book = 3; + repeated Author m_author = 5; + optional Cyclic m_cyclic = 4; +} diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index b2b3242a..fe8119bf 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc @@ -456,7 +456,9 @@ bool MessageDifferencer::Compare( const Descriptor* descriptor2 = message2.GetDescriptor(); if (descriptor1 != descriptor2) { GOOGLE_LOG(DFATAL) << "Comparison between two messages with different " - << "descriptors."; + << "descriptors. " + << descriptor1->full_name() << " vs " + << descriptor2->full_name(); return false; } // Expand google.protobuf.Any payload if possible. @@ -1385,7 +1387,7 @@ bool MessageDifferencer::MatchRepeatedFieldIndices( // algorithm will fail to find a maximum matching. // Here we use the argumenting path algorithm. MaximumMatcher::NodeMatchCallback* callback = - google::protobuf::internal::NewPermanentCallback( + ::google::protobuf::internal::NewPermanentCallback( this, &MessageDifferencer::IsMatch, repeated_field, key_comparator, &message1, &message2, parent_fields); diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc index 204c8029..60801423 100644 --- a/src/google/protobuf/wrappers.pb.cc +++ b/src/google/protobuf/wrappers.pb.cc @@ -388,12 +388,13 @@ DoubleValue* DoubleValue::New(::google::protobuf::Arena* arena) const { } void DoubleValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.DoubleValue) value_ = 0; } bool DoubleValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.DoubleValue) for (;;) { @@ -460,6 +461,7 @@ void DoubleValue::SerializeWithCachedSizes( } int DoubleValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.DoubleValue) int total_size = 0; // optional double value = 1; @@ -474,18 +476,22 @@ int DoubleValue::ByteSize() const { } void DoubleValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.DoubleValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const DoubleValue* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.DoubleValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.DoubleValue) MergeFrom(*source); } } void DoubleValue::MergeFrom(const DoubleValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.DoubleValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -493,12 +499,14 @@ void DoubleValue::MergeFrom(const DoubleValue& from) { } void DoubleValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.DoubleValue) if (&from == this) return; Clear(); MergeFrom(from); } void DoubleValue::CopyFrom(const DoubleValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.DoubleValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -638,12 +646,13 @@ FloatValue* FloatValue::New(::google::protobuf::Arena* arena) const { } void FloatValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.FloatValue) value_ = 0; } bool FloatValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.FloatValue) for (;;) { @@ -710,6 +719,7 @@ void FloatValue::SerializeWithCachedSizes( } int FloatValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.FloatValue) int total_size = 0; // optional float value = 1; @@ -724,18 +734,22 @@ int FloatValue::ByteSize() const { } void FloatValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.FloatValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const FloatValue* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.FloatValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.FloatValue) MergeFrom(*source); } } void FloatValue::MergeFrom(const FloatValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.FloatValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -743,12 +757,14 @@ void FloatValue::MergeFrom(const FloatValue& from) { } void FloatValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.FloatValue) if (&from == this) return; Clear(); MergeFrom(from); } void FloatValue::CopyFrom(const FloatValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.FloatValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -888,12 +904,13 @@ Int64Value* Int64Value::New(::google::protobuf::Arena* arena) const { } void Int64Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Int64Value) value_ = GOOGLE_LONGLONG(0); } bool Int64Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Int64Value) for (;;) { @@ -960,6 +977,7 @@ void Int64Value::SerializeWithCachedSizes( } int Int64Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int64Value) int total_size = 0; // optional int64 value = 1; @@ -976,18 +994,22 @@ int Int64Value::ByteSize() const { } void Int64Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Int64Value* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Int64Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Int64Value) MergeFrom(*source); } } void Int64Value::MergeFrom(const Int64Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -995,12 +1017,14 @@ void Int64Value::MergeFrom(const Int64Value& from) { } void Int64Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Int64Value) if (&from == this) return; Clear(); MergeFrom(from); } void Int64Value::CopyFrom(const Int64Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int64Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1140,12 +1164,13 @@ UInt64Value* UInt64Value::New(::google::protobuf::Arena* arena) const { } void UInt64Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt64Value) value_ = GOOGLE_ULONGLONG(0); } bool UInt64Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UInt64Value) for (;;) { @@ -1212,6 +1237,7 @@ void UInt64Value::SerializeWithCachedSizes( } int UInt64Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt64Value) int total_size = 0; // optional uint64 value = 1; @@ -1228,18 +1254,22 @@ int UInt64Value::ByteSize() const { } void UInt64Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UInt64Value* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UInt64Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UInt64Value) MergeFrom(*source); } } void UInt64Value::MergeFrom(const UInt64Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt64Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -1247,12 +1277,14 @@ void UInt64Value::MergeFrom(const UInt64Value& from) { } void UInt64Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UInt64Value) if (&from == this) return; Clear(); MergeFrom(from); } void UInt64Value::CopyFrom(const UInt64Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt64Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1392,12 +1424,13 @@ Int32Value* Int32Value::New(::google::protobuf::Arena* arena) const { } void Int32Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.Int32Value) value_ = 0; } bool Int32Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.Int32Value) for (;;) { @@ -1464,6 +1497,7 @@ void Int32Value::SerializeWithCachedSizes( } int Int32Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.Int32Value) int total_size = 0; // optional int32 value = 1; @@ -1480,18 +1514,22 @@ int Int32Value::ByteSize() const { } void Int32Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.Int32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const Int32Value* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.Int32Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.Int32Value) MergeFrom(*source); } } void Int32Value::MergeFrom(const Int32Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.Int32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -1499,12 +1537,14 @@ void Int32Value::MergeFrom(const Int32Value& from) { } void Int32Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.Int32Value) if (&from == this) return; Clear(); MergeFrom(from); } void Int32Value::CopyFrom(const Int32Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.Int32Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1644,12 +1684,13 @@ UInt32Value* UInt32Value::New(::google::protobuf::Arena* arena) const { } void UInt32Value::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.UInt32Value) value_ = 0u; } bool UInt32Value::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.UInt32Value) for (;;) { @@ -1716,6 +1757,7 @@ void UInt32Value::SerializeWithCachedSizes( } int UInt32Value::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.UInt32Value) int total_size = 0; // optional uint32 value = 1; @@ -1732,18 +1774,22 @@ int UInt32Value::ByteSize() const { } void UInt32Value::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.UInt32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const UInt32Value* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.UInt32Value) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.UInt32Value) MergeFrom(*source); } } void UInt32Value::MergeFrom(const UInt32Value& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.UInt32Value) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -1751,12 +1797,14 @@ void UInt32Value::MergeFrom(const UInt32Value& from) { } void UInt32Value::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.UInt32Value) if (&from == this) return; Clear(); MergeFrom(from); } void UInt32Value::CopyFrom(const UInt32Value& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.UInt32Value) if (&from == this) return; Clear(); MergeFrom(from); @@ -1896,12 +1944,13 @@ BoolValue* BoolValue::New(::google::protobuf::Arena* arena) const { } void BoolValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.BoolValue) value_ = false; } bool BoolValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.BoolValue) for (;;) { @@ -1968,6 +2017,7 @@ void BoolValue::SerializeWithCachedSizes( } int BoolValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BoolValue) int total_size = 0; // optional bool value = 1; @@ -1982,18 +2032,22 @@ int BoolValue::ByteSize() const { } void BoolValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BoolValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const BoolValue* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.BoolValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.BoolValue) MergeFrom(*source); } } void BoolValue::MergeFrom(const BoolValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BoolValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value() != 0) { set_value(from.value()); @@ -2001,12 +2055,14 @@ void BoolValue::MergeFrom(const BoolValue& from) { } void BoolValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.BoolValue) if (&from == this) return; Clear(); MergeFrom(from); } void BoolValue::CopyFrom(const BoolValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BoolValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2148,12 +2204,13 @@ StringValue* StringValue::New(::google::protobuf::Arena* arena) const { } void StringValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.StringValue) value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } bool StringValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.StringValue) for (;;) { @@ -2233,6 +2290,7 @@ void StringValue::SerializeWithCachedSizes( } int StringValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.StringValue) int total_size = 0; // optional string value = 1; @@ -2249,18 +2307,22 @@ int StringValue::ByteSize() const { } void StringValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.StringValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const StringValue* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.StringValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.StringValue) MergeFrom(*source); } } void StringValue::MergeFrom(const StringValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.StringValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value().size() > 0) { set_value(from.value()); @@ -2268,12 +2330,14 @@ void StringValue::MergeFrom(const StringValue& from) { } void StringValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.StringValue) if (&from == this) return; Clear(); MergeFrom(from); } void StringValue::CopyFrom(const StringValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.StringValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2349,10 +2413,12 @@ void StringValue::clear_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* StringValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* StringValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.StringValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -2378,7 +2444,7 @@ void StringValue::clear_value() { } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value) } #endif // PROTOBUF_INLINE_NOT_IN_HEADERS @@ -2465,12 +2531,13 @@ BytesValue* BytesValue::New(::google::protobuf::Arena* arena) const { } void BytesValue::Clear() { +// @@protoc_insertion_point(message_clear_start:google.protobuf.BytesValue) value_.ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } bool BytesValue::MergePartialFromCodedStream( ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!(EXPRESSION)) goto failure +#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure ::google::protobuf::uint32 tag; // @@protoc_insertion_point(parse_start:google.protobuf.BytesValue) for (;;) { @@ -2538,6 +2605,7 @@ void BytesValue::SerializeWithCachedSizes( } int BytesValue::ByteSize() const { +// @@protoc_insertion_point(message_byte_size_start:google.protobuf.BytesValue) int total_size = 0; // optional bytes value = 1; @@ -2554,18 +2622,22 @@ int BytesValue::ByteSize() const { } void BytesValue::MergeFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.BytesValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); const BytesValue* source = ::google::protobuf::internal::DynamicCastToGenerated( &from); if (source == NULL) { + // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.BytesValue) ::google::protobuf::internal::ReflectionOps::Merge(from, this); } else { + // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.BytesValue) MergeFrom(*source); } } void BytesValue::MergeFrom(const BytesValue& from) { +// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.BytesValue) if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__); if (from.value().size() > 0) { set_value(from.value()); @@ -2573,12 +2645,14 @@ void BytesValue::MergeFrom(const BytesValue& from) { } void BytesValue::CopyFrom(const ::google::protobuf::Message& from) { +// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.BytesValue) if (&from == this) return; Clear(); MergeFrom(from); } void BytesValue::CopyFrom(const BytesValue& from) { +// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.BytesValue) if (&from == this) return; Clear(); MergeFrom(from); @@ -2654,10 +2728,12 @@ void BytesValue::clear_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* BytesValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } ::std::string* BytesValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.BytesValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -2683,7 +2759,7 @@ void BytesValue::clear_value() { } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.BytesValue.value) } #endif // PROTOBUF_INLINE_NOT_IN_HEADERS diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h index 7dca938c..10784778 100644 --- a/src/google/protobuf/wrappers.pb.h +++ b/src/google/protobuf/wrappers.pb.h @@ -1048,10 +1048,12 @@ inline ::std::string* StringValue::mutable_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* StringValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.StringValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* StringValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.StringValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -1077,7 +1079,7 @@ inline void StringValue::unsafe_arena_set_allocated_value( } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.StringValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.StringValue.value) } // ------------------------------------------------------------------- @@ -1116,10 +1118,12 @@ inline ::std::string* BytesValue::mutable_value() { return value_.Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* BytesValue::release_value() { + // @@protoc_insertion_point(field_release:google.protobuf.BytesValue.value) return value_.Release(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), GetArenaNoVirtual()); } inline ::std::string* BytesValue::unsafe_arena_release_value() { + // @@protoc_insertion_point(field_unsafe_arena_release:google.protobuf.BytesValue.value) GOOGLE_DCHECK(GetArenaNoVirtual() != NULL); return value_.UnsafeArenaRelease(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), @@ -1145,7 +1149,7 @@ inline void BytesValue::unsafe_arena_set_allocated_value( } value_.UnsafeArenaSetAllocated(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value, GetArenaNoVirtual()); - // @@protoc_insertion_point(field_set_allocated:google.protobuf.BytesValue.value) + // @@protoc_insertion_point(field_unsafe_arena_set_allocated:google.protobuf.BytesValue.value) } #endif // !PROTOBUF_INLINE_NOT_IN_HEADERS From f86d39c29546b90426a013163f460e815f4499f4 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 28 Apr 2016 14:43:22 -0700 Subject: [PATCH 102/123] Update file lists. --- BUILD | 2 +- cmake/tests.cmake | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/BUILD b/BUILD index ab147e5c..8b1046b9 100644 --- a/BUILD +++ b/BUILD @@ -464,8 +464,8 @@ cc_test( "src/google/protobuf/message_unittest.cc", "src/google/protobuf/no_field_presence_test.cc", "src/google/protobuf/preserve_unknown_enum_test.cc", - "src/google/protobuf/proto3_arena_unittest.cc", "src/google/protobuf/proto3_arena_lite_unittest.cc", + "src/google/protobuf/proto3_arena_unittest.cc", "src/google/protobuf/proto3_lite_unittest.cc", "src/google/protobuf/reflection_ops_unittest.cc", "src/google/protobuf/repeated_field_reflection_unittest.cc", diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 941f33d8..76fdf8ef 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -52,6 +52,8 @@ set(tests_protos google/protobuf/unittest_preserve_unknown_enum.proto google/protobuf/unittest_preserve_unknown_enum2.proto google/protobuf/unittest_proto3_arena.proto + google/protobuf/unittest_proto3_arena_lite.proto + google/protobuf/unittest_proto3_lite.proto google/protobuf/unittest_well_known_types.proto google/protobuf/util/internal/testdata/anys.proto google/protobuf/util/internal/testdata/books.proto @@ -116,6 +118,7 @@ set(tests_files ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/cpp_unittest.cc + ${protobuf_source_dir}/src/google/protobuf/compiler/cpp/metadata_test.cc ${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_generator_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/importer_unittest.cc ${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment_unittest.cc @@ -140,7 +143,9 @@ set(tests_files ${protobuf_source_dir}/src/google/protobuf/message_unittest.cc ${protobuf_source_dir}/src/google/protobuf/no_field_presence_test.cc ${protobuf_source_dir}/src/google/protobuf/preserve_unknown_enum_test.cc + ${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_ops_unittest.cc ${protobuf_source_dir}/src/google/protobuf/repeated_field_reflection_unittest.cc ${protobuf_source_dir}/src/google/protobuf/repeated_field_unittest.cc From 61307b86f561721ac47ecd74d9fd1dffa0acad53 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Fri, 29 Apr 2016 10:10:40 +0100 Subject: [PATCH 103/123] Allow custom type URL prefixes in Any.Pack (And likewise ignore the prefix in unpack.) Fixes issue #1459. --- .../Google.Protobuf.Test/JsonFormatterTest.cs | 9 ++++ .../Google.Protobuf.Test/JsonParserTest.cs | 11 +++++ .../WellKnownTypes/AnyTest.cs | 27 +++++++++++ csharp/src/Google.Protobuf/JsonFormatter.cs | 14 +----- csharp/src/Google.Protobuf/JsonParser.cs | 2 +- .../WellKnownTypes/AnyPartial.cs | 48 +++++++++++++++---- 6 files changed, 88 insertions(+), 23 deletions(-) diff --git a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs index 0b6cd7e6..827a7595 100644 --- a/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonFormatterTest.cs @@ -480,6 +480,15 @@ namespace Google.Protobuf AssertJson("{ '@type': 'type.googleapis.com/protobuf_unittest.TestAllTypes', 'singleInt32': 10, 'singleNestedMessage': { 'bb': 20 } }", formatter.Format(any)); } + [Test] + public void AnyMessageType_CustomPrefix() + { + var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor))); + var message = new TestAllTypes { SingleInt32 = 10 }; + var any = Any.Pack(message, "foo.bar/baz"); + AssertJson("{ '@type': 'foo.bar/baz/protobuf_unittest.TestAllTypes', 'singleInt32': 10 }", formatter.Format(any)); + } + [Test] public void AnyNested() { diff --git a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs index 684f52b4..c3ad851b 100644 --- a/csharp/src/Google.Protobuf.Test/JsonParserTest.cs +++ b/csharp/src/Google.Protobuf.Test/JsonParserTest.cs @@ -810,6 +810,17 @@ namespace Google.Protobuf Assert.AreEqual(original, parser.Parse(valueFirstJson)); } + [Test] + public void Any_CustomPrefix() + { + var registry = TypeRegistry.FromMessages(TestAllTypes.Descriptor); + var message = new TestAllTypes { SingleInt32 = 10 }; + var original = Any.Pack(message, "custom.prefix/middle-part"); + var parser = new JsonParser(new JsonParser.Settings(10, registry)); + string json = "{ \"@type\": \"custom.prefix/middle-part/protobuf_unittest.TestAllTypes\", \"singleInt32\": 10 }"; + Assert.AreEqual(original, parser.Parse(json)); + } + [Test] public void Any_UnknownType() { diff --git a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs index f3593e5f..f21be7d9 100644 --- a/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs +++ b/csharp/src/Google.Protobuf.Test/WellKnownTypes/AnyTest.cs @@ -46,6 +46,24 @@ namespace Google.Protobuf.WellKnownTypes Assert.AreEqual(message.CalculateSize(), any.Value.Length); } + [Test] + public void Pack_WithCustomPrefix() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var any = Any.Pack(message, "foo.bar/baz"); + Assert.AreEqual("foo.bar/baz/protobuf_unittest.TestAllTypes", any.TypeUrl); + Assert.AreEqual(message.CalculateSize(), any.Value.Length); + } + + [Test] + public void Pack_WithCustomPrefixTrailingSlash() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var any = Any.Pack(message, "foo.bar/baz/"); + Assert.AreEqual("foo.bar/baz/protobuf_unittest.TestAllTypes", any.TypeUrl); + Assert.AreEqual(message.CalculateSize(), any.Value.Length); + } + [Test] public void Unpack_WrongType() { @@ -63,6 +81,15 @@ namespace Google.Protobuf.WellKnownTypes Assert.AreEqual(message, unpacked); } + [Test] + public void Unpack_CustomPrefix_Success() + { + var message = SampleMessages.CreateFullTestAllTypes(); + var any = Any.Pack(message, "foo.bar/baz"); + var unpacked = any.Unpack(); + Assert.AreEqual(message, unpacked); + } + [Test] public void ToString_WithValues() { diff --git a/csharp/src/Google.Protobuf/JsonFormatter.cs b/csharp/src/Google.Protobuf/JsonFormatter.cs index 73a4f64b..83772473 100644 --- a/csharp/src/Google.Protobuf/JsonFormatter.cs +++ b/csharp/src/Google.Protobuf/JsonFormatter.cs @@ -567,7 +567,7 @@ namespace Google.Protobuf string typeUrl = (string) value.Descriptor.Fields[Any.TypeUrlFieldNumber].Accessor.GetValue(value); ByteString data = (ByteString) value.Descriptor.Fields[Any.ValueFieldNumber].Accessor.GetValue(value); - string typeName = GetTypeName(typeUrl); + string typeName = Any.GetTypeName(typeUrl); MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName); if (descriptor == null) { @@ -608,17 +608,7 @@ namespace Google.Protobuf writer.Write(data.ToBase64()); writer.Write('"'); writer.Write(" }"); - } - - internal static string GetTypeName(String typeUrl) - { - string[] parts = typeUrl.Split('/'); - if (parts.Length != 2 || parts[0] != TypeUrlPrefix) - { - throw new InvalidProtocolBufferException($"Invalid type url: {typeUrl}"); - } - return parts[1]; - } + } private void WriteStruct(TextWriter writer, IMessage message) { diff --git a/csharp/src/Google.Protobuf/JsonParser.cs b/csharp/src/Google.Protobuf/JsonParser.cs index 80d3013d..d738ebb0 100644 --- a/csharp/src/Google.Protobuf/JsonParser.cs +++ b/csharp/src/Google.Protobuf/JsonParser.cs @@ -513,7 +513,7 @@ namespace Google.Protobuf throw new InvalidProtocolBufferException("Expected string value for Any.@type"); } string typeUrl = token.StringValue; - string typeName = JsonFormatter.GetTypeName(typeUrl); + string typeName = Any.GetTypeName(typeUrl); MessageDescriptor descriptor = settings.TypeRegistry.Find(typeName); if (descriptor == null) diff --git a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs index 9d43856e..f4fac738 100644 --- a/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs +++ b/csharp/src/Google.Protobuf/WellKnownTypes/AnyPartial.cs @@ -36,11 +36,27 @@ namespace Google.Protobuf.WellKnownTypes { public partial class Any { + private const string DefaultPrefix = "type.googleapis.com"; + // This could be moved to MessageDescriptor if we wanted to, but keeping it here means // all the Any-specific code is in the same place. - private static string GetTypeUrl(MessageDescriptor descriptor) + private static string GetTypeUrl(MessageDescriptor descriptor, string prefix) => + prefix.EndsWith("/") ? prefix + descriptor.FullName : prefix + "/" + descriptor.FullName; + + /// + /// Retrieves the type name for a type URL. This is always just the last part of the URL, + /// after the trailing slash. No validation of anything before the trailing slash is performed. + /// If the type URL does not include a slash, an empty string is returned rather than an exception + /// being thrown; this won't match any types, and the calling code is probably in a better position + /// to give a meaningful error. + /// There is no handling of fragments or queries at the moment. + /// + /// The URL to extract the type name from + /// The type name + internal static string GetTypeName(string typeUrl) { - return "type.googleapis.com/" + descriptor.FullName; + int lastSlash = typeUrl.LastIndexOf('/'); + return lastSlash == -1 ? "" : typeUrl.Substring(lastSlash + 1); } /// @@ -55,25 +71,37 @@ namespace Google.Protobuf.WellKnownTypes // Note: this doesn't perform as well is it might. We could take a MessageParser in an alternative overload, // which would be expected to perform slightly better... although the difference is likely to be negligible. T target = new T(); - string targetTypeUrl = GetTypeUrl(target.Descriptor); - if (TypeUrl != targetTypeUrl) + if (GetTypeName(TypeUrl) != target.Descriptor.FullName) { - throw new InvalidProtocolBufferException(string.Format("Type url for {0} is {1}; Any message's type url is {2}", - target.Descriptor.Name, targetTypeUrl, TypeUrl)); + throw new InvalidProtocolBufferException( + $"Full type name for {target.Descriptor.Name} is {target.Descriptor.FullName}; Any message's type url is {TypeUrl}"); } target.MergeFrom(Value); return target; } /// - /// Packs the specified message into an Any message. + /// Packs the specified message into an Any message using a type URL prefix of "type.googleapis.com". /// /// The message to pack. /// An Any message with the content and type URL of . - public static Any Pack(IMessage message) + public static Any Pack(IMessage message) => Pack(message, DefaultPrefix); + + /// + /// Packs the specified message into an Any message using the specified type URL prefix. + /// + /// The message to pack. + /// The prefix for the type URL. + /// An Any message with the content and type URL of . + public static Any Pack(IMessage message, string typeUrlPrefix) { - ProtoPreconditions.CheckNotNull(message, "message"); - return new Any { TypeUrl = GetTypeUrl(message.Descriptor), Value = message.ToByteString() }; + ProtoPreconditions.CheckNotNull(message, nameof(message)); + ProtoPreconditions.CheckNotNull(typeUrlPrefix, nameof(typeUrlPrefix)); + return new Any + { + TypeUrl = GetTypeUrl(message.Descriptor, typeUrlPrefix), + Value = message.ToByteString() + }; } } } From 1ce5bd8e84085a3f89017d71442c75fd4a8dc9f6 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 29 Apr 2016 09:39:26 -0700 Subject: [PATCH 104/123] Updates for PR comments. --- benchmarks/Makefile.am | 3 ++- benchmarks/benchmarks.proto | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am index 79581ee9..f0ed4899 100644 --- a/benchmarks/Makefile.am +++ b/benchmarks/Makefile.am @@ -27,8 +27,9 @@ nodist_generate_datasets_SOURCES = \ $(benchmarks_protoc_outputs) \ $(benchmarks_protoc_outputs_proto2) -# Explicit deps beacuse BUILT_SOURCES are only done before a "make all/check" +# Explicit deps because BUILT_SOURCES are only done before a "make all/check" # so a direct "make test_cpp" could fail if parallel enough. +# See: https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html#Recording-Dependencies-manually generate_datasets-generate_datasets.$(OBJEXT): benchmarks.pb.h google_message1.h google_message2.h $(benchmarks_protoc_outputs): protoc_middleman diff --git a/benchmarks/benchmarks.proto b/benchmarks/benchmarks.proto index 5c2706df..0ac3bf33 100644 --- a/benchmarks/benchmarks.proto +++ b/benchmarks/benchmarks.proto @@ -68,16 +68,16 @@ message Metric { // A unique ID for these results. Used for de-duping. string guid = 1; - // The tags specify exactly what benchmark was run against the dataset. + // The labels specify exactly what benchmark was run against the dataset. // The specific benchmark suite can decide what these mean, but here are - // some common tags that have a predefined meaning: + // some common labels that have a predefined meaning: // // - "dataset": for tests that pertain to a specific dataset. // // For example: // // # Tests parsing from binary proto string using arenas. - // tags={ + // labels={ // dataset: "testalltypes", // op: "parse", // format: "binaryproto", @@ -86,7 +86,7 @@ message Metric { // } // // # Tests serializing to JSON string. - // tags={ + // labels={ // dataset: "testalltypes", // op: "serialize", // format: "json", From cb36bde04716436fc9560ac908ca4551bdc614fb Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 29 Apr 2016 09:52:20 -0700 Subject: [PATCH 105/123] Make the C++ tests build the benchmarking code. --- tests.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests.sh b/tests.sh index fd81b764..75bf9001 100755 --- a/tests.sh +++ b/tests.sh @@ -36,6 +36,9 @@ build_cpp() { internal_build_cpp make check -j2 cd conformance && make test_cpp && cd .. + + # Verify benchmarking code can build successfully. + cd benchmarks && make && cd .. } build_cpp_distcheck() { From 49a8918e9742d4bc9f577df9599061e342516b96 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 29 Apr 2016 10:19:03 -0700 Subject: [PATCH 106/123] Read files directly from filesystem since xxd isn't always available. --- benchmarks/Makefile.am | 12 +----------- benchmarks/generate_datasets.cc | 18 +++++++++++++----- tests.sh | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am index f0ed4899..1e162eb1 100644 --- a/benchmarks/Makefile.am +++ b/benchmarks/Makefile.am @@ -22,30 +22,20 @@ generate_datasets_LDADD = $(top_srcdir)/src/libprotobuf.la generate_datasets_SOURCES = generate_datasets.cc generate_datasets_CPPFLAGS = -I$(top_srcdir)/src -I$(srcdir) nodist_generate_datasets_SOURCES = \ - google_message1.h \ - google_message2.h \ $(benchmarks_protoc_outputs) \ $(benchmarks_protoc_outputs_proto2) # Explicit deps because BUILT_SOURCES are only done before a "make all/check" # so a direct "make test_cpp" could fail if parallel enough. # See: https://www.gnu.org/software/automake/manual/html_node/Built-Sources-Example.html#Recording-Dependencies-manually -generate_datasets-generate_datasets.$(OBJEXT): benchmarks.pb.h google_message1.h google_message2.h +generate_datasets-generate_datasets.$(OBJEXT): benchmarks.pb.h $(benchmarks_protoc_outputs): protoc_middleman $(benchmarks_protoc_outputs_proto2): protoc_middleman2 -google_message1.h: google_message1.dat - xxd -i $< $@ - -google_message2.h: google_message2.dat - xxd -i $< $@ - CLEANFILES = \ $(benchmarks_protoc_outputs) \ $(benchmarks_protoc_outputs_proto2) \ - google_message1.h \ - google_message2.h \ protoc_middleman \ protoc_middleman2 \ dataset.* diff --git a/benchmarks/generate_datasets.cc b/benchmarks/generate_datasets.cc index f6f30cd8..8e9b441c 100644 --- a/benchmarks/generate_datasets.cc +++ b/benchmarks/generate_datasets.cc @@ -34,8 +34,6 @@ const char *file_suffix = ".pb"; #include #include #include "benchmarks.pb.h" -#include "google_message1.h" -#include "google_message2.h" using benchmarks::BenchmarkDataset; using google::protobuf::Descriptor; @@ -102,13 +100,23 @@ void WriteFile(const std::string& name, const std::string& message_name, WriteFileWithPayloads(name, message_name, payloads); } +std::string ReadFile(const std::string& name) { + std::ifstream file(name); + GOOGLE_CHECK(file.is_open()) << "Couldn't find file '" << name << + "', please make sure you are running " + "this command from the benchmarks/ " + "directory.\n"; + return std::string((std::istreambuf_iterator(file)), + std::istreambuf_iterator()); +} + int main() { WriteFile("google_message1_proto3", "benchmarks.p3.GoogleMessage1", - ARRAY_TO_STRING(google_message1_dat)); + ReadFile("google_message1.dat")); WriteFile("google_message1_proto2", "benchmarks.p2.GoogleMessage1", - ARRAY_TO_STRING(google_message1_dat)); + ReadFile("google_message1.dat")); // Not in proto3 because it has a group, which is not supported. WriteFile("google_message2", "benchmarks.p2.GoogleMessage2", - ARRAY_TO_STRING(google_message2_dat)); + ReadFile("google_message2.dat")); } diff --git a/tests.sh b/tests.sh index 75bf9001..6a9439a5 100755 --- a/tests.sh +++ b/tests.sh @@ -38,7 +38,7 @@ build_cpp() { cd conformance && make test_cpp && cd .. # Verify benchmarking code can build successfully. - cd benchmarks && make && cd .. + cd benchmarks && make && ./generate-datasets && cd .. } build_cpp_distcheck() { From b2d4b1a528a4b2e808ac2924e0552e4ea94c1d87 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 29 Apr 2016 10:22:56 -0700 Subject: [PATCH 107/123] Fixed for pre-C++11 ifstream which does not accept std::string. --- benchmarks/generate_datasets.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/generate_datasets.cc b/benchmarks/generate_datasets.cc index 8e9b441c..dab635e7 100644 --- a/benchmarks/generate_datasets.cc +++ b/benchmarks/generate_datasets.cc @@ -86,7 +86,7 @@ void WriteFileWithPayloads(const std::string& name, std::ofstream writer; std::string fname = file_prefix + name + file_suffix; - writer.open(fname); + writer.open(fname.c_str()); writer << serialized; writer.close(); @@ -101,7 +101,7 @@ void WriteFile(const std::string& name, const std::string& message_name, } std::string ReadFile(const std::string& name) { - std::ifstream file(name); + std::ifstream file(name.c_str()); GOOGLE_CHECK(file.is_open()) << "Couldn't find file '" << name << "', please make sure you are running " "this command from the benchmarks/ " From 1f8b6da920799d3aaa6f4d17f87c0caf87b76b3e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 29 Apr 2016 20:00:43 +0200 Subject: [PATCH 108/123] Few tweaks to the rakefile to permit native gems compilation with the proto files generation. --- ruby/Gemfile.lock | 2 +- ruby/Rakefile | 64 +++++++++++++++++++----------------- ruby/google-protobuf.gemspec | 2 +- 3 files changed, 36 insertions(+), 32 deletions(-) diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock index 27e57506..d0eb9cc4 100644 --- a/ruby/Gemfile.lock +++ b/ruby/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - google-protobuf (3.0.0.alpha.5.0) + google-protobuf (3.0.0.alpha.5.0.5) GEM remote: https://rubygems.org/ diff --git a/ruby/Rakefile b/ruby/Rakefile index 8eb7a2df..45694d1f 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -5,6 +5,38 @@ require "rake/testtask" spec = Gem::Specification.load("google-protobuf.gemspec") +well_known_protos = %w[ + google/protobuf/any.proto + google/protobuf/api.proto + google/protobuf/duration.proto + google/protobuf/empty.proto + google/protobuf/field_mask.proto + google/protobuf/source_context.proto + google/protobuf/struct.proto + google/protobuf/timestamp.proto + google/protobuf/type.proto + google/protobuf/wrappers.proto +] + +# These are omitted for now because we don't support proto2. +proto2_protos = %w[ + google/protobuf/descriptor.proto + google/protobuf/compiler/plugin.proto +] + +genproto_output = [] + +unless ENV['IN_DOCKER'] == 'true' + well_known_protos.each do |proto_file| + input_file = "../src/" + proto_file + output_file = "lib/" + proto_file.sub(/\.proto$/, ".rb") + genproto_output << output_file + file output_file => input_file do |file_task| + sh "../src/protoc -I../src --ruby_out=lib #{input_file}" + end + end +end + if RUBY_PLATFORM == "java" if `which mvn` == '' raise ArgumentError, "maven needs to be installed" @@ -30,38 +62,10 @@ else task 'gem:windows' do require 'rake_compiler_dock' - RakeCompilerDock.sh "bundle && rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.6" + RakeCompilerDock.sh "bundle && IN_DOCKER=true rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0" end -end -well_known_protos = %w[ - google/protobuf/any.proto - google/protobuf/api.proto - google/protobuf/duration.proto - google/protobuf/empty.proto - google/protobuf/field_mask.proto - google/protobuf/source_context.proto - google/protobuf/struct.proto - google/protobuf/timestamp.proto - google/protobuf/type.proto - google/protobuf/wrappers.proto -] - -# These are omitted for now because we don't support proto2. -proto2_protos = %w[ - google/protobuf/descriptor.proto - google/protobuf/compiler/plugin.proto -] - -genproto_output = [] - -well_known_protos.each do |proto_file| - input_file = "../src/" + proto_file - output_file = "lib/" + proto_file.sub(/\.proto$/, ".rb") - genproto_output << output_file - file output_file => input_file do |file_task| - sh "../src/protoc -I../src --ruby_out=lib #{input_file}" - end + task 'gem:native' => [:genproto, 'gem:windows'] end diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 7b64ee77..1fa626fe 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.0.0.alpha.5.0" + s.version = "3.0.0.alpha.5.0.5" s.licenses = ["BSD"] s.summary = "Protocol Buffers" s.description = "Protocol Buffers are Google's data interchange format." From cf7e99db969dba4a78b97d1a0cd5228cc8e6ec8c Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 29 Apr 2016 11:31:57 -0700 Subject: [PATCH 109/123] Fix cp -r usage to be portable. cp -r foo/ bar/ in linux will create a bar/foo directoy. In the objectivec generate descritpor case, well known types will be created in objectivec/google/google/protobuf/.. if the command is run under linux. Adding the trailing period fixes the behavior inconsistency. --- objectivec/generate_well_known_types.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/objectivec/generate_well_known_types.sh b/objectivec/generate_well_known_types.sh index 73be50ff..36c34603 100755 --- a/objectivec/generate_well_known_types.sh +++ b/objectivec/generate_well_known_types.sh @@ -73,4 +73,4 @@ fi # Copy them over. echo "Copying over updated WellKnownType sources." -cp -r "${TMP_DIR}/google/" "${ProtoRootDir}/objectivec/google/" +cp -r "${TMP_DIR}/google/." "${ProtoRootDir}/objectivec/google/" From e0df23ac1483dcc68d2429c804aeba0508714892 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 29 Apr 2016 11:41:38 -0700 Subject: [PATCH 110/123] Update descritpor protos for objc --- .../google/google/protobuf/Any.pbobjc.h | 134 ---- .../google/google/protobuf/Any.pbobjc.m | 93 --- .../google/google/protobuf/Api.pbobjc.h | 262 ------- .../google/google/protobuf/Api.pbobjc.m | 348 --------- .../google/google/protobuf/Duration.pbobjc.h | 101 --- .../google/google/protobuf/Duration.pbobjc.m | 88 --- .../google/google/protobuf/Empty.pbobjc.h | 53 -- .../google/google/protobuf/Empty.pbobjc.m | 64 -- .../google/google/protobuf/FieldMask.pbobjc.h | 202 ----- .../google/google/protobuf/FieldMask.pbobjc.m | 77 -- .../google/protobuf/SourceContext.pbobjc.h | 54 -- .../google/protobuf/SourceContext.pbobjc.m | 77 -- .../google/google/protobuf/Struct.pbobjc.h | 167 ----- .../google/google/protobuf/Struct.pbobjc.m | 273 ------- .../google/google/protobuf/Timestamp.pbobjc.h | 113 --- .../google/google/protobuf/Timestamp.pbobjc.m | 88 --- .../google/google/protobuf/Type.pbobjc.h | 373 ---------- .../google/google/protobuf/Type.pbobjc.m | 693 ------------------ .../google/google/protobuf/Wrappers.pbobjc.h | 182 ----- .../google/google/protobuf/Wrappers.pbobjc.m | 420 ----------- objectivec/google/protobuf/Any.pbobjc.h | 2 + objectivec/google/protobuf/FieldMask.pbobjc.h | 2 +- 22 files changed, 3 insertions(+), 3863 deletions(-) delete mode 100644 objectivec/google/google/protobuf/Any.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Any.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/Api.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Api.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/Duration.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Duration.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/Empty.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Empty.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/FieldMask.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/FieldMask.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/SourceContext.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/SourceContext.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/Struct.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Struct.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/Timestamp.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Timestamp.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/Type.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Type.pbobjc.m delete mode 100644 objectivec/google/google/protobuf/Wrappers.pbobjc.h delete mode 100644 objectivec/google/google/protobuf/Wrappers.pbobjc.m diff --git a/objectivec/google/google/protobuf/Any.pbobjc.h b/objectivec/google/google/protobuf/Any.pbobjc.h deleted file mode 100644 index 4002a989..00000000 --- a/objectivec/google/google/protobuf/Any.pbobjc.h +++ /dev/null @@ -1,134 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/any.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBAnyRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBAnyRoot : GPBRootObject -@end - -#pragma mark - GPBAny - -typedef GPB_ENUM(GPBAny_FieldNumber) { - GPBAny_FieldNumber_TypeURL = 1, - GPBAny_FieldNumber_Value = 2, -}; - -/// `Any` contains an arbitrary serialized protocol buffer message along with a -/// URL that describes the type of the serialized message. -/// -/// Protobuf library provides support to pack/unpack Any values in the form -/// of utility functions or additional generated methods of the Any type. -/// -/// Example 1: Pack and unpack a message in C++. -/// -/// Foo foo = ...; -/// Any any; -/// any.PackFrom(foo); -/// ... -/// if (any.UnpackTo(&foo)) { -/// ... -/// } -/// -/// Example 2: Pack and unpack a message in Java. -/// -/// Foo foo = ...; -/// Any any = Any.pack(foo); -/// ... -/// if (any.is(Foo.class)) { -/// foo = any.unpack(Foo.class); -/// } -/// -/// The pack methods provided by protobuf library will by default use -/// 'type.googleapis.com/full.type.name' as the type URL and the unpack -/// methods only use the fully qualified type name after the last '/' -/// in the type URL, for example "foo.bar.com/x/y.z" will yield type -/// name "y.z". -/// -/// -/// JSON -/// ==== -/// The JSON representation of an `Any` value uses the regular -/// representation of the deserialized, embedded message, with an -/// additional field `\@type` which contains the type URL. Example: -/// -/// package google.profile; -/// message Person { -/// string first_name = 1; -/// string last_name = 2; -/// } -/// -/// { -/// "\@type": "type.googleapis.com/google.profile.Person", -/// "firstName": , -/// "lastName": -/// } -/// -/// If the embedded message type is well-known and has a custom JSON -/// representation, that representation will be embedded adding a field -/// `value` which holds the custom JSON in addition to the `\@type` -/// field. Example (for message [google.protobuf.Duration][]): -/// -/// { -/// "\@type": "type.googleapis.com/google.protobuf.Duration", -/// "value": "1.212s" -/// } -@interface GPBAny : GPBMessage - -/// A URL/resource name whose content describes the type of the -/// serialized protocol buffer message. -/// -/// For URLs which use the schema `http`, `https`, or no schema, the -/// following restrictions and interpretations apply: -/// -/// * If no schema is provided, `https` is assumed. -/// * The last segment of the URL's path must represent the fully -/// qualified name of the type (as in `path/google.protobuf.Duration`). -/// The name should be in a canonical form (e.g., leading "." is -/// not accepted). -/// * An HTTP GET on the URL must yield a [google.protobuf.Type][] -/// value in binary format, or produce an error. -/// * Applications are allowed to cache lookup results based on the -/// URL, or have them precompiled into a binary to avoid any -/// lookup. Therefore, binary compatibility needs to be preserved -/// on changes to types. (Use versioned type names to manage -/// breaking changes.) -/// -/// Schemas other than `http`, `https` (or the empty schema) might be -/// used with implementation specific semantics. -@property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL; - -/// Must be a valid serialized protocol buffer of the above specified type. -@property(nonatomic, readwrite, copy, null_resettable) NSData *value; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Any.pbobjc.m b/objectivec/google/google/protobuf/Any.pbobjc.m deleted file mode 100644 index 6a1bf894..00000000 --- a/objectivec/google/google/protobuf/Any.pbobjc.m +++ /dev/null @@ -1,93 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/any.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Any.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBAnyRoot - -@implementation GPBAnyRoot - -@end - -#pragma mark - GPBAnyRoot_FileDescriptor - -static GPBFileDescriptor *GPBAnyRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBAny - -@implementation GPBAny - -@dynamic typeURL; -@dynamic value; - -typedef struct GPBAny__storage_ { - uint32_t _has_storage_[1]; - NSString *typeURL; - NSData *value; -} GPBAny__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "typeURL", - .dataTypeSpecific.className = NULL, - .number = GPBAny_FieldNumber_TypeURL, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBAny__storage_, typeURL), - .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, - .dataType = GPBDataTypeString, - }, - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBAny_FieldNumber_Value, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBAny__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBAny class] - rootClass:[GPBAnyRoot class] - file:GPBAnyRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBAny__storage_) - flags:0]; -#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - static const char *extraTextFormatInfo = - "\001\001\004\241!!\000"; - [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; -#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Api.pbobjc.h b/objectivec/google/google/protobuf/Api.pbobjc.h deleted file mode 100644 index d66df629..00000000 --- a/objectivec/google/google/protobuf/Api.pbobjc.h +++ /dev/null @@ -1,262 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/api.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GPBMethod; -@class GPBMixin; -@class GPBOption; -@class GPBSourceContext; -GPB_ENUM_FWD_DECLARE(GPBSyntax); - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBApiRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBApiRoot : GPBRootObject -@end - -#pragma mark - GPBApi - -typedef GPB_ENUM(GPBApi_FieldNumber) { - GPBApi_FieldNumber_Name = 1, - GPBApi_FieldNumber_MethodsArray = 2, - GPBApi_FieldNumber_OptionsArray = 3, - GPBApi_FieldNumber_Version = 4, - GPBApi_FieldNumber_SourceContext = 5, - GPBApi_FieldNumber_MixinsArray = 6, - GPBApi_FieldNumber_Syntax = 7, -}; - -/// Api is a light-weight descriptor for a protocol buffer service. -@interface GPBApi : GPBMessage - -/// The fully qualified name of this api, including package name -/// followed by the api's simple name. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// The methods of this api, in unspecified order. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *methodsArray; -/// The number of items in @c methodsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger methodsArray_Count; - -/// Any metadata attached to the API. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; -/// The number of items in @c optionsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger optionsArray_Count; - -/// A version string for this api. If specified, must have the form -/// `major-version.minor-version`, as in `1.10`. If the minor version -/// is omitted, it defaults to zero. If the entire version field is -/// empty, the major version is derived from the package name, as -/// outlined below. If the field is not empty, the version in the -/// package name will be verified to be consistent with what is -/// provided here. -/// -/// The versioning schema uses [semantic -/// versioning](http://semver.org) where the major version number -/// indicates a breaking change and the minor version an additive, -/// non-breaking change. Both version numbers are signals to users -/// what to expect from different versions, and should be carefully -/// chosen based on the product plan. -/// -/// The major version is also reflected in the package name of the -/// API, which must end in `v`, as in -/// `google.feature.v1`. For major versions 0 and 1, the suffix can -/// be omitted. Zero major versions must only be used for -/// experimental, none-GA apis. -@property(nonatomic, readwrite, copy, null_resettable) NSString *version; - -/// Source context for the protocol buffer service represented by this -/// message. -@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext; -/// Test to see if @c sourceContext has been set. -@property(nonatomic, readwrite) BOOL hasSourceContext; - -/// Included APIs. See [Mixin][]. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *mixinsArray; -/// The number of items in @c mixinsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger mixinsArray_Count; - -/// The source syntax of the service. -@property(nonatomic, readwrite) enum GPBSyntax syntax; - -@end - -/// Fetches the raw value of a @c GPBApi's @c syntax property, even -/// if the value was not defined by the enum at the time the code was generated. -int32_t GPBApi_Syntax_RawValue(GPBApi *message); -/// Sets the raw value of an @c GPBApi's @c syntax property, allowing -/// it to be set to a value that was not defined by the enum at the time the code -/// was generated. -void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value); - -#pragma mark - GPBMethod - -typedef GPB_ENUM(GPBMethod_FieldNumber) { - GPBMethod_FieldNumber_Name = 1, - GPBMethod_FieldNumber_RequestTypeURL = 2, - GPBMethod_FieldNumber_RequestStreaming = 3, - GPBMethod_FieldNumber_ResponseTypeURL = 4, - GPBMethod_FieldNumber_ResponseStreaming = 5, - GPBMethod_FieldNumber_OptionsArray = 6, - GPBMethod_FieldNumber_Syntax = 7, -}; - -/// Method represents a method of an api. -@interface GPBMethod : GPBMessage - -/// The simple name of this method. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// A URL of the input message type. -@property(nonatomic, readwrite, copy, null_resettable) NSString *requestTypeURL; - -/// If true, the request is streamed. -@property(nonatomic, readwrite) BOOL requestStreaming; - -/// The URL of the output message type. -@property(nonatomic, readwrite, copy, null_resettable) NSString *responseTypeURL; - -/// If true, the response is streamed. -@property(nonatomic, readwrite) BOOL responseStreaming; - -/// Any metadata attached to the method. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; -/// The number of items in @c optionsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger optionsArray_Count; - -/// The source syntax of this method. -@property(nonatomic, readwrite) enum GPBSyntax syntax; - -@end - -/// Fetches the raw value of a @c GPBMethod's @c syntax property, even -/// if the value was not defined by the enum at the time the code was generated. -int32_t GPBMethod_Syntax_RawValue(GPBMethod *message); -/// Sets the raw value of an @c GPBMethod's @c syntax property, allowing -/// it to be set to a value that was not defined by the enum at the time the code -/// was generated. -void SetGPBMethod_Syntax_RawValue(GPBMethod *message, int32_t value); - -#pragma mark - GPBMixin - -typedef GPB_ENUM(GPBMixin_FieldNumber) { - GPBMixin_FieldNumber_Name = 1, - GPBMixin_FieldNumber_Root = 2, -}; - -/// Declares an API to be included in this API. The including API must -/// redeclare all the methods from the included API, but documentation -/// and options are inherited as follows: -/// -/// - If after comment and whitespace stripping, the documentation -/// string of the redeclared method is empty, it will be inherited -/// from the original method. -/// -/// - Each annotation belonging to the service config (http, -/// visibility) which is not set in the redeclared method will be -/// inherited. -/// -/// - If an http annotation is inherited, the path pattern will be -/// modified as follows. Any version prefix will be replaced by the -/// version of the including API plus the [root][] path if specified. -/// -/// Example of a simple mixin: -/// -/// package google.acl.v1; -/// service AccessControl { -/// // Get the underlying ACL object. -/// rpc GetAcl(GetAclRequest) returns (Acl) { -/// option (google.api.http).get = "/v1/{resource=**}:getAcl"; -/// } -/// } -/// -/// package google.storage.v2; -/// service Storage { -/// rpc GetAcl(GetAclRequest) returns (Acl); -/// -/// // Get a data record. -/// rpc GetData(GetDataRequest) returns (Data) { -/// option (google.api.http).get = "/v2/{resource=**}"; -/// } -/// } -/// -/// Example of a mixin configuration: -/// -/// apis: -/// - name: google.storage.v2.Storage -/// mixins: -/// - name: google.acl.v1.AccessControl -/// -/// The mixin construct implies that all methods in `AccessControl` are -/// also declared with same name and request/response types in -/// `Storage`. A documentation generator or annotation processor will -/// see the effective `Storage.GetAcl` method after inherting -/// documentation and annotations as follows: -/// -/// service Storage { -/// // Get the underlying ACL object. -/// rpc GetAcl(GetAclRequest) returns (Acl) { -/// option (google.api.http).get = "/v2/{resource=**}:getAcl"; -/// } -/// ... -/// } -/// -/// Note how the version in the path pattern changed from `v1` to `v2`. -/// -/// If the `root` field in the mixin is specified, it should be a -/// relative path under which inherited HTTP paths are placed. Example: -/// -/// apis: -/// - name: google.storage.v2.Storage -/// mixins: -/// - name: google.acl.v1.AccessControl -/// root: acls -/// -/// This implies the following inherited HTTP annotation: -/// -/// service Storage { -/// // Get the underlying ACL object. -/// rpc GetAcl(GetAclRequest) returns (Acl) { -/// option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; -/// } -/// ... -/// } -@interface GPBMixin : GPBMessage - -/// The fully qualified name of the API which is included. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// If non-empty specifies a path under which inherited HTTP paths -/// are rooted. -@property(nonatomic, readwrite, copy, null_resettable) NSString *root; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Api.pbobjc.m b/objectivec/google/google/protobuf/Api.pbobjc.m deleted file mode 100644 index 45a06e60..00000000 --- a/objectivec/google/google/protobuf/Api.pbobjc.m +++ /dev/null @@ -1,348 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/api.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Api.pbobjc.h" -#import "google/protobuf/SourceContext.pbobjc.h" -#import "google/protobuf/Type.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBApiRoot - -@implementation GPBApiRoot - -+ (GPBExtensionRegistry*)extensionRegistry { - // This is called by +initialize so there is no need to worry - // about thread safety and initialization of registry. - static GPBExtensionRegistry* registry = nil; - if (!registry) { - GPBDebugCheckRuntimeVersion(); - registry = [[GPBExtensionRegistry alloc] init]; - [registry addExtensions:[GPBSourceContextRoot extensionRegistry]]; - [registry addExtensions:[GPBTypeRoot extensionRegistry]]; - } - return registry; -} - -@end - -#pragma mark - GPBApiRoot_FileDescriptor - -static GPBFileDescriptor *GPBApiRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBApi - -@implementation GPBApi - -@dynamic name; -@dynamic methodsArray, methodsArray_Count; -@dynamic optionsArray, optionsArray_Count; -@dynamic version; -@dynamic hasSourceContext, sourceContext; -@dynamic mixinsArray, mixinsArray_Count; -@dynamic syntax; - -typedef struct GPBApi__storage_ { - uint32_t _has_storage_[1]; - GPBSyntax syntax; - NSString *name; - NSMutableArray *methodsArray; - NSMutableArray *optionsArray; - NSString *version; - GPBSourceContext *sourceContext; - NSMutableArray *mixinsArray; -} GPBApi__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBApi_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBApi__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "methodsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBMethod), - .number = GPBApi_FieldNumber_MethodsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBApi__storage_, methodsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .number = GPBApi_FieldNumber_OptionsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBApi__storage_, optionsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "version", - .dataTypeSpecific.className = NULL, - .number = GPBApi_FieldNumber_Version, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBApi__storage_, version), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "sourceContext", - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), - .number = GPBApi_FieldNumber_SourceContext, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GPBApi__storage_, sourceContext), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "mixinsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBMixin), - .number = GPBApi_FieldNumber_MixinsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBApi__storage_, mixinsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "syntax", - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .number = GPBApi_FieldNumber_Syntax, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GPBApi__storage_, syntax), - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBApi class] - rootClass:[GPBApiRoot class] - file:GPBApiRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBApi__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GPBApi_Syntax_RawValue(GPBApi *message) { - GPBDescriptor *descriptor = [GPBApi descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBApi_FieldNumber_Syntax]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGPBApi_Syntax_RawValue(GPBApi *message, int32_t value) { - GPBDescriptor *descriptor = [GPBApi descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBApi_FieldNumber_Syntax]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - GPBMethod - -@implementation GPBMethod - -@dynamic name; -@dynamic requestTypeURL; -@dynamic requestStreaming; -@dynamic responseTypeURL; -@dynamic responseStreaming; -@dynamic optionsArray, optionsArray_Count; -@dynamic syntax; - -typedef struct GPBMethod__storage_ { - uint32_t _has_storage_[1]; - GPBSyntax syntax; - NSString *name; - NSString *requestTypeURL; - NSString *responseTypeURL; - NSMutableArray *optionsArray; -} GPBMethod__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBMethod_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBMethod__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "requestTypeURL", - .dataTypeSpecific.className = NULL, - .number = GPBMethod_FieldNumber_RequestTypeURL, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBMethod__storage_, requestTypeURL), - .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, - .dataType = GPBDataTypeString, - }, - { - .name = "requestStreaming", - .dataTypeSpecific.className = NULL, - .number = GPBMethod_FieldNumber_RequestStreaming, - .hasIndex = 2, - .offset = 3, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - { - .name = "responseTypeURL", - .dataTypeSpecific.className = NULL, - .number = GPBMethod_FieldNumber_ResponseTypeURL, - .hasIndex = 4, - .offset = (uint32_t)offsetof(GPBMethod__storage_, responseTypeURL), - .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, - .dataType = GPBDataTypeString, - }, - { - .name = "responseStreaming", - .dataTypeSpecific.className = NULL, - .number = GPBMethod_FieldNumber_ResponseStreaming, - .hasIndex = 5, - .offset = 6, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - { - .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .number = GPBMethod_FieldNumber_OptionsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBMethod__storage_, optionsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "syntax", - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .number = GPBMethod_FieldNumber_Syntax, - .hasIndex = 7, - .offset = (uint32_t)offsetof(GPBMethod__storage_, syntax), - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBMethod class] - rootClass:[GPBApiRoot class] - file:GPBApiRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBMethod__storage_) - flags:0]; -#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - static const char *extraTextFormatInfo = - "\002\002\007\244\241!!\000\004\010\244\241!!\000"; - [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; -#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GPBMethod_Syntax_RawValue(GPBMethod *message) { - GPBDescriptor *descriptor = [GPBMethod descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBMethod_FieldNumber_Syntax]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGPBMethod_Syntax_RawValue(GPBMethod *message, int32_t value) { - GPBDescriptor *descriptor = [GPBMethod descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBMethod_FieldNumber_Syntax]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - GPBMixin - -@implementation GPBMixin - -@dynamic name; -@dynamic root; - -typedef struct GPBMixin__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - NSString *root; -} GPBMixin__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBMixin_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBMixin__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "root", - .dataTypeSpecific.className = NULL, - .number = GPBMixin_FieldNumber_Root, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBMixin__storage_, root), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBMixin class] - rootClass:[GPBApiRoot class] - file:GPBApiRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBMixin__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Duration.pbobjc.h b/objectivec/google/google/protobuf/Duration.pbobjc.h deleted file mode 100644 index 29888d6c..00000000 --- a/objectivec/google/google/protobuf/Duration.pbobjc.h +++ /dev/null @@ -1,101 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/duration.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBDurationRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBDurationRoot : GPBRootObject -@end - -#pragma mark - GPBDuration - -typedef GPB_ENUM(GPBDuration_FieldNumber) { - GPBDuration_FieldNumber_Seconds = 1, - GPBDuration_FieldNumber_Nanos = 2, -}; - -/// A Duration represents a signed, fixed-length span of time represented -/// as a count of seconds and fractions of seconds at nanosecond -/// resolution. It is independent of any calendar and concepts like "day" -/// or "month". It is related to Timestamp in that the difference between -/// two Timestamp values is a Duration and it can be added or subtracted -/// from a Timestamp. Range is approximately +-10,000 years. -/// -/// Example 1: Compute Duration from two Timestamps in pseudo code. -/// -/// Timestamp start = ...; -/// Timestamp end = ...; -/// Duration duration = ...; -/// -/// duration.seconds = end.seconds - start.seconds; -/// duration.nanos = end.nanos - start.nanos; -/// -/// if (duration.seconds < 0 && duration.nanos > 0) { -/// duration.seconds += 1; -/// duration.nanos -= 1000000000; -/// } else if (durations.seconds > 0 && duration.nanos < 0) { -/// duration.seconds -= 1; -/// duration.nanos += 1000000000; -/// } -/// -/// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -/// -/// Timestamp start = ...; -/// Duration duration = ...; -/// Timestamp end = ...; -/// -/// end.seconds = start.seconds + duration.seconds; -/// end.nanos = start.nanos + duration.nanos; -/// -/// if (end.nanos < 0) { -/// end.seconds -= 1; -/// end.nanos += 1000000000; -/// } else if (end.nanos >= 1000000000) { -/// end.seconds += 1; -/// end.nanos -= 1000000000; -/// } -@interface GPBDuration : GPBMessage - -/// Signed seconds of the span of time. Must be from -315,576,000,000 -/// to +315,576,000,000 inclusive. -@property(nonatomic, readwrite) int64_t seconds; - -/// Signed fractions of a second at nanosecond resolution of the span -/// of time. Durations less than one second are represented with a 0 -/// `seconds` field and a positive or negative `nanos` field. For durations -/// of one second or more, a non-zero value for the `nanos` field must be -/// of the same sign as the `seconds` field. Must be from -999,999,999 -/// to +999,999,999 inclusive. -@property(nonatomic, readwrite) int32_t nanos; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Duration.pbobjc.m b/objectivec/google/google/protobuf/Duration.pbobjc.m deleted file mode 100644 index 7dd6b64a..00000000 --- a/objectivec/google/google/protobuf/Duration.pbobjc.m +++ /dev/null @@ -1,88 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/duration.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Duration.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBDurationRoot - -@implementation GPBDurationRoot - -@end - -#pragma mark - GPBDurationRoot_FileDescriptor - -static GPBFileDescriptor *GPBDurationRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBDuration - -@implementation GPBDuration - -@dynamic seconds; -@dynamic nanos; - -typedef struct GPBDuration__storage_ { - uint32_t _has_storage_[1]; - int32_t nanos; - int64_t seconds; -} GPBDuration__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "seconds", - .dataTypeSpecific.className = NULL, - .number = GPBDuration_FieldNumber_Seconds, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBDuration__storage_, seconds), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt64, - }, - { - .name = "nanos", - .dataTypeSpecific.className = NULL, - .number = GPBDuration_FieldNumber_Nanos, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBDuration__storage_, nanos), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBDuration class] - rootClass:[GPBDurationRoot class] - file:GPBDurationRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBDuration__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Empty.pbobjc.h b/objectivec/google/google/protobuf/Empty.pbobjc.h deleted file mode 100644 index f33db017..00000000 --- a/objectivec/google/google/protobuf/Empty.pbobjc.h +++ /dev/null @@ -1,53 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/empty.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBEmptyRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBEmptyRoot : GPBRootObject -@end - -#pragma mark - GPBEmpty - -/// A generic empty message that you can re-use to avoid defining duplicated -/// empty messages in your APIs. A typical example is to use it as the request -/// or the response type of an API method. For instance: -/// -/// service Foo { -/// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); -/// } -/// -/// The JSON representation for `Empty` is empty JSON object `{}`. -@interface GPBEmpty : GPBMessage - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Empty.pbobjc.m b/objectivec/google/google/protobuf/Empty.pbobjc.m deleted file mode 100644 index 88753aaf..00000000 --- a/objectivec/google/google/protobuf/Empty.pbobjc.m +++ /dev/null @@ -1,64 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/empty.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Empty.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBEmptyRoot - -@implementation GPBEmptyRoot - -@end - -#pragma mark - GPBEmptyRoot_FileDescriptor - -static GPBFileDescriptor *GPBEmptyRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBEmpty - -@implementation GPBEmpty - - -typedef struct GPBEmpty__storage_ { - uint32_t _has_storage_[1]; -} GPBEmpty__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBEmpty class] - rootClass:[GPBEmptyRoot class] - file:GPBEmptyRoot_FileDescriptor() - fields:NULL - fieldCount:0 - storageSize:sizeof(GPBEmpty__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/google/protobuf/FieldMask.pbobjc.h deleted file mode 100644 index 73cbd8a5..00000000 --- a/objectivec/google/google/protobuf/FieldMask.pbobjc.h +++ /dev/null @@ -1,202 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/field_mask.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBFieldMaskRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBFieldMaskRoot : GPBRootObject -@end - -#pragma mark - GPBFieldMask - -typedef GPB_ENUM(GPBFieldMask_FieldNumber) { - GPBFieldMask_FieldNumber_PathsArray = 1, -}; - -/// `FieldMask` represents a set of symbolic field paths, for example: -/// -/// paths: "f.a" -/// paths: "f.b.d" -/// -/// Here `f` represents a field in some root message, `a` and `b` -/// fields in the message found in `f`, and `d` a field found in the -/// message in `f.b`. -/// -/// Field masks are used to specify a subset of fields that should be -/// returned by a get operation or modified by an update operation. -/// Field masks also have a custom JSON encoding (see below). -/// -/// # Field Masks in Projections -/// -/// When used in the context of a projection, a response message or -/// sub-message is filtered by the API to only contain those fields as -/// specified in the mask. For example, if the mask in the previous -/// example is applied to a response message as follows: -/// -/// f { -/// a : 22 -/// b { -/// d : 1 -/// x : 2 -/// } -/// y : 13 -/// } -/// z: 8 -/// -/// The result will not contain specific values for fields x,y and z -/// (their value will be set to the default, and omitted in proto text -/// output): -/// -/// -/// f { -/// a : 22 -/// b { -/// d : 1 -/// } -/// } -/// -/// A repeated field is not allowed except at the last position of a -/// field mask. -/// -/// If a FieldMask object is not present in a get operation, the -/// operation applies to all fields (as if a FieldMask of all fields -/// had been specified). -/// -/// Note that a field mask does not necessarily apply to the -/// top-level response message. In case of a REST get operation, the -/// field mask applies directly to the response, but in case of a REST -/// list operation, the mask instead applies to each individual message -/// in the returned resource list. In case of a REST custom method, -/// other definitions may be used. Where the mask applies will be -/// clearly documented together with its declaration in the API. In -/// any case, the effect on the returned resource/resources is required -/// behavior for APIs. -/// -/// # Field Masks in Update Operations -/// -/// A field mask in update operations specifies which fields of the -/// targeted resource are going to be updated. The API is required -/// to only change the values of the fields as specified in the mask -/// and leave the others untouched. If a resource is passed in to -/// describe the updated values, the API ignores the values of all -/// fields not covered by the mask. -/// -/// In order to reset a field's value to the default, the field must -/// be in the mask and set to the default value in the provided resource. -/// Hence, in order to reset all fields of a resource, provide a default -/// instance of the resource and set all fields in the mask, or do -/// not provide a mask as described below. -/// -/// If a field mask is not present on update, the operation applies to -/// all fields (as if a field mask of all fields has been specified). -/// Note that in the presence of schema evolution, this may mean that -/// fields the client does not know and has therefore not filled into -/// the request will be reset to their default. If this is unwanted -/// behavior, a specific service may require a client to always specify -/// a field mask, producing an error if not. -/// -/// As with get operations, the location of the resource which -/// describes the updated values in the request message depends on the -/// operation kind. In any case, the effect of the field mask is -/// required to be honored by the API. -/// -/// ## Considerations for HTTP REST -/// -/// The HTTP kind of an update operation which uses a field mask must -/// be set to PATCH instead of PUT in order to satisfy HTTP semantics -/// (PUT must only be used for full updates). -/// -/// # JSON Encoding of Field Masks -/// -/// In JSON, a field mask is encoded as a single string where paths are -/// separated by a comma. Fields name in each path are converted -/// to/from lower-camel naming conventions. -/// -/// As an example, consider the following message declarations: -/// -/// message Profile { -/// User user = 1; -/// Photo photo = 2; -/// } -/// message User { -/// string display_name = 1; -/// string address = 2; -/// } -/// -/// In proto a field mask for `Profile` may look as such: -/// -/// mask { -/// paths: "user.display_name" -/// paths: "photo" -/// } -/// -/// In JSON, the same mask is represented as below: -/// -/// { -/// mask: "user.displayName,photo" -/// } -/// -/// # Field Masks and Oneof Fields -/// -/// Field masks treat fields in oneofs just as regular fields. Consider the -/// following message: -/// -/// message SampleMessage { -/// oneof test_oneof { -/// string name = 4; -/// SubMessage sub_message = 9; -/// } -/// } -/// -/// The field mask can be: -/// -/// mask { -/// paths: "name" -/// } -/// -/// Or: -/// -/// mask { -/// paths: "sub_message" -/// } -/// -/// Note that oneof type names ("test_oneof" in this case) cannot be used in -/// paths. -@interface GPBFieldMask : GPBMessage - -/// The set of field mask paths. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *pathsArray; -/// The number of items in @c pathsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger pathsArray_Count; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/FieldMask.pbobjc.m b/objectivec/google/google/protobuf/FieldMask.pbobjc.m deleted file mode 100644 index 8c241afc..00000000 --- a/objectivec/google/google/protobuf/FieldMask.pbobjc.m +++ /dev/null @@ -1,77 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/field_mask.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/FieldMask.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBFieldMaskRoot - -@implementation GPBFieldMaskRoot - -@end - -#pragma mark - GPBFieldMaskRoot_FileDescriptor - -static GPBFileDescriptor *GPBFieldMaskRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBFieldMask - -@implementation GPBFieldMask - -@dynamic pathsArray, pathsArray_Count; - -typedef struct GPBFieldMask__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *pathsArray; -} GPBFieldMask__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "pathsArray", - .dataTypeSpecific.className = NULL, - .number = GPBFieldMask_FieldNumber_PathsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBFieldMask__storage_, pathsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBFieldMask class] - rootClass:[GPBFieldMaskRoot class] - file:GPBFieldMaskRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBFieldMask__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/SourceContext.pbobjc.h b/objectivec/google/google/protobuf/SourceContext.pbobjc.h deleted file mode 100644 index 8775348e..00000000 --- a/objectivec/google/google/protobuf/SourceContext.pbobjc.h +++ /dev/null @@ -1,54 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/source_context.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBSourceContextRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBSourceContextRoot : GPBRootObject -@end - -#pragma mark - GPBSourceContext - -typedef GPB_ENUM(GPBSourceContext_FieldNumber) { - GPBSourceContext_FieldNumber_FileName = 1, -}; - -/// `SourceContext` represents information about the source of a -/// protobuf element, like the file in which it is defined. -@interface GPBSourceContext : GPBMessage - -/// The path-qualified name of the .proto file that contained the associated -/// protobuf element. For example: `"google/protobuf/source.proto"`. -@property(nonatomic, readwrite, copy, null_resettable) NSString *fileName; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/SourceContext.pbobjc.m b/objectivec/google/google/protobuf/SourceContext.pbobjc.m deleted file mode 100644 index 95007126..00000000 --- a/objectivec/google/google/protobuf/SourceContext.pbobjc.m +++ /dev/null @@ -1,77 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/source_context.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/SourceContext.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBSourceContextRoot - -@implementation GPBSourceContextRoot - -@end - -#pragma mark - GPBSourceContextRoot_FileDescriptor - -static GPBFileDescriptor *GPBSourceContextRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBSourceContext - -@implementation GPBSourceContext - -@dynamic fileName; - -typedef struct GPBSourceContext__storage_ { - uint32_t _has_storage_[1]; - NSString *fileName; -} GPBSourceContext__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fileName", - .dataTypeSpecific.className = NULL, - .number = GPBSourceContext_FieldNumber_FileName, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBSourceContext__storage_, fileName), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBSourceContext class] - rootClass:[GPBSourceContextRoot class] - file:GPBSourceContextRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBSourceContext__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Struct.pbobjc.h b/objectivec/google/google/protobuf/Struct.pbobjc.h deleted file mode 100644 index 3924b4b7..00000000 --- a/objectivec/google/google/protobuf/Struct.pbobjc.h +++ /dev/null @@ -1,167 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/struct.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GPBListValue; -@class GPBStruct; -@class GPBValue; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Enum GPBNullValue - -/// `NullValue` is a singleton enumeration to represent the null value for the -/// `Value` type union. -/// -/// The JSON representation for `NullValue` is JSON `null`. -typedef GPB_ENUM(GPBNullValue) { - /// Value used if any message's field encounters a value that is not defined - /// by this enum. The message will also have C functions to get/set the rawValue - /// of the field. - GPBNullValue_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /// Null value. - GPBNullValue_NullValue = 0, -}; - -GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBNullValue_IsValidValue(int32_t value); - -#pragma mark - GPBStructRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBStructRoot : GPBRootObject -@end - -#pragma mark - GPBStruct - -typedef GPB_ENUM(GPBStruct_FieldNumber) { - GPBStruct_FieldNumber_Fields = 1, -}; - -/// `Struct` represents a structured data value, consisting of fields -/// which map to dynamically typed values. In some languages, `Struct` -/// might be supported by a native representation. For example, in -/// scripting languages like JS a struct is represented as an -/// object. The details of that representation are described together -/// with the proto support for the language. -/// -/// The JSON representation for `Struct` is JSON object. -@interface GPBStruct : GPBMessage - -/// Unordered map of dynamically typed values. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *fields; -/// The number of items in @c fields without causing the array to be created. -@property(nonatomic, readonly) NSUInteger fields_Count; - -@end - -#pragma mark - GPBValue - -typedef GPB_ENUM(GPBValue_FieldNumber) { - GPBValue_FieldNumber_NullValue = 1, - GPBValue_FieldNumber_NumberValue = 2, - GPBValue_FieldNumber_StringValue = 3, - GPBValue_FieldNumber_BoolValue = 4, - GPBValue_FieldNumber_StructValue = 5, - GPBValue_FieldNumber_ListValue = 6, -}; - -typedef GPB_ENUM(GPBValue_Kind_OneOfCase) { - GPBValue_Kind_OneOfCase_GPBUnsetOneOfCase = 0, - GPBValue_Kind_OneOfCase_NullValue = 1, - GPBValue_Kind_OneOfCase_NumberValue = 2, - GPBValue_Kind_OneOfCase_StringValue = 3, - GPBValue_Kind_OneOfCase_BoolValue = 4, - GPBValue_Kind_OneOfCase_StructValue = 5, - GPBValue_Kind_OneOfCase_ListValue = 6, -}; - -/// `Value` represents a dynamically typed value which can be either -/// null, a number, a string, a boolean, a recursive struct value, or a -/// list of values. A producer of value is expected to set one of that -/// variants, absence of any variant indicates an error. -/// -/// The JSON representation for `Value` is JSON value. -@interface GPBValue : GPBMessage - -/// The kind of value. -@property(nonatomic, readonly) GPBValue_Kind_OneOfCase kindOneOfCase; - -/// Represents a null value. -@property(nonatomic, readwrite) GPBNullValue nullValue; - -/// Represents a double value. -@property(nonatomic, readwrite) double numberValue; - -/// Represents a string value. -@property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue; - -/// Represents a boolean value. -@property(nonatomic, readwrite) BOOL boolValue; - -/// Represents a structured value. -@property(nonatomic, readwrite, strong, null_resettable) GPBStruct *structValue; - -/// Represents a repeated `Value`. -@property(nonatomic, readwrite, strong, null_resettable) GPBListValue *listValue; - -@end - -/// Fetches the raw value of a @c GPBValue's @c nullValue property, even -/// if the value was not defined by the enum at the time the code was generated. -int32_t GPBValue_NullValue_RawValue(GPBValue *message); -/// Sets the raw value of an @c GPBValue's @c nullValue property, allowing -/// it to be set to a value that was not defined by the enum at the time the code -/// was generated. -void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value); - -/// Clears whatever value was set for the oneof 'kind'. -void GPBValue_ClearKindOneOfCase(GPBValue *message); - -#pragma mark - GPBListValue - -typedef GPB_ENUM(GPBListValue_FieldNumber) { - GPBListValue_FieldNumber_ValuesArray = 1, -}; - -/// `ListValue` is a wrapper around a repeated field of values. -/// -/// The JSON representation for `ListValue` is JSON array. -@interface GPBListValue : GPBMessage - -/// Repeated field of dynamically typed values. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *valuesArray; -/// The number of items in @c valuesArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger valuesArray_Count; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Struct.pbobjc.m b/objectivec/google/google/protobuf/Struct.pbobjc.m deleted file mode 100644 index 60940027..00000000 --- a/objectivec/google/google/protobuf/Struct.pbobjc.m +++ /dev/null @@ -1,273 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/struct.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Struct.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBStructRoot - -@implementation GPBStructRoot - -@end - -#pragma mark - GPBStructRoot_FileDescriptor - -static GPBFileDescriptor *GPBStructRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - Enum GPBNullValue - -GPBEnumDescriptor *GPBNullValue_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "NullValue\000"; - static const int32_t values[] = { - GPBNullValue_NullValue, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBNullValue) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GPBNullValue_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GPBNullValue_IsValidValue(int32_t value__) { - switch (value__) { - case GPBNullValue_NullValue: - return YES; - default: - return NO; - } -} - -#pragma mark - GPBStruct - -@implementation GPBStruct - -@dynamic fields, fields_Count; - -typedef struct GPBStruct__storage_ { - uint32_t _has_storage_[1]; - NSMutableDictionary *fields; -} GPBStruct__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "fields", - .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), - .number = GPBStruct_FieldNumber_Fields, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBStruct__storage_, fields), - .flags = GPBFieldMapKeyString, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBStruct class] - rootClass:[GPBStructRoot class] - file:GPBStructRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBStruct__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBValue - -@implementation GPBValue - -@dynamic kindOneOfCase; -@dynamic nullValue; -@dynamic numberValue; -@dynamic stringValue; -@dynamic boolValue; -@dynamic structValue; -@dynamic listValue; - -typedef struct GPBValue__storage_ { - uint32_t _has_storage_[2]; - GPBNullValue nullValue; - NSString *stringValue; - GPBStruct *structValue; - GPBListValue *listValue; - double numberValue; -} GPBValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "nullValue", - .dataTypeSpecific.enumDescFunc = GPBNullValue_EnumDescriptor, - .number = GPBValue_FieldNumber_NullValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GPBValue__storage_, nullValue), - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - }, - { - .name = "numberValue", - .dataTypeSpecific.className = NULL, - .number = GPBValue_FieldNumber_NumberValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GPBValue__storage_, numberValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeDouble, - }, - { - .name = "stringValue", - .dataTypeSpecific.className = NULL, - .number = GPBValue_FieldNumber_StringValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GPBValue__storage_, stringValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "boolValue", - .dataTypeSpecific.className = NULL, - .number = GPBValue_FieldNumber_BoolValue, - .hasIndex = -1, - .offset = 0, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - { - .name = "structValue", - .dataTypeSpecific.className = GPBStringifySymbol(GPBStruct), - .number = GPBValue_FieldNumber_StructValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GPBValue__storage_, structValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "listValue", - .dataTypeSpecific.className = GPBStringifySymbol(GPBListValue), - .number = GPBValue_FieldNumber_ListValue, - .hasIndex = -1, - .offset = (uint32_t)offsetof(GPBValue__storage_, listValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBValue class] - rootClass:[GPBStructRoot class] - file:GPBStructRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBValue__storage_) - flags:0]; - static const char *oneofs[] = { - "kind", - }; - [localDescriptor setupOneofs:oneofs - count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) - firstHasIndex:-1]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GPBValue_NullValue_RawValue(GPBValue *message) { - GPBDescriptor *descriptor = [GPBValue descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGPBValue_NullValue_RawValue(GPBValue *message, int32_t value) { - GPBDescriptor *descriptor = [GPBValue descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBValue_FieldNumber_NullValue]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -void GPBValue_ClearKindOneOfCase(GPBValue *message) { - GPBDescriptor *descriptor = [message descriptor]; - GPBOneofDescriptor *oneof = descriptor->oneofs_[0]; - GPBMaybeClearOneof(message, oneof, -1, 0); -} -#pragma mark - GPBListValue - -@implementation GPBListValue - -@dynamic valuesArray, valuesArray_Count; - -typedef struct GPBListValue__storage_ { - uint32_t _has_storage_[1]; - NSMutableArray *valuesArray; -} GPBListValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "valuesArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBValue), - .number = GPBListValue_FieldNumber_ValuesArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBListValue__storage_, valuesArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBListValue class] - rootClass:[GPBStructRoot class] - file:GPBStructRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBListValue__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Timestamp.pbobjc.h b/objectivec/google/google/protobuf/Timestamp.pbobjc.h deleted file mode 100644 index 925dca84..00000000 --- a/objectivec/google/google/protobuf/Timestamp.pbobjc.h +++ /dev/null @@ -1,113 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/timestamp.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBTimestampRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBTimestampRoot : GPBRootObject -@end - -#pragma mark - GPBTimestamp - -typedef GPB_ENUM(GPBTimestamp_FieldNumber) { - GPBTimestamp_FieldNumber_Seconds = 1, - GPBTimestamp_FieldNumber_Nanos = 2, -}; - -/// A Timestamp represents a point in time independent of any time zone -/// or calendar, represented as seconds and fractions of seconds at -/// nanosecond resolution in UTC Epoch time. It is encoded using the -/// Proleptic Gregorian Calendar which extends the Gregorian calendar -/// backwards to year one. It is encoded assuming all minutes are 60 -/// seconds long, i.e. leap seconds are "smeared" so that no leap second -/// table is needed for interpretation. Range is from -/// 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. -/// By restricting to that range, we ensure that we can convert to -/// and from RFC 3339 date strings. -/// See [https://www.ietf.org/rfc/rfc3339.txt](https://www.ietf.org/rfc/rfc3339.txt). -/// -/// Example 1: Compute Timestamp from POSIX `time()`. -/// -/// Timestamp timestamp; -/// timestamp.set_seconds(time(NULL)); -/// timestamp.set_nanos(0); -/// -/// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -/// -/// struct timeval tv; -/// gettimeofday(&tv, NULL); -/// -/// Timestamp timestamp; -/// timestamp.set_seconds(tv.tv_sec); -/// timestamp.set_nanos(tv.tv_usec * 1000); -/// -/// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -/// -/// FILETIME ft; -/// GetSystemTimeAsFileTime(&ft); -/// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -/// -/// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -/// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -/// Timestamp timestamp; -/// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -/// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -/// -/// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -/// -/// long millis = System.currentTimeMillis(); -/// -/// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -/// .setNanos((int) ((millis % 1000) * 1000000)).build(); -/// -/// -/// Example 5: Compute Timestamp from current time in Python. -/// -/// now = time.time() -/// seconds = int(now) -/// nanos = int((now - seconds) * 10**9) -/// timestamp = Timestamp(seconds=seconds, nanos=nanos) -@interface GPBTimestamp : GPBMessage - -/// Represents seconds of UTC time since Unix epoch -/// 1970-01-01T00:00:00Z. Must be from from 0001-01-01T00:00:00Z to -/// 9999-12-31T23:59:59Z inclusive. -@property(nonatomic, readwrite) int64_t seconds; - -/// Non-negative fractions of a second at nanosecond resolution. Negative -/// second values with fractions must still have non-negative nanos values -/// that count forward in time. Must be from 0 to 999,999,999 -/// inclusive. -@property(nonatomic, readwrite) int32_t nanos; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Timestamp.pbobjc.m b/objectivec/google/google/protobuf/Timestamp.pbobjc.m deleted file mode 100644 index f35e435d..00000000 --- a/objectivec/google/google/protobuf/Timestamp.pbobjc.m +++ /dev/null @@ -1,88 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/timestamp.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Timestamp.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBTimestampRoot - -@implementation GPBTimestampRoot - -@end - -#pragma mark - GPBTimestampRoot_FileDescriptor - -static GPBFileDescriptor *GPBTimestampRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBTimestamp - -@implementation GPBTimestamp - -@dynamic seconds; -@dynamic nanos; - -typedef struct GPBTimestamp__storage_ { - uint32_t _has_storage_[1]; - int32_t nanos; - int64_t seconds; -} GPBTimestamp__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "seconds", - .dataTypeSpecific.className = NULL, - .number = GPBTimestamp_FieldNumber_Seconds, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBTimestamp__storage_, seconds), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt64, - }, - { - .name = "nanos", - .dataTypeSpecific.className = NULL, - .number = GPBTimestamp_FieldNumber_Nanos, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBTimestamp__storage_, nanos), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBTimestamp class] - rootClass:[GPBTimestampRoot class] - file:GPBTimestampRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBTimestamp__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Type.pbobjc.h b/objectivec/google/google/protobuf/Type.pbobjc.h deleted file mode 100644 index 590d970b..00000000 --- a/objectivec/google/google/protobuf/Type.pbobjc.h +++ /dev/null @@ -1,373 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/type.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -@class GPBAny; -@class GPBEnumValue; -@class GPBField; -@class GPBOption; -@class GPBSourceContext; - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - Enum GPBSyntax - -/// The syntax in which a protocol buffer element is defined. -typedef GPB_ENUM(GPBSyntax) { - /// Value used if any message's field encounters a value that is not defined - /// by this enum. The message will also have C functions to get/set the rawValue - /// of the field. - GPBSyntax_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /// Syntax `proto2`. - GPBSyntax_SyntaxProto2 = 0, - - /// Syntax `proto3`. - GPBSyntax_SyntaxProto3 = 1, -}; - -GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBSyntax_IsValidValue(int32_t value); - -#pragma mark - Enum GPBField_Kind - -/// Basic field types. -typedef GPB_ENUM(GPBField_Kind) { - /// Value used if any message's field encounters a value that is not defined - /// by this enum. The message will also have C functions to get/set the rawValue - /// of the field. - GPBField_Kind_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /// Field type unknown. - GPBField_Kind_TypeUnknown = 0, - - /// Field type double. - GPBField_Kind_TypeDouble = 1, - - /// Field type float. - GPBField_Kind_TypeFloat = 2, - - /// Field type int64. - GPBField_Kind_TypeInt64 = 3, - - /// Field type uint64. - GPBField_Kind_TypeUint64 = 4, - - /// Field type int32. - GPBField_Kind_TypeInt32 = 5, - - /// Field type fixed64. - GPBField_Kind_TypeFixed64 = 6, - - /// Field type fixed32. - GPBField_Kind_TypeFixed32 = 7, - - /// Field type bool. - GPBField_Kind_TypeBool = 8, - - /// Field type string. - GPBField_Kind_TypeString = 9, - - /// Field type group. Proto2 syntax only, and deprecated. - GPBField_Kind_TypeGroup = 10, - - /// Field type message. - GPBField_Kind_TypeMessage = 11, - - /// Field type bytes. - GPBField_Kind_TypeBytes = 12, - - /// Field type uint32. - GPBField_Kind_TypeUint32 = 13, - - /// Field type enum. - GPBField_Kind_TypeEnum = 14, - - /// Field type sfixed32. - GPBField_Kind_TypeSfixed32 = 15, - - /// Field type sfixed64. - GPBField_Kind_TypeSfixed64 = 16, - - /// Field type sint32. - GPBField_Kind_TypeSint32 = 17, - - /// Field type sint64. - GPBField_Kind_TypeSint64 = 18, -}; - -GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBField_Kind_IsValidValue(int32_t value); - -#pragma mark - Enum GPBField_Cardinality - -/// Whether a field is optional, required, or repeated. -typedef GPB_ENUM(GPBField_Cardinality) { - /// Value used if any message's field encounters a value that is not defined - /// by this enum. The message will also have C functions to get/set the rawValue - /// of the field. - GPBField_Cardinality_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, - /// For fields with unknown cardinality. - GPBField_Cardinality_CardinalityUnknown = 0, - - /// For optional fields. - GPBField_Cardinality_CardinalityOptional = 1, - - /// For required fields. Proto2 syntax only. - GPBField_Cardinality_CardinalityRequired = 2, - - /// For repeated fields. - GPBField_Cardinality_CardinalityRepeated = 3, -}; - -GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void); - -/// Checks to see if the given value is defined by the enum or was not known at -/// the time this source was generated. -BOOL GPBField_Cardinality_IsValidValue(int32_t value); - -#pragma mark - GPBTypeRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBTypeRoot : GPBRootObject -@end - -#pragma mark - GPBType - -typedef GPB_ENUM(GPBType_FieldNumber) { - GPBType_FieldNumber_Name = 1, - GPBType_FieldNumber_FieldsArray = 2, - GPBType_FieldNumber_OneofsArray = 3, - GPBType_FieldNumber_OptionsArray = 4, - GPBType_FieldNumber_SourceContext = 5, - GPBType_FieldNumber_Syntax = 6, -}; - -/// A protocol buffer message type. -@interface GPBType : GPBMessage - -/// The fully qualified message name. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// The list of fields. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *fieldsArray; -/// The number of items in @c fieldsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger fieldsArray_Count; - -/// The list of types appearing in `oneof` definitions in this type. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *oneofsArray; -/// The number of items in @c oneofsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger oneofsArray_Count; - -/// The protocol buffer options. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; -/// The number of items in @c optionsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger optionsArray_Count; - -/// The source context. -@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext; -/// Test to see if @c sourceContext has been set. -@property(nonatomic, readwrite) BOOL hasSourceContext; - -/// The source syntax. -@property(nonatomic, readwrite) GPBSyntax syntax; - -@end - -/// Fetches the raw value of a @c GPBType's @c syntax property, even -/// if the value was not defined by the enum at the time the code was generated. -int32_t GPBType_Syntax_RawValue(GPBType *message); -/// Sets the raw value of an @c GPBType's @c syntax property, allowing -/// it to be set to a value that was not defined by the enum at the time the code -/// was generated. -void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value); - -#pragma mark - GPBField - -typedef GPB_ENUM(GPBField_FieldNumber) { - GPBField_FieldNumber_Kind = 1, - GPBField_FieldNumber_Cardinality = 2, - GPBField_FieldNumber_Number = 3, - GPBField_FieldNumber_Name = 4, - GPBField_FieldNumber_TypeURL = 6, - GPBField_FieldNumber_OneofIndex = 7, - GPBField_FieldNumber_Packed = 8, - GPBField_FieldNumber_OptionsArray = 9, - GPBField_FieldNumber_JsonName = 10, - GPBField_FieldNumber_DefaultValue = 11, -}; - -/// A single field of a message type. -@interface GPBField : GPBMessage - -/// The field type. -@property(nonatomic, readwrite) GPBField_Kind kind; - -/// The field cardinality. -@property(nonatomic, readwrite) GPBField_Cardinality cardinality; - -/// The field number. -@property(nonatomic, readwrite) int32_t number; - -/// The field name. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// The field type URL, without the scheme, for message or enumeration -/// types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. -@property(nonatomic, readwrite, copy, null_resettable) NSString *typeURL; - -/// The index of the field type in `Type.oneofs`, for message or enumeration -/// types. The first type has index 1; zero means the type is not in the list. -@property(nonatomic, readwrite) int32_t oneofIndex; - -/// Whether to use alternative packed wire representation. -@property(nonatomic, readwrite) BOOL packed; - -/// The protocol buffer options. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; -/// The number of items in @c optionsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger optionsArray_Count; - -/// The field JSON name. -@property(nonatomic, readwrite, copy, null_resettable) NSString *jsonName; - -/// The string value of the default value of this field. Proto2 syntax only. -@property(nonatomic, readwrite, copy, null_resettable) NSString *defaultValue; - -@end - -/// Fetches the raw value of a @c GPBField's @c kind property, even -/// if the value was not defined by the enum at the time the code was generated. -int32_t GPBField_Kind_RawValue(GPBField *message); -/// Sets the raw value of an @c GPBField's @c kind property, allowing -/// it to be set to a value that was not defined by the enum at the time the code -/// was generated. -void SetGPBField_Kind_RawValue(GPBField *message, int32_t value); - -/// Fetches the raw value of a @c GPBField's @c cardinality property, even -/// if the value was not defined by the enum at the time the code was generated. -int32_t GPBField_Cardinality_RawValue(GPBField *message); -/// Sets the raw value of an @c GPBField's @c cardinality property, allowing -/// it to be set to a value that was not defined by the enum at the time the code -/// was generated. -void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value); - -#pragma mark - GPBEnum - -typedef GPB_ENUM(GPBEnum_FieldNumber) { - GPBEnum_FieldNumber_Name = 1, - GPBEnum_FieldNumber_EnumvalueArray = 2, - GPBEnum_FieldNumber_OptionsArray = 3, - GPBEnum_FieldNumber_SourceContext = 4, - GPBEnum_FieldNumber_Syntax = 5, -}; - -/// Enum type definition. -@interface GPBEnum : GPBMessage - -/// Enum type name. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// Enum value definitions. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *enumvalueArray; -/// The number of items in @c enumvalueArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger enumvalueArray_Count; - -/// Protocol buffer options. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; -/// The number of items in @c optionsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger optionsArray_Count; - -/// The source context. -@property(nonatomic, readwrite, strong, null_resettable) GPBSourceContext *sourceContext; -/// Test to see if @c sourceContext has been set. -@property(nonatomic, readwrite) BOOL hasSourceContext; - -/// The source syntax. -@property(nonatomic, readwrite) GPBSyntax syntax; - -@end - -/// Fetches the raw value of a @c GPBEnum's @c syntax property, even -/// if the value was not defined by the enum at the time the code was generated. -int32_t GPBEnum_Syntax_RawValue(GPBEnum *message); -/// Sets the raw value of an @c GPBEnum's @c syntax property, allowing -/// it to be set to a value that was not defined by the enum at the time the code -/// was generated. -void SetGPBEnum_Syntax_RawValue(GPBEnum *message, int32_t value); - -#pragma mark - GPBEnumValue - -typedef GPB_ENUM(GPBEnumValue_FieldNumber) { - GPBEnumValue_FieldNumber_Name = 1, - GPBEnumValue_FieldNumber_Number = 2, - GPBEnumValue_FieldNumber_OptionsArray = 3, -}; - -/// Enum value definition. -@interface GPBEnumValue : GPBMessage - -/// Enum value name. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// Enum value number. -@property(nonatomic, readwrite) int32_t number; - -/// Protocol buffer options. -@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *optionsArray; -/// The number of items in @c optionsArray without causing the array to be created. -@property(nonatomic, readonly) NSUInteger optionsArray_Count; - -@end - -#pragma mark - GPBOption - -typedef GPB_ENUM(GPBOption_FieldNumber) { - GPBOption_FieldNumber_Name = 1, - GPBOption_FieldNumber_Value = 2, -}; - -/// A protocol buffer option, which can be attached to a message, field, -/// enumeration, etc. -@interface GPBOption : GPBMessage - -/// The option's name. For example, `"java_package"`. -@property(nonatomic, readwrite, copy, null_resettable) NSString *name; - -/// The option's value. For example, `"com.google.protobuf"`. -@property(nonatomic, readwrite, strong, null_resettable) GPBAny *value; -/// Test to see if @c value has been set. -@property(nonatomic, readwrite) BOOL hasValue; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Type.pbobjc.m b/objectivec/google/google/protobuf/Type.pbobjc.m deleted file mode 100644 index 5554a222..00000000 --- a/objectivec/google/google/protobuf/Type.pbobjc.m +++ /dev/null @@ -1,693 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/type.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Type.pbobjc.h" -#import "google/protobuf/Any.pbobjc.h" -#import "google/protobuf/SourceContext.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBTypeRoot - -@implementation GPBTypeRoot - -+ (GPBExtensionRegistry*)extensionRegistry { - // This is called by +initialize so there is no need to worry - // about thread safety and initialization of registry. - static GPBExtensionRegistry* registry = nil; - if (!registry) { - GPBDebugCheckRuntimeVersion(); - registry = [[GPBExtensionRegistry alloc] init]; - [registry addExtensions:[GPBAnyRoot extensionRegistry]]; - [registry addExtensions:[GPBSourceContextRoot extensionRegistry]]; - } - return registry; -} - -@end - -#pragma mark - GPBTypeRoot_FileDescriptor - -static GPBFileDescriptor *GPBTypeRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - Enum GPBSyntax - -GPBEnumDescriptor *GPBSyntax_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "SyntaxProto2\000SyntaxProto3\000"; - static const int32_t values[] = { - GPBSyntax_SyntaxProto2, - GPBSyntax_SyntaxProto3, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBSyntax) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GPBSyntax_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GPBSyntax_IsValidValue(int32_t value__) { - switch (value__) { - case GPBSyntax_SyntaxProto2: - case GPBSyntax_SyntaxProto3: - return YES; - default: - return NO; - } -} - -#pragma mark - GPBType - -@implementation GPBType - -@dynamic name; -@dynamic fieldsArray, fieldsArray_Count; -@dynamic oneofsArray, oneofsArray_Count; -@dynamic optionsArray, optionsArray_Count; -@dynamic hasSourceContext, sourceContext; -@dynamic syntax; - -typedef struct GPBType__storage_ { - uint32_t _has_storage_[1]; - GPBSyntax syntax; - NSString *name; - NSMutableArray *fieldsArray; - NSMutableArray *oneofsArray; - NSMutableArray *optionsArray; - GPBSourceContext *sourceContext; -} GPBType__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBType_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBType__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "fieldsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBField), - .number = GPBType_FieldNumber_FieldsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBType__storage_, fieldsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "oneofsArray", - .dataTypeSpecific.className = NULL, - .number = GPBType_FieldNumber_OneofsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBType__storage_, oneofsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeString, - }, - { - .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .number = GPBType_FieldNumber_OptionsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBType__storage_, optionsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "sourceContext", - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), - .number = GPBType_FieldNumber_SourceContext, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBType__storage_, sourceContext), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "syntax", - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .number = GPBType_FieldNumber_Syntax, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GPBType__storage_, syntax), - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBType class] - rootClass:[GPBTypeRoot class] - file:GPBTypeRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBType__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GPBType_Syntax_RawValue(GPBType *message) { - GPBDescriptor *descriptor = [GPBType descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBType_FieldNumber_Syntax]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGPBType_Syntax_RawValue(GPBType *message, int32_t value) { - GPBDescriptor *descriptor = [GPBType descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBType_FieldNumber_Syntax]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - GPBField - -@implementation GPBField - -@dynamic kind; -@dynamic cardinality; -@dynamic number; -@dynamic name; -@dynamic typeURL; -@dynamic oneofIndex; -@dynamic packed; -@dynamic optionsArray, optionsArray_Count; -@dynamic jsonName; -@dynamic defaultValue; - -typedef struct GPBField__storage_ { - uint32_t _has_storage_[1]; - GPBField_Kind kind; - GPBField_Cardinality cardinality; - int32_t number; - int32_t oneofIndex; - NSString *name; - NSString *typeURL; - NSMutableArray *optionsArray; - NSString *jsonName; - NSString *defaultValue; -} GPBField__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "kind", - .dataTypeSpecific.enumDescFunc = GPBField_Kind_EnumDescriptor, - .number = GPBField_FieldNumber_Kind, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBField__storage_, kind), - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - }, - { - .name = "cardinality", - .dataTypeSpecific.enumDescFunc = GPBField_Cardinality_EnumDescriptor, - .number = GPBField_FieldNumber_Cardinality, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBField__storage_, cardinality), - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - }, - { - .name = "number", - .dataTypeSpecific.className = NULL, - .number = GPBField_FieldNumber_Number, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GPBField__storage_, number), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBField_FieldNumber_Name, - .hasIndex = 3, - .offset = (uint32_t)offsetof(GPBField__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "typeURL", - .dataTypeSpecific.className = NULL, - .number = GPBField_FieldNumber_TypeURL, - .hasIndex = 4, - .offset = (uint32_t)offsetof(GPBField__storage_, typeURL), - .flags = GPBFieldOptional | GPBFieldTextFormatNameCustom, - .dataType = GPBDataTypeString, - }, - { - .name = "oneofIndex", - .dataTypeSpecific.className = NULL, - .number = GPBField_FieldNumber_OneofIndex, - .hasIndex = 5, - .offset = (uint32_t)offsetof(GPBField__storage_, oneofIndex), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "packed", - .dataTypeSpecific.className = NULL, - .number = GPBField_FieldNumber_Packed, - .hasIndex = 6, - .offset = 7, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - { - .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .number = GPBField_FieldNumber_OptionsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBField__storage_, optionsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "jsonName", - .dataTypeSpecific.className = NULL, - .number = GPBField_FieldNumber_JsonName, - .hasIndex = 8, - .offset = (uint32_t)offsetof(GPBField__storage_, jsonName), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "defaultValue", - .dataTypeSpecific.className = NULL, - .number = GPBField_FieldNumber_DefaultValue, - .hasIndex = 9, - .offset = (uint32_t)offsetof(GPBField__storage_, defaultValue), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBField class] - rootClass:[GPBTypeRoot class] - file:GPBTypeRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBField__storage_) - flags:0]; -#if !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - static const char *extraTextFormatInfo = - "\001\006\004\241!!\000"; - [localDescriptor setupExtraTextInfo:extraTextFormatInfo]; -#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GPBField_Kind_RawValue(GPBField *message) { - GPBDescriptor *descriptor = [GPBField descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGPBField_Kind_RawValue(GPBField *message, int32_t value) { - GPBDescriptor *descriptor = [GPBField descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Kind]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -int32_t GPBField_Cardinality_RawValue(GPBField *message) { - GPBDescriptor *descriptor = [GPBField descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGPBField_Cardinality_RawValue(GPBField *message, int32_t value) { - GPBDescriptor *descriptor = [GPBField descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBField_FieldNumber_Cardinality]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - Enum GPBField_Kind - -GPBEnumDescriptor *GPBField_Kind_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "TypeUnknown\000TypeDouble\000TypeFloat\000TypeInt" - "64\000TypeUint64\000TypeInt32\000TypeFixed64\000Type" - "Fixed32\000TypeBool\000TypeString\000TypeGroup\000Ty" - "peMessage\000TypeBytes\000TypeUint32\000TypeEnum\000" - "TypeSfixed32\000TypeSfixed64\000TypeSint32\000Typ" - "eSint64\000"; - static const int32_t values[] = { - GPBField_Kind_TypeUnknown, - GPBField_Kind_TypeDouble, - GPBField_Kind_TypeFloat, - GPBField_Kind_TypeInt64, - GPBField_Kind_TypeUint64, - GPBField_Kind_TypeInt32, - GPBField_Kind_TypeFixed64, - GPBField_Kind_TypeFixed32, - GPBField_Kind_TypeBool, - GPBField_Kind_TypeString, - GPBField_Kind_TypeGroup, - GPBField_Kind_TypeMessage, - GPBField_Kind_TypeBytes, - GPBField_Kind_TypeUint32, - GPBField_Kind_TypeEnum, - GPBField_Kind_TypeSfixed32, - GPBField_Kind_TypeSfixed64, - GPBField_Kind_TypeSint32, - GPBField_Kind_TypeSint64, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Kind) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GPBField_Kind_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GPBField_Kind_IsValidValue(int32_t value__) { - switch (value__) { - case GPBField_Kind_TypeUnknown: - case GPBField_Kind_TypeDouble: - case GPBField_Kind_TypeFloat: - case GPBField_Kind_TypeInt64: - case GPBField_Kind_TypeUint64: - case GPBField_Kind_TypeInt32: - case GPBField_Kind_TypeFixed64: - case GPBField_Kind_TypeFixed32: - case GPBField_Kind_TypeBool: - case GPBField_Kind_TypeString: - case GPBField_Kind_TypeGroup: - case GPBField_Kind_TypeMessage: - case GPBField_Kind_TypeBytes: - case GPBField_Kind_TypeUint32: - case GPBField_Kind_TypeEnum: - case GPBField_Kind_TypeSfixed32: - case GPBField_Kind_TypeSfixed64: - case GPBField_Kind_TypeSint32: - case GPBField_Kind_TypeSint64: - return YES; - default: - return NO; - } -} - -#pragma mark - Enum GPBField_Cardinality - -GPBEnumDescriptor *GPBField_Cardinality_EnumDescriptor(void) { - static GPBEnumDescriptor *descriptor = NULL; - if (!descriptor) { - static const char *valueNames = - "CardinalityUnknown\000CardinalityOptional\000C" - "ardinalityRequired\000CardinalityRepeated\000"; - static const int32_t values[] = { - GPBField_Cardinality_CardinalityUnknown, - GPBField_Cardinality_CardinalityOptional, - GPBField_Cardinality_CardinalityRequired, - GPBField_Cardinality_CardinalityRepeated, - }; - GPBEnumDescriptor *worker = - [GPBEnumDescriptor allocDescriptorForName:GPBNSStringifySymbol(GPBField_Cardinality) - valueNames:valueNames - values:values - count:(uint32_t)(sizeof(values) / sizeof(int32_t)) - enumVerifier:GPBField_Cardinality_IsValidValue]; - if (!OSAtomicCompareAndSwapPtrBarrier(nil, worker, (void * volatile *)&descriptor)) { - [worker release]; - } - } - return descriptor; -} - -BOOL GPBField_Cardinality_IsValidValue(int32_t value__) { - switch (value__) { - case GPBField_Cardinality_CardinalityUnknown: - case GPBField_Cardinality_CardinalityOptional: - case GPBField_Cardinality_CardinalityRequired: - case GPBField_Cardinality_CardinalityRepeated: - return YES; - default: - return NO; - } -} - -#pragma mark - GPBEnum - -@implementation GPBEnum - -@dynamic name; -@dynamic enumvalueArray, enumvalueArray_Count; -@dynamic optionsArray, optionsArray_Count; -@dynamic hasSourceContext, sourceContext; -@dynamic syntax; - -typedef struct GPBEnum__storage_ { - uint32_t _has_storage_[1]; - GPBSyntax syntax; - NSString *name; - NSMutableArray *enumvalueArray; - NSMutableArray *optionsArray; - GPBSourceContext *sourceContext; -} GPBEnum__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBEnum_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBEnum__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "enumvalueArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBEnumValue), - .number = GPBEnum_FieldNumber_EnumvalueArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBEnum__storage_, enumvalueArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .number = GPBEnum_FieldNumber_OptionsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBEnum__storage_, optionsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - { - .name = "sourceContext", - .dataTypeSpecific.className = GPBStringifySymbol(GPBSourceContext), - .number = GPBEnum_FieldNumber_SourceContext, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBEnum__storage_, sourceContext), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - { - .name = "syntax", - .dataTypeSpecific.enumDescFunc = GPBSyntax_EnumDescriptor, - .number = GPBEnum_FieldNumber_Syntax, - .hasIndex = 2, - .offset = (uint32_t)offsetof(GPBEnum__storage_, syntax), - .flags = GPBFieldOptional | GPBFieldHasEnumDescriptor, - .dataType = GPBDataTypeEnum, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBEnum class] - rootClass:[GPBTypeRoot class] - file:GPBTypeRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBEnum__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -int32_t GPBEnum_Syntax_RawValue(GPBEnum *message) { - GPBDescriptor *descriptor = [GPBEnum descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBEnum_FieldNumber_Syntax]; - return GPBGetMessageInt32Field(message, field); -} - -void SetGPBEnum_Syntax_RawValue(GPBEnum *message, int32_t value) { - GPBDescriptor *descriptor = [GPBEnum descriptor]; - GPBFieldDescriptor *field = [descriptor fieldWithNumber:GPBEnum_FieldNumber_Syntax]; - GPBSetInt32IvarWithFieldInternal(message, field, value, descriptor.file.syntax); -} - -#pragma mark - GPBEnumValue - -@implementation GPBEnumValue - -@dynamic name; -@dynamic number; -@dynamic optionsArray, optionsArray_Count; - -typedef struct GPBEnumValue__storage_ { - uint32_t _has_storage_[1]; - int32_t number; - NSString *name; - NSMutableArray *optionsArray; -} GPBEnumValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBEnumValue_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBEnumValue__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "number", - .dataTypeSpecific.className = NULL, - .number = GPBEnumValue_FieldNumber_Number, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBEnumValue__storage_, number), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - { - .name = "optionsArray", - .dataTypeSpecific.className = GPBStringifySymbol(GPBOption), - .number = GPBEnumValue_FieldNumber_OptionsArray, - .hasIndex = GPBNoHasBit, - .offset = (uint32_t)offsetof(GPBEnumValue__storage_, optionsArray), - .flags = GPBFieldRepeated, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBEnumValue class] - rootClass:[GPBTypeRoot class] - file:GPBTypeRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBEnumValue__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBOption - -@implementation GPBOption - -@dynamic name; -@dynamic hasValue, value; - -typedef struct GPBOption__storage_ { - uint32_t _has_storage_[1]; - NSString *name; - GPBAny *value; -} GPBOption__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "name", - .dataTypeSpecific.className = NULL, - .number = GPBOption_FieldNumber_Name, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBOption__storage_, name), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - { - .name = "value", - .dataTypeSpecific.className = GPBStringifySymbol(GPBAny), - .number = GPBOption_FieldNumber_Value, - .hasIndex = 1, - .offset = (uint32_t)offsetof(GPBOption__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeMessage, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBOption class] - rootClass:[GPBTypeRoot class] - file:GPBTypeRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBOption__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Wrappers.pbobjc.h b/objectivec/google/google/protobuf/Wrappers.pbobjc.h deleted file mode 100644 index 46510500..00000000 --- a/objectivec/google/google/protobuf/Wrappers.pbobjc.h +++ /dev/null @@ -1,182 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/wrappers.proto - -#import "GPBProtocolBuffers.h" - -#if GOOGLE_PROTOBUF_OBJC_GEN_VERSION != 30001 -#error This file was generated by a different version of protoc which is incompatible with your Protocol Buffer library sources. -#endif - -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -CF_EXTERN_C_BEGIN - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark - GPBWrappersRoot - -/// Exposes the extension registry for this file. -/// -/// The base class provides: -/// @code -/// + (GPBExtensionRegistry *)extensionRegistry; -/// @endcode -/// which is a @c GPBExtensionRegistry that includes all the extensions defined by -/// this file and all files that it depends on. -@interface GPBWrappersRoot : GPBRootObject -@end - -#pragma mark - GPBDoubleValue - -typedef GPB_ENUM(GPBDoubleValue_FieldNumber) { - GPBDoubleValue_FieldNumber_Value = 1, -}; - -/// Wrapper message for `double`. -/// -/// The JSON representation for `DoubleValue` is JSON number. -@interface GPBDoubleValue : GPBMessage - -/// The double value. -@property(nonatomic, readwrite) double value; - -@end - -#pragma mark - GPBFloatValue - -typedef GPB_ENUM(GPBFloatValue_FieldNumber) { - GPBFloatValue_FieldNumber_Value = 1, -}; - -/// Wrapper message for `float`. -/// -/// The JSON representation for `FloatValue` is JSON number. -@interface GPBFloatValue : GPBMessage - -/// The float value. -@property(nonatomic, readwrite) float value; - -@end - -#pragma mark - GPBInt64Value - -typedef GPB_ENUM(GPBInt64Value_FieldNumber) { - GPBInt64Value_FieldNumber_Value = 1, -}; - -/// Wrapper message for `int64`. -/// -/// The JSON representation for `Int64Value` is JSON string. -@interface GPBInt64Value : GPBMessage - -/// The int64 value. -@property(nonatomic, readwrite) int64_t value; - -@end - -#pragma mark - GPBUInt64Value - -typedef GPB_ENUM(GPBUInt64Value_FieldNumber) { - GPBUInt64Value_FieldNumber_Value = 1, -}; - -/// Wrapper message for `uint64`. -/// -/// The JSON representation for `UInt64Value` is JSON string. -@interface GPBUInt64Value : GPBMessage - -/// The uint64 value. -@property(nonatomic, readwrite) uint64_t value; - -@end - -#pragma mark - GPBInt32Value - -typedef GPB_ENUM(GPBInt32Value_FieldNumber) { - GPBInt32Value_FieldNumber_Value = 1, -}; - -/// Wrapper message for `int32`. -/// -/// The JSON representation for `Int32Value` is JSON number. -@interface GPBInt32Value : GPBMessage - -/// The int32 value. -@property(nonatomic, readwrite) int32_t value; - -@end - -#pragma mark - GPBUInt32Value - -typedef GPB_ENUM(GPBUInt32Value_FieldNumber) { - GPBUInt32Value_FieldNumber_Value = 1, -}; - -/// Wrapper message for `uint32`. -/// -/// The JSON representation for `UInt32Value` is JSON number. -@interface GPBUInt32Value : GPBMessage - -/// The uint32 value. -@property(nonatomic, readwrite) uint32_t value; - -@end - -#pragma mark - GPBBoolValue - -typedef GPB_ENUM(GPBBoolValue_FieldNumber) { - GPBBoolValue_FieldNumber_Value = 1, -}; - -/// Wrapper message for `bool`. -/// -/// The JSON representation for `BoolValue` is JSON `true` and `false`. -@interface GPBBoolValue : GPBMessage - -/// The bool value. -@property(nonatomic, readwrite) BOOL value; - -@end - -#pragma mark - GPBStringValue - -typedef GPB_ENUM(GPBStringValue_FieldNumber) { - GPBStringValue_FieldNumber_Value = 1, -}; - -/// Wrapper message for `string`. -/// -/// The JSON representation for `StringValue` is JSON string. -@interface GPBStringValue : GPBMessage - -/// The string value. -@property(nonatomic, readwrite, copy, null_resettable) NSString *value; - -@end - -#pragma mark - GPBBytesValue - -typedef GPB_ENUM(GPBBytesValue_FieldNumber) { - GPBBytesValue_FieldNumber_Value = 1, -}; - -/// Wrapper message for `bytes`. -/// -/// The JSON representation for `BytesValue` is JSON string. -@interface GPBBytesValue : GPBMessage - -/// The bytes value. -@property(nonatomic, readwrite, copy, null_resettable) NSData *value; - -@end - -NS_ASSUME_NONNULL_END - -CF_EXTERN_C_END - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/google/protobuf/Wrappers.pbobjc.m b/objectivec/google/google/protobuf/Wrappers.pbobjc.m deleted file mode 100644 index 5cc6c2e4..00000000 --- a/objectivec/google/google/protobuf/Wrappers.pbobjc.m +++ /dev/null @@ -1,420 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: google/protobuf/wrappers.proto - -#import "GPBProtocolBuffers_RuntimeSupport.h" -#import "google/protobuf/Wrappers.pbobjc.h" -// @@protoc_insertion_point(imports) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#pragma mark - GPBWrappersRoot - -@implementation GPBWrappersRoot - -@end - -#pragma mark - GPBWrappersRoot_FileDescriptor - -static GPBFileDescriptor *GPBWrappersRoot_FileDescriptor(void) { - // This is called by +initialize so there is no need to worry - // about thread safety of the singleton. - static GPBFileDescriptor *descriptor = NULL; - if (!descriptor) { - GPBDebugCheckRuntimeVersion(); - descriptor = [[GPBFileDescriptor alloc] initWithPackage:@"google.protobuf" - syntax:GPBFileSyntaxProto3]; - } - return descriptor; -} - -#pragma mark - GPBDoubleValue - -@implementation GPBDoubleValue - -@dynamic value; - -typedef struct GPBDoubleValue__storage_ { - uint32_t _has_storage_[1]; - double value; -} GPBDoubleValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBDoubleValue_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBDoubleValue__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeDouble, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBDoubleValue class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBDoubleValue__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBFloatValue - -@implementation GPBFloatValue - -@dynamic value; - -typedef struct GPBFloatValue__storage_ { - uint32_t _has_storage_[1]; - float value; -} GPBFloatValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBFloatValue_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBFloatValue__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeFloat, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBFloatValue class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBFloatValue__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBInt64Value - -@implementation GPBInt64Value - -@dynamic value; - -typedef struct GPBInt64Value__storage_ { - uint32_t _has_storage_[1]; - int64_t value; -} GPBInt64Value__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBInt64Value_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBInt64Value__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt64, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBInt64Value class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBInt64Value__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBUInt64Value - -@implementation GPBUInt64Value - -@dynamic value; - -typedef struct GPBUInt64Value__storage_ { - uint32_t _has_storage_[1]; - uint64_t value; -} GPBUInt64Value__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBUInt64Value_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBUInt64Value__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeUInt64, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBUInt64Value class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBUInt64Value__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBInt32Value - -@implementation GPBInt32Value - -@dynamic value; - -typedef struct GPBInt32Value__storage_ { - uint32_t _has_storage_[1]; - int32_t value; -} GPBInt32Value__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBInt32Value_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBInt32Value__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBInt32Value class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBInt32Value__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBUInt32Value - -@implementation GPBUInt32Value - -@dynamic value; - -typedef struct GPBUInt32Value__storage_ { - uint32_t _has_storage_[1]; - uint32_t value; -} GPBUInt32Value__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBUInt32Value_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBUInt32Value__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeUInt32, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBUInt32Value class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBUInt32Value__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBBoolValue - -@implementation GPBBoolValue - -@dynamic value; - -typedef struct GPBBoolValue__storage_ { - uint32_t _has_storage_[1]; -} GPBBoolValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBBoolValue_FieldNumber_Value, - .hasIndex = 0, - .offset = 1, // Stored in _has_storage_ to save space. - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBool, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBBoolValue class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBBoolValue__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBStringValue - -@implementation GPBStringValue - -@dynamic value; - -typedef struct GPBStringValue__storage_ { - uint32_t _has_storage_[1]; - NSString *value; -} GPBStringValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBStringValue_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBStringValue__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeString, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBStringValue class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBStringValue__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - -#pragma mark - GPBBytesValue - -@implementation GPBBytesValue - -@dynamic value; - -typedef struct GPBBytesValue__storage_ { - uint32_t _has_storage_[1]; - NSData *value; -} GPBBytesValue__storage_; - -// This method is threadsafe because it is initially called -// in +initialize for each subclass. -+ (GPBDescriptor *)descriptor { - static GPBDescriptor *descriptor = nil; - if (!descriptor) { - static GPBMessageFieldDescription fields[] = { - { - .name = "value", - .dataTypeSpecific.className = NULL, - .number = GPBBytesValue_FieldNumber_Value, - .hasIndex = 0, - .offset = (uint32_t)offsetof(GPBBytesValue__storage_, value), - .flags = GPBFieldOptional, - .dataType = GPBDataTypeBytes, - }, - }; - GPBDescriptor *localDescriptor = - [GPBDescriptor allocDescriptorForClass:[GPBBytesValue class] - rootClass:[GPBWrappersRoot class] - file:GPBWrappersRoot_FileDescriptor() - fields:fields - fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) - storageSize:sizeof(GPBBytesValue__storage_) - flags:0]; - NSAssert(descriptor == nil, @"Startup recursed!"); - descriptor = localDescriptor; - } - return descriptor; -} - -@end - - -#pragma clang diagnostic pop - -// @@protoc_insertion_point(global_scope) diff --git a/objectivec/google/protobuf/Any.pbobjc.h b/objectivec/google/protobuf/Any.pbobjc.h index 439e3b37..4002a989 100644 --- a/objectivec/google/protobuf/Any.pbobjc.h +++ b/objectivec/google/protobuf/Any.pbobjc.h @@ -106,6 +106,8 @@ typedef GPB_ENUM(GPBAny_FieldNumber) { /// * If no schema is provided, `https` is assumed. /// * The last segment of the URL's path must represent the fully /// qualified name of the type (as in `path/google.protobuf.Duration`). +/// The name should be in a canonical form (e.g., leading "." is +/// not accepted). /// * An HTTP GET on the URL must yield a [google.protobuf.Type][] /// value in binary format, or produce an error. /// * Applications are allowed to cache lookup results based on the diff --git a/objectivec/google/protobuf/FieldMask.pbobjc.h b/objectivec/google/protobuf/FieldMask.pbobjc.h index 47a239ba..73cbd8a5 100644 --- a/objectivec/google/protobuf/FieldMask.pbobjc.h +++ b/objectivec/google/protobuf/FieldMask.pbobjc.h @@ -84,7 +84,7 @@ typedef GPB_ENUM(GPBFieldMask_FieldNumber) { /// operation applies to all fields (as if a FieldMask of all fields /// had been specified). /// -/// Note that a field mask does not necessarily applies to the +/// Note that a field mask does not necessarily apply to the /// top-level response message. In case of a REST get operation, the /// field mask applies directly to the response, but in case of a REST /// list operation, the mask instead applies to each individual message From 236b93937f21fdd1ba040326e61ded3dc8e6561a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sat, 30 Apr 2016 02:14:18 +0200 Subject: [PATCH 111/123] Addressing concerns. --- ruby/Rakefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ruby/Rakefile b/ruby/Rakefile index 45694d1f..88a07a64 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -26,6 +26,8 @@ proto2_protos = %w[ genproto_output = [] +# We won't have access to .. from within docker, but the proto files +# will be there, thanks to the :genproto rule dependency for gem:native. unless ENV['IN_DOCKER'] == 'true' well_known_protos.each do |proto_file| input_file = "../src/" + proto_file @@ -65,7 +67,13 @@ else RakeCompilerDock.sh "bundle && IN_DOCKER=true rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0" end - task 'gem:native' => [:genproto, 'gem:windows'] + if RUBY_PLATFORM =~ /darwin/ + task 'gem:native' do + system "rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0" + end + else + task 'gem:native' => [:genproto, 'gem:windows'] + end end From 247ef1f0df4ebb08a2bd8d47912a9e42b88abdc2 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 3 May 2016 12:53:49 -0700 Subject: [PATCH 112/123] Addressed PR comments. --- benchmarks/benchmark_messages_proto2.proto | 2 +- benchmarks/benchmark_messages_proto3.proto | 2 +- benchmarks/benchmarks.proto | 41 ---------------------- benchmarks/generate_datasets.cc | 19 ++++------ 4 files changed, 9 insertions(+), 55 deletions(-) diff --git a/benchmarks/benchmark_messages_proto2.proto b/benchmarks/benchmark_messages_proto2.proto index c7103be5..01f67a1a 100644 --- a/benchmarks/benchmark_messages_proto2.proto +++ b/benchmarks/benchmark_messages_proto2.proto @@ -2,7 +2,7 @@ syntax = "proto2"; -package benchmarks.p2; +package benchmarks.proto2; option java_package = "com.google.protobuf.benchmarks"; // This is the default, but we specify it here explicitly. diff --git a/benchmarks/benchmark_messages_proto3.proto b/benchmarks/benchmark_messages_proto3.proto index 4ea39c22..32f58698 100644 --- a/benchmarks/benchmark_messages_proto3.proto +++ b/benchmarks/benchmark_messages_proto3.proto @@ -2,7 +2,7 @@ syntax = "proto3"; -package benchmarks.p3; +package benchmarks.proto3; option java_package = "com.google.protobuf.benchmarks"; // This is the default, but we specify it here explicitly. diff --git a/benchmarks/benchmarks.proto b/benchmarks/benchmarks.proto index 0ac3bf33..51c0b548 100644 --- a/benchmarks/benchmarks.proto +++ b/benchmarks/benchmarks.proto @@ -61,44 +61,3 @@ message BenchmarkDataset { // good branch prediction performance. repeated bytes payload = 3; } - -// A benchmark can write out metrics that we will then upload to our metrics -// database for tracking over time. -message Metric { - // A unique ID for these results. Used for de-duping. - string guid = 1; - - // The labels specify exactly what benchmark was run against the dataset. - // The specific benchmark suite can decide what these mean, but here are - // some common labels that have a predefined meaning: - // - // - "dataset": for tests that pertain to a specific dataset. - // - // For example: - // - // # Tests parsing from binary proto string using arenas. - // labels={ - // dataset: "testalltypes", - // op: "parse", - // format: "binaryproto", - // input: "string" - // arena: "true" - // } - // - // # Tests serializing to JSON string. - // labels={ - // dataset: "testalltypes", - // op: "serialize", - // format: "json", - // input: "string" - // } - map labels = 2; - - // Unit of measurement for the metric: - // - a speed test might be "mb_per_second" or "ops_per_second" - // - a size test might be "kb". - string unit = 3; - - // Metric value. - double value = 4; -} diff --git a/benchmarks/generate_datasets.cc b/benchmarks/generate_datasets.cc index dab635e7..61e7adf1 100644 --- a/benchmarks/generate_datasets.cc +++ b/benchmarks/generate_datasets.cc @@ -28,9 +28,6 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -const char *file_prefix = "dataset."; -const char *file_suffix = ".pb"; - #include #include #include "benchmarks.pb.h" @@ -41,10 +38,11 @@ using google::protobuf::DescriptorPool; using google::protobuf::Message; using google::protobuf::MessageFactory; -#define ARRAY_TO_STRING(arr) std::string(arr, arr + sizeof(arr)) - std::set names; +const char *file_prefix = "dataset."; +const char *file_suffix = ".pb"; + void WriteFileWithPayloads(const std::string& name, const std::string& message_name, const std::vector& payload) { @@ -81,13 +79,10 @@ void WriteFileWithPayloads(const std::string& name, dataset.add_payload()->assign(payload[i]); } - std::string serialized; - dataset.SerializeToString(&serialized); - std::ofstream writer; std::string fname = file_prefix + name + file_suffix; writer.open(fname.c_str()); - writer << serialized; + dataset.SerializeToOstream(&writer); writer.close(); std::cerr << "Wrote dataset: " << fname << "\n"; @@ -111,12 +106,12 @@ std::string ReadFile(const std::string& name) { } int main() { - WriteFile("google_message1_proto3", "benchmarks.p3.GoogleMessage1", + WriteFile("google_message1_proto3", "benchmarks.proto3.GoogleMessage1", ReadFile("google_message1.dat")); - WriteFile("google_message1_proto2", "benchmarks.p2.GoogleMessage1", + WriteFile("google_message1_proto2", "benchmarks.proto2.GoogleMessage1", ReadFile("google_message1.dat")); // Not in proto3 because it has a group, which is not supported. - WriteFile("google_message2", "benchmarks.p2.GoogleMessage2", + WriteFile("google_message2", "benchmarks.proto2.GoogleMessage2", ReadFile("google_message2.dat")); } From edd29498f420427212079193ce1e82aa74aa2014 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 4 May 2016 02:29:17 +0200 Subject: [PATCH 113/123] Properly generating well known proto files for the macos build. --- ruby/Rakefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ruby/Rakefile b/ruby/Rakefile index 88a07a64..fa29c315 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -69,6 +69,7 @@ else if RUBY_PLATFORM =~ /darwin/ task 'gem:native' do + system "rake genproto" system "rake cross native gem RUBY_CC_VERSION=2.3.0:2.2.2:2.1.5:2.0.0" end else From 75e5898513d480c920486975389728dad3d158d6 Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 5 May 2016 16:04:30 -0700 Subject: [PATCH 114/123] Fix the std::string error introduced in integration. --- python/google/protobuf/pyext/message.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index 9dce198f..9a865147 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -54,7 +54,7 @@ class MessageFactory; #ifdef _SHARED_PTR_H using shared_ptr; -using std::std::string; +using ::std::string; #else using internal::shared_ptr; #endif From f8a5c5f74650630a269951322a8afb915e7c9c3d Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Thu, 5 May 2016 16:34:42 -0700 Subject: [PATCH 115/123] Fix using std::shared_ptr --- python/google/protobuf/pyext/extension_dict.h | 2 +- python/google/protobuf/pyext/map_container.h | 2 +- python/google/protobuf/pyext/message.h | 2 +- python/google/protobuf/pyext/repeated_composite_container.h | 2 +- python/google/protobuf/pyext/repeated_scalar_container.h | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/python/google/protobuf/pyext/extension_dict.h b/python/google/protobuf/pyext/extension_dict.h index 049d2e45..2456eda1 100644 --- a/python/google/protobuf/pyext/extension_dict.h +++ b/python/google/protobuf/pyext/extension_dict.h @@ -48,7 +48,7 @@ class Message; class FieldDescriptor; #ifdef _SHARED_PTR_H -using shared_ptr; +using std::shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/map_container.h b/python/google/protobuf/pyext/map_container.h index b11dfa34..fbd6713f 100644 --- a/python/google/protobuf/pyext/map_container.h +++ b/python/google/protobuf/pyext/map_container.h @@ -47,7 +47,7 @@ namespace protobuf { class Message; #ifdef _SHARED_PTR_H -using shared_ptr; +using std::shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h index 9a865147..3a4bec81 100644 --- a/python/google/protobuf/pyext/message.h +++ b/python/google/protobuf/pyext/message.h @@ -53,7 +53,7 @@ class DescriptorPool; class MessageFactory; #ifdef _SHARED_PTR_H -using shared_ptr; +using std::shared_ptr; using ::std::string; #else using internal::shared_ptr; diff --git a/python/google/protobuf/pyext/repeated_composite_container.h b/python/google/protobuf/pyext/repeated_composite_container.h index 25463037..a7b56b61 100644 --- a/python/google/protobuf/pyext/repeated_composite_container.h +++ b/python/google/protobuf/pyext/repeated_composite_container.h @@ -50,7 +50,7 @@ class FieldDescriptor; class Message; #ifdef _SHARED_PTR_H -using shared_ptr; +using std::shared_ptr; #else using internal::shared_ptr; #endif diff --git a/python/google/protobuf/pyext/repeated_scalar_container.h b/python/google/protobuf/pyext/repeated_scalar_container.h index 608222e0..555e621c 100644 --- a/python/google/protobuf/pyext/repeated_scalar_container.h +++ b/python/google/protobuf/pyext/repeated_scalar_container.h @@ -49,7 +49,7 @@ namespace protobuf { class Message; #ifdef _SHARED_PTR_H -using shared_ptr; +using std::shared_ptr; #else using internal::shared_ptr; #endif From 9b3357ddac879aa7c63ef2ae97438eaeedbb36d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mahmut=20Ali=20=C3=96ZKURAN?= Date: Fri, 6 May 2016 10:16:28 +0300 Subject: [PATCH 116/123] Updated README.md Added relative link to cmake guide. --- src/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/README.md b/src/README.md index 4e312c0c..c85bad34 100644 --- a/src/README.md +++ b/src/README.md @@ -181,7 +181,7 @@ In the downloads section, download the zip file protoc-$VERSION-win32.zip. It contains the protoc binary as well as public proto files of protobuf library. -To build from source using Microsoft Visual C++, see cmake/README.md. +To build from source using Microsoft Visual C++, see [cmake/README.md](../cmake/README.md). To build from source using Cygwin or MinGW, follow the Unix installation instructions, above. From b12f630e8190f6c0fb7a58a434e445da1d5daff8 Mon Sep 17 00:00:00 2001 From: beardedn5rd Date: Fri, 6 May 2016 14:49:52 +0200 Subject: [PATCH 117/123] updated README --- src/README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/README.md b/src/README.md index 4e312c0c..6ace6bcd 100644 --- a/src/README.md +++ b/src/README.md @@ -16,10 +16,13 @@ To build protobuf from source, the following tools are needed: * automake * libtool * curl (used to download gmock) + * make + * clang (gcc) + * unzip On Ubuntu, you can install them with: - $ sudo apt-get install autoconf automake libtool curl + $ sudo apt-get install autoconf automake libtool curl make clang unzip On other platforms, please use the corresponding package managing tool to install them before proceeding. From f367642103160b357cce6e59256cd3a51c9bad28 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 6 May 2016 11:44:42 -0400 Subject: [PATCH 118/123] Add two missing ignores for conformance directory. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index a2d6ca9c..27eeb9c2 100644 --- a/.gitignore +++ b/.gitignore @@ -111,5 +111,7 @@ conformance/conformance.pb.h conformance/Conformance.pbobjc.h conformance/Conformance.pbobjc.m conformance/conformance.rb +conformance/google/ conformance/javac_middleman +conformance/lite/ conformance/protoc_middleman From ce2ef0d7055cbf03ae585b7131db166a4727c555 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 6 May 2016 12:41:23 -0400 Subject: [PATCH 119/123] Properly express all outputs for the conformance build - Fixes up `make distclean` and `make maintainer-clean` - Fixes the build so make is more likely to notice if one of those files is stale/missing. --- conformance/Makefile.am | 110 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 4 deletions(-) diff --git a/conformance/Makefile.am b/conformance/Makefile.am index abb1c00d..31a9e408 100644 --- a/conformance/Makefile.am +++ b/conformance/Makefile.am @@ -17,12 +17,114 @@ protoc_outputs = \ conformance.pb.h other_language_protoc_outputs = \ - conformance.rb \ - com/google/protobuf/conformance/Conformance.java \ - lite/com/google/protobuf/conformance/Conformance.java \ conformance_pb2.py \ Conformance.pbobjc.h \ - Conformance.pbobjc.m + Conformance.pbobjc.m \ + conformance.rb \ + com/google/protobuf/Any.java \ + com/google/protobuf/AnyOrBuilder.java \ + com/google/protobuf/AnyProto.java \ + com/google/protobuf/BoolValue.java \ + com/google/protobuf/BoolValueOrBuilder.java \ + com/google/protobuf/BytesValue.java \ + com/google/protobuf/BytesValueOrBuilder.java \ + com/google/protobuf/conformance/Conformance.java \ + com/google/protobuf/DoubleValue.java \ + com/google/protobuf/DoubleValueOrBuilder.java \ + com/google/protobuf/Duration.java \ + com/google/protobuf/DurationOrBuilder.java \ + com/google/protobuf/DurationProto.java \ + com/google/protobuf/FieldMask.java \ + com/google/protobuf/FieldMaskOrBuilder.java \ + com/google/protobuf/FieldMaskProto.java \ + com/google/protobuf/FloatValue.java \ + com/google/protobuf/FloatValueOrBuilder.java \ + com/google/protobuf/Int32Value.java \ + com/google/protobuf/Int32ValueOrBuilder.java \ + com/google/protobuf/Int64Value.java \ + com/google/protobuf/Int64ValueOrBuilder.java \ + com/google/protobuf/ListValue.java \ + com/google/protobuf/ListValueOrBuilder.java \ + com/google/protobuf/NullValue.java \ + com/google/protobuf/StringValue.java \ + com/google/protobuf/StringValueOrBuilder.java \ + com/google/protobuf/Struct.java \ + com/google/protobuf/StructOrBuilder.java \ + com/google/protobuf/StructProto.java \ + com/google/protobuf/Timestamp.java \ + com/google/protobuf/TimestampOrBuilder.java \ + com/google/protobuf/TimestampProto.java \ + com/google/protobuf/UInt32Value.java \ + com/google/protobuf/UInt32ValueOrBuilder.java \ + com/google/protobuf/UInt64Value.java \ + com/google/protobuf/UInt64ValueOrBuilder.java \ + com/google/protobuf/Value.java \ + com/google/protobuf/ValueOrBuilder.java \ + com/google/protobuf/WrappersProto.java \ + google/protobuf/any.pb.cc \ + google/protobuf/any.pb.h \ + google/protobuf/any.rb \ + google/protobuf/any_pb2.py \ + google/protobuf/duration.pb.cc \ + google/protobuf/duration.pb.h \ + google/protobuf/duration.rb \ + google/protobuf/duration_pb2.py \ + google/protobuf/field_mask.pb.cc \ + google/protobuf/field_mask.pb.h \ + google/protobuf/field_mask.rb \ + google/protobuf/field_mask_pb2.py \ + google/protobuf/struct.pb.cc \ + google/protobuf/struct.pb.h \ + google/protobuf/struct.rb \ + google/protobuf/struct_pb2.py \ + google/protobuf/timestamp.pb.cc \ + google/protobuf/timestamp.pb.h \ + google/protobuf/timestamp.rb \ + google/protobuf/timestamp_pb2.py \ + google/protobuf/wrappers.pb.cc \ + google/protobuf/wrappers.pb.h \ + google/protobuf/wrappers.rb \ + google/protobuf/wrappers_pb2.py \ + lite/com/google/protobuf/Any.java \ + lite/com/google/protobuf/AnyOrBuilder.java \ + lite/com/google/protobuf/AnyProto.java \ + lite/com/google/protobuf/BoolValue.java \ + lite/com/google/protobuf/BoolValueOrBuilder.java \ + lite/com/google/protobuf/BytesValue.java \ + lite/com/google/protobuf/BytesValueOrBuilder.java \ + lite/com/google/protobuf/conformance/Conformance.java \ + lite/com/google/protobuf/DoubleValue.java \ + lite/com/google/protobuf/DoubleValueOrBuilder.java \ + lite/com/google/protobuf/Duration.java \ + lite/com/google/protobuf/DurationOrBuilder.java \ + lite/com/google/protobuf/DurationProto.java \ + lite/com/google/protobuf/FieldMask.java \ + lite/com/google/protobuf/FieldMaskOrBuilder.java \ + lite/com/google/protobuf/FieldMaskProto.java \ + lite/com/google/protobuf/FloatValue.java \ + lite/com/google/protobuf/FloatValueOrBuilder.java \ + lite/com/google/protobuf/Int32Value.java \ + lite/com/google/protobuf/Int32ValueOrBuilder.java \ + lite/com/google/protobuf/Int64Value.java \ + lite/com/google/protobuf/Int64ValueOrBuilder.java \ + lite/com/google/protobuf/ListValue.java \ + lite/com/google/protobuf/ListValueOrBuilder.java \ + lite/com/google/protobuf/NullValue.java \ + lite/com/google/protobuf/StringValue.java \ + lite/com/google/protobuf/StringValueOrBuilder.java \ + lite/com/google/protobuf/Struct.java \ + lite/com/google/protobuf/StructOrBuilder.java \ + lite/com/google/protobuf/StructProto.java \ + lite/com/google/protobuf/Timestamp.java \ + lite/com/google/protobuf/TimestampOrBuilder.java \ + lite/com/google/protobuf/TimestampProto.java \ + lite/com/google/protobuf/UInt32Value.java \ + lite/com/google/protobuf/UInt32ValueOrBuilder.java \ + lite/com/google/protobuf/UInt64Value.java \ + lite/com/google/protobuf/UInt64ValueOrBuilder.java \ + lite/com/google/protobuf/Value.java \ + lite/com/google/protobuf/ValueOrBuilder.java \ + lite/com/google/protobuf/WrappersProto.java bin_PROGRAMS = conformance-test-runner conformance-cpp From b661fb5000cdef8d22a610b410188bc9a04be703 Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Fri, 6 May 2016 12:47:41 -0400 Subject: [PATCH 120/123] Add the missing maintiner-clean entry for benchmarks --- benchmarks/Makefile.am | 3 +++ 1 file changed, 3 insertions(+) diff --git a/benchmarks/Makefile.am b/benchmarks/Makefile.am index 1e162eb1..f730afe5 100644 --- a/benchmarks/Makefile.am +++ b/benchmarks/Makefile.am @@ -40,6 +40,9 @@ CLEANFILES = \ protoc_middleman2 \ dataset.* +MAINTAINERCLEANFILES = \ + Makefile.in + if USE_EXTERNAL_PROTOC protoc_middleman: $(benchmarks_protoc_inputs) From 2eb774e6026d1ddf082270861ff90422cd96b878 Mon Sep 17 00:00:00 2001 From: beardedn5rd Date: Fri, 6 May 2016 22:47:17 +0200 Subject: [PATCH 121/123] after comment of Feng Xiao changed the entry to g++ --- src/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/README.md b/src/README.md index 6ace6bcd..d623a49a 100644 --- a/src/README.md +++ b/src/README.md @@ -17,12 +17,12 @@ To build protobuf from source, the following tools are needed: * libtool * curl (used to download gmock) * make - * clang (gcc) + * g++ * unzip On Ubuntu, you can install them with: - $ sudo apt-get install autoconf automake libtool curl make clang unzip + $ sudo apt-get install autoconf automake libtool curl make g++ unzip On other platforms, please use the corresponding package managing tool to install them before proceeding. From ce6bec74fddd44b6870553db0c58fddaf9fa239f Mon Sep 17 00:00:00 2001 From: Jisi Liu Date: Fri, 6 May 2016 15:57:06 -0700 Subject: [PATCH 122/123] Remove accidentally restored deleted files. --- .../com/google/protobuf/AbstractMessage.java | 553 ------------------ .../google/protobuf/AbstractMessageLite.java | 386 ------------ .../com/google/protobuf/AbstractParser.java | 258 -------- .../google/protobuf/AbstractProtobufList.java | 180 ------ .../google/protobuf/BlockingRpcChannel.java | 51 -- .../com/google/protobuf/BlockingService.java | 64 -- 6 files changed, 1492 deletions(-) delete mode 100644 java/src/main/java/com/google/protobuf/AbstractMessage.java delete mode 100644 java/src/main/java/com/google/protobuf/AbstractMessageLite.java delete mode 100644 java/src/main/java/com/google/protobuf/AbstractParser.java delete mode 100644 java/src/main/java/com/google/protobuf/AbstractProtobufList.java delete mode 100644 java/src/main/java/com/google/protobuf/BlockingRpcChannel.java delete mode 100644 java/src/main/java/com/google/protobuf/BlockingService.java diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java deleted file mode 100644 index 03c0d579..00000000 --- a/java/src/main/java/com/google/protobuf/AbstractMessage.java +++ /dev/null @@ -1,553 +0,0 @@ -// 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. - -package com.google.protobuf; - -import com.google.protobuf.Descriptors.EnumValueDescriptor; -import com.google.protobuf.Descriptors.FieldDescriptor; -import com.google.protobuf.Descriptors.OneofDescriptor; -import com.google.protobuf.Internal.EnumLite; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * A partial implementation of the {@link Message} interface which implements - * as many methods of that interface as possible in terms of other methods. - * - * @author kenton@google.com Kenton Varda - */ -public abstract class AbstractMessage - // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType. - extends AbstractMessageLite - implements Message { - - @Override - public boolean isInitialized() { - return MessageReflection.isInitialized(this); - } - - - @Override - public List findInitializationErrors() { - return MessageReflection.findMissingFields(this); - } - - @Override - public String getInitializationErrorString() { - return MessageReflection.delimitWithCommas(findInitializationErrors()); - } - - /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ - @Override - public boolean hasOneof(OneofDescriptor oneof) { - throw new UnsupportedOperationException("hasOneof() is not implemented."); - } - - /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ - @Override - public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { - throw new UnsupportedOperationException( - "getOneofFieldDescriptor() is not implemented."); - } - - @Override - public final String toString() { - return TextFormat.printToString(this); - } - - @Override - public void writeTo(final CodedOutputStream output) throws IOException { - MessageReflection.writeMessageTo(this, getAllFields(), output, false); - } - - protected int memoizedSize = -1; - - @Override - public int getSerializedSize() { - int size = memoizedSize; - if (size != -1) { - return size; - } - - memoizedSize = MessageReflection.getSerializedSize(this, getAllFields()); - return memoizedSize; - } - - @Override - public boolean equals(final Object other) { - if (other == this) { - return true; - } - if (!(other instanceof Message)) { - return false; - } - final Message otherMessage = (Message) other; - if (getDescriptorForType() != otherMessage.getDescriptorForType()) { - return false; - } - return compareFields(getAllFields(), otherMessage.getAllFields()) && - getUnknownFields().equals(otherMessage.getUnknownFields()); - } - - @Override - public int hashCode() { - int hash = memoizedHashCode; - if (hash == 0) { - hash = 41; - hash = (19 * hash) + getDescriptorForType().hashCode(); - hash = hashFields(hash, getAllFields()); - hash = (29 * hash) + getUnknownFields().hashCode(); - memoizedHashCode = hash; - } - return hash; - } - - private static ByteString toByteString(Object value) { - if (value instanceof byte[]) { - return ByteString.copyFrom((byte[]) value); - } else { - return (ByteString) value; - } - } - - /** - * Compares two bytes fields. The parameters must be either a byte array or a - * ByteString object. They can be of different type though. - */ - private static boolean compareBytes(Object a, Object b) { - if (a instanceof byte[] && b instanceof byte[]) { - return Arrays.equals((byte[])a, (byte[])b); - } - return toByteString(a).equals(toByteString(b)); - } - - /** - * Converts a list of MapEntry messages into a Map used for equals() and - * hashCode(). - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - private static Map convertMapEntryListToMap(List list) { - if (list.isEmpty()) { - return Collections.emptyMap(); - } - Map result = new HashMap(); - Iterator iterator = list.iterator(); - Message entry = (Message) iterator.next(); - Descriptors.Descriptor descriptor = entry.getDescriptorForType(); - Descriptors.FieldDescriptor key = descriptor.findFieldByName("key"); - Descriptors.FieldDescriptor value = descriptor.findFieldByName("value"); - Object fieldValue = entry.getField(value); - if (fieldValue instanceof EnumValueDescriptor) { - fieldValue = ((EnumValueDescriptor) fieldValue).getNumber(); - } - result.put(entry.getField(key), fieldValue); - while (iterator.hasNext()) { - entry = (Message) iterator.next(); - fieldValue = entry.getField(value); - if (fieldValue instanceof EnumValueDescriptor) { - fieldValue = ((EnumValueDescriptor) fieldValue).getNumber(); - } - result.put(entry.getField(key), fieldValue); - } - return result; - } - - /** - * Compares two map fields. The parameters must be a list of MapEntry - * messages. - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - private static boolean compareMapField(Object a, Object b) { - Map ma = convertMapEntryListToMap((List) a); - Map mb = convertMapEntryListToMap((List) b); - return MapFieldLite.equals(ma, mb); - } - - /** - * Compares two set of fields. - * This method is used to implement {@link AbstractMessage#equals(Object)} - * and {@link AbstractMutableMessage#equals(Object)}. It takes special care - * of bytes fields because immutable messages and mutable messages use - * different Java type to reprensent a bytes field and this method should be - * able to compare immutable messages, mutable messages and also an immutable - * message to a mutable message. - */ - static boolean compareFields(Map a, - Map b) { - if (a.size() != b.size()) { - return false; - } - for (FieldDescriptor descriptor : a.keySet()) { - if (!b.containsKey(descriptor)) { - return false; - } - Object value1 = a.get(descriptor); - Object value2 = b.get(descriptor); - if (descriptor.getType() == FieldDescriptor.Type.BYTES) { - if (descriptor.isRepeated()) { - List list1 = (List) value1; - List list2 = (List) value2; - if (list1.size() != list2.size()) { - return false; - } - for (int i = 0; i < list1.size(); i++) { - if (!compareBytes(list1.get(i), list2.get(i))) { - return false; - } - } - } else { - // Compares a singular bytes field. - if (!compareBytes(value1, value2)) { - return false; - } - } - } else if (descriptor.isMapField()) { - if (!compareMapField(value1, value2)) { - return false; - } - } else { - // Compare non-bytes fields. - if (!value1.equals(value2)) { - return false; - } - } - } - return true; - } - - /** - * Calculates the hash code of a map field. {@code value} must be a list of - * MapEntry messages. - */ - @SuppressWarnings("unchecked") - private static int hashMapField(Object value) { - return MapFieldLite.calculateHashCodeForMap(convertMapEntryListToMap((List) value)); - } - - /** Get a hash code for given fields and values, using the given seed. */ - @SuppressWarnings("unchecked") - protected static int hashFields(int hash, Map map) { - for (Map.Entry entry : map.entrySet()) { - FieldDescriptor field = entry.getKey(); - Object value = entry.getValue(); - hash = (37 * hash) + field.getNumber(); - if (field.isMapField()) { - hash = (53 * hash) + hashMapField(value); - } else if (field.getType() != FieldDescriptor.Type.ENUM){ - hash = (53 * hash) + value.hashCode(); - } else if (field.isRepeated()) { - List list = (List) value; - hash = (53 * hash) + Internal.hashEnumList(list); - } else { - hash = (53 * hash) + Internal.hashEnum((EnumLite) value); - } - } - return hash; - } - - /** - * Package private helper method for AbstractParser to create - * UninitializedMessageException with missing field information. - */ - @Override - UninitializedMessageException newUninitializedMessageException() { - return Builder.newUninitializedMessageException(this); - } - - // ================================================================= - - /** - * A partial implementation of the {@link Message.Builder} interface which - * implements as many methods of that interface as possible in terms of - * other methods. - */ - @SuppressWarnings("unchecked") - public static abstract class Builder> - extends AbstractMessageLite.Builder - implements Message.Builder { - // The compiler produces an error if this is not declared explicitly. - @Override - public abstract BuilderType clone(); - - /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ - @Override - public boolean hasOneof(OneofDescriptor oneof) { - throw new UnsupportedOperationException("hasOneof() is not implemented."); - } - - /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ - @Override - public FieldDescriptor getOneofFieldDescriptor(OneofDescriptor oneof) { - throw new UnsupportedOperationException( - "getOneofFieldDescriptor() is not implemented."); - } - - /** TODO(jieluo): Clear it when all subclasses have implemented this method. */ - @Override - public BuilderType clearOneof(OneofDescriptor oneof) { - throw new UnsupportedOperationException("clearOneof() is not implemented."); - } - - @Override - public BuilderType clear() { - for (final Map.Entry entry : - getAllFields().entrySet()) { - clearField(entry.getKey()); - } - return (BuilderType) this; - } - - @Override - public List findInitializationErrors() { - return MessageReflection.findMissingFields(this); - } - - @Override - public String getInitializationErrorString() { - return MessageReflection.delimitWithCommas(findInitializationErrors()); - } - - @Override - protected BuilderType internalMergeFrom(AbstractMessageLite other) { - return mergeFrom((Message) other); - } - - @Override - public BuilderType mergeFrom(final Message other) { - if (other.getDescriptorForType() != getDescriptorForType()) { - throw new IllegalArgumentException( - "mergeFrom(Message) can only merge messages of the same type."); - } - - // Note: We don't attempt to verify that other's fields have valid - // types. Doing so would be a losing battle. We'd have to verify - // all sub-messages as well, and we'd have to make copies of all of - // them to insure that they don't change after verification (since - // the Message interface itself cannot enforce immutability of - // implementations). - // TODO(kenton): Provide a function somewhere called makeDeepCopy() - // which allows people to make secure deep copies of messages. - - for (final Map.Entry entry : - other.getAllFields().entrySet()) { - final FieldDescriptor field = entry.getKey(); - if (field.isRepeated()) { - for (final Object element : (List)entry.getValue()) { - addRepeatedField(field, element); - } - } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) { - final Message existingValue = (Message)getField(field); - if (existingValue == existingValue.getDefaultInstanceForType()) { - setField(field, entry.getValue()); - } else { - setField(field, - existingValue.newBuilderForType() - .mergeFrom(existingValue) - .mergeFrom((Message)entry.getValue()) - .build()); - } - } else { - setField(field, entry.getValue()); - } - } - - mergeUnknownFields(other.getUnknownFields()); - - return (BuilderType) this; - } - - @Override - public BuilderType mergeFrom(final CodedInputStream input) - throws IOException { - return mergeFrom(input, ExtensionRegistry.getEmptyRegistry()); - } - - @Override - public BuilderType mergeFrom( - final CodedInputStream input, - final ExtensionRegistryLite extensionRegistry) - throws IOException { - final UnknownFieldSet.Builder unknownFields = - UnknownFieldSet.newBuilder(getUnknownFields()); - while (true) { - final int tag = input.readTag(); - if (tag == 0) { - break; - } - - MessageReflection.BuilderAdapter builderAdapter = - new MessageReflection.BuilderAdapter(this); - if (!MessageReflection.mergeFieldFrom(input, unknownFields, - extensionRegistry, - getDescriptorForType(), - builderAdapter, - tag)) { - // end group tag - break; - } - } - setUnknownFields(unknownFields.build()); - return (BuilderType) this; - } - - @Override - public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) { - setUnknownFields( - UnknownFieldSet.newBuilder(getUnknownFields()) - .mergeFrom(unknownFields) - .build()); - return (BuilderType) this; - } - - @Override - public Message.Builder getFieldBuilder(final FieldDescriptor field) { - throw new UnsupportedOperationException( - "getFieldBuilder() called on an unsupported message type."); - } - - @Override - public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) { - throw new UnsupportedOperationException( - "getRepeatedFieldBuilder() called on an unsupported message type."); - } - - @Override - public String toString() { - return TextFormat.printToString(this); - } - - /** - * Construct an UninitializedMessageException reporting missing fields in - * the given message. - */ - protected static UninitializedMessageException - newUninitializedMessageException(Message message) { - return new UninitializedMessageException( - MessageReflection.findMissingFields(message)); - } - - // =============================================================== - // The following definitions seem to be required in order to make javac - // not produce weird errors like: - // - // java/com/google/protobuf/DynamicMessage.java:203: types - // com.google.protobuf.AbstractMessage.Builder< - // com.google.protobuf.DynamicMessage.Builder> and - // com.google.protobuf.AbstractMessage.Builder< - // com.google.protobuf.DynamicMessage.Builder> are incompatible; both - // define mergeFrom(com.google.protobuf.ByteString), but with unrelated - // return types. - // - // Strangely, these lines are only needed if javac is invoked separately - // on AbstractMessage.java and AbstractMessageLite.java. If javac is - // invoked on both simultaneously, it works. (Or maybe the important - // point is whether or not DynamicMessage.java is compiled together with - // AbstractMessageLite.java -- not sure.) I suspect this is a compiler - // bug. - - @Override - public BuilderType mergeFrom(final ByteString data) - throws InvalidProtocolBufferException { - return (BuilderType) super.mergeFrom(data); - } - - @Override - public BuilderType mergeFrom( - final ByteString data, - final ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return (BuilderType) super.mergeFrom(data, extensionRegistry); - } - - @Override - public BuilderType mergeFrom(final byte[] data) - throws InvalidProtocolBufferException { - return (BuilderType) super.mergeFrom(data); - } - - @Override - public BuilderType mergeFrom( - final byte[] data, final int off, final int len) - throws InvalidProtocolBufferException { - return (BuilderType) super.mergeFrom(data, off, len); - } - - @Override - public BuilderType mergeFrom( - final byte[] data, - final ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return (BuilderType) super.mergeFrom(data, extensionRegistry); - } - - @Override - public BuilderType mergeFrom( - final byte[] data, final int off, final int len, - final ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return (BuilderType) super.mergeFrom(data, off, len, extensionRegistry); - } - - @Override - public BuilderType mergeFrom(final InputStream input) - throws IOException { - return (BuilderType) super.mergeFrom(input); - } - - @Override - public BuilderType mergeFrom( - final InputStream input, - final ExtensionRegistryLite extensionRegistry) - throws IOException { - return (BuilderType) super.mergeFrom(input, extensionRegistry); - } - - @Override - public boolean mergeDelimitedFrom(final InputStream input) - throws IOException { - return super.mergeDelimitedFrom(input); - } - - @Override - public boolean mergeDelimitedFrom( - final InputStream input, - final ExtensionRegistryLite extensionRegistry) - throws IOException { - return super.mergeDelimitedFrom(input, extensionRegistry); - } - } -} diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java deleted file mode 100644 index 43736dd1..00000000 --- a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java +++ /dev/null @@ -1,386 +0,0 @@ -// 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. - -package com.google.protobuf; - -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Collection; - -/** - * A partial implementation of the {@link MessageLite} interface which - * implements as many methods of that interface as possible in terms of other - * methods. - * - * @author kenton@google.com Kenton Varda - */ -public abstract class AbstractMessageLite< - MessageType extends AbstractMessageLite, - BuilderType extends AbstractMessageLite.Builder> - implements MessageLite { - protected int memoizedHashCode = 0; - - @Override - public ByteString toByteString() { - try { - final ByteString.CodedBuilder out = - ByteString.newCodedBuilder(getSerializedSize()); - writeTo(out.getCodedOutput()); - return out.build(); - } catch (IOException e) { - throw new RuntimeException( - "Serializing to a ByteString threw an IOException (should " + - "never happen).", e); - } - } - - @Override - public byte[] toByteArray() { - try { - final byte[] result = new byte[getSerializedSize()]; - final CodedOutputStream output = CodedOutputStream.newInstance(result); - writeTo(output); - output.checkNoSpaceLeft(); - return result; - } catch (IOException e) { - throw new RuntimeException( - "Serializing to a byte array threw an IOException " + - "(should never happen).", e); - } - } - - @Override - public void writeTo(final OutputStream output) throws IOException { - final int bufferSize = - CodedOutputStream.computePreferredBufferSize(getSerializedSize()); - final CodedOutputStream codedOutput = - CodedOutputStream.newInstance(output, bufferSize); - writeTo(codedOutput); - codedOutput.flush(); - } - - @Override - public void writeDelimitedTo(final OutputStream output) throws IOException { - final int serialized = getSerializedSize(); - final int bufferSize = CodedOutputStream.computePreferredBufferSize( - CodedOutputStream.computeRawVarint32Size(serialized) + serialized); - final CodedOutputStream codedOutput = - CodedOutputStream.newInstance(output, bufferSize); - codedOutput.writeRawVarint32(serialized); - writeTo(codedOutput); - codedOutput.flush(); - } - - - /** - * Package private helper method for AbstractParser to create - * UninitializedMessageException. - */ - UninitializedMessageException newUninitializedMessageException() { - return new UninitializedMessageException(this); - } - - protected static void checkByteStringIsUtf8(ByteString byteString) - throws IllegalArgumentException { - if (!byteString.isValidUtf8()) { - throw new IllegalArgumentException("Byte string is not UTF-8."); - } - } - - protected static void addAll(final Iterable values, - final Collection list) { - Builder.addAll(values, list); - } - - /** - * A partial implementation of the {@link Message.Builder} interface which - * implements as many methods of that interface as possible in terms of - * other methods. - */ - @SuppressWarnings("unchecked") - public abstract static class Builder< - MessageType extends AbstractMessageLite, - BuilderType extends Builder> - implements MessageLite.Builder { - // The compiler produces an error if this is not declared explicitly. - @Override - public abstract BuilderType clone(); - - @Override - public BuilderType mergeFrom(final CodedInputStream input) throws IOException { - return mergeFrom(input, ExtensionRegistryLite.getEmptyRegistry()); - } - - // Re-defined here for return type covariance. - @Override - public abstract BuilderType mergeFrom( - final CodedInputStream input, final ExtensionRegistryLite extensionRegistry) - throws IOException; - - @Override - public BuilderType mergeFrom(final ByteString data) throws InvalidProtocolBufferException { - try { - final CodedInputStream input = data.newCodedInput(); - mergeFrom(input); - input.checkLastTagWas(0); - return (BuilderType) this; - } catch (InvalidProtocolBufferException e) { - throw e; - } catch (IOException e) { - throw new RuntimeException( - "Reading from a ByteString threw an IOException (should " + - "never happen).", e); - } - } - - @Override - public BuilderType mergeFrom( - final ByteString data, final ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - try { - final CodedInputStream input = data.newCodedInput(); - mergeFrom(input, extensionRegistry); - input.checkLastTagWas(0); - return (BuilderType) this; - } catch (InvalidProtocolBufferException e) { - throw e; - } catch (IOException e) { - throw new RuntimeException( - "Reading from a ByteString threw an IOException (should " + - "never happen).", e); - } - } - - @Override - public BuilderType mergeFrom(final byte[] data) throws InvalidProtocolBufferException { - return mergeFrom(data, 0, data.length); - } - - @Override - public BuilderType mergeFrom(final byte[] data, final int off, final int len) - throws InvalidProtocolBufferException { - try { - final CodedInputStream input = - CodedInputStream.newInstance(data, off, len); - mergeFrom(input); - input.checkLastTagWas(0); - return (BuilderType) this; - } catch (InvalidProtocolBufferException e) { - throw e; - } catch (IOException e) { - throw new RuntimeException( - "Reading from a byte array threw an IOException (should " + - "never happen).", e); - } - } - - @Override - public BuilderType mergeFrom(final byte[] data, final ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return mergeFrom(data, 0, data.length, extensionRegistry); - } - - @Override - public BuilderType mergeFrom( - final byte[] data, - final int off, - final int len, - final ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - try { - final CodedInputStream input = - CodedInputStream.newInstance(data, off, len); - mergeFrom(input, extensionRegistry); - input.checkLastTagWas(0); - return (BuilderType) this; - } catch (InvalidProtocolBufferException e) { - throw e; - } catch (IOException e) { - throw new RuntimeException( - "Reading from a byte array threw an IOException (should " + - "never happen).", e); - } - } - - @Override - public BuilderType mergeFrom(final InputStream input) throws IOException { - final CodedInputStream codedInput = CodedInputStream.newInstance(input); - mergeFrom(codedInput); - codedInput.checkLastTagWas(0); - return (BuilderType) this; - } - - @Override - public BuilderType mergeFrom( - final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { - final CodedInputStream codedInput = CodedInputStream.newInstance(input); - mergeFrom(codedInput, extensionRegistry); - codedInput.checkLastTagWas(0); - return (BuilderType) this; - } - - /** - * An InputStream implementations which reads from some other InputStream - * but is limited to a particular number of bytes. Used by - * mergeDelimitedFrom(). This is intentionally package-private so that - * UnknownFieldSet can share it. - */ - static final class LimitedInputStream extends FilterInputStream { - private int limit; - - LimitedInputStream(InputStream in, int limit) { - super(in); - this.limit = limit; - } - - @Override - public int available() throws IOException { - return Math.min(super.available(), limit); - } - - @Override - public int read() throws IOException { - if (limit <= 0) { - return -1; - } - final int result = super.read(); - if (result >= 0) { - --limit; - } - return result; - } - - @Override - public int read(final byte[] b, final int off, int len) - throws IOException { - if (limit <= 0) { - return -1; - } - len = Math.min(len, limit); - final int result = super.read(b, off, len); - if (result >= 0) { - limit -= result; - } - return result; - } - - @Override - public long skip(final long n) throws IOException { - final long result = super.skip(Math.min(n, limit)); - if (result >= 0) { - limit -= result; - } - return result; - } - } - - @Override - public boolean mergeDelimitedFrom( - final InputStream input, final ExtensionRegistryLite extensionRegistry) throws IOException { - final int firstByte = input.read(); - if (firstByte == -1) { - return false; - } - final int size = CodedInputStream.readRawVarint32(firstByte, input); - final InputStream limitedInput = new LimitedInputStream(input, size); - mergeFrom(limitedInput, extensionRegistry); - return true; - } - - @Override - public boolean mergeDelimitedFrom(final InputStream input) throws IOException { - return mergeDelimitedFrom(input, - ExtensionRegistryLite.getEmptyRegistry()); - } - - @Override - @SuppressWarnings("unchecked") // isInstance takes care of this - public BuilderType mergeFrom(final MessageLite other) { - if (!getDefaultInstanceForType().getClass().isInstance(other)) { - throw new IllegalArgumentException( - "mergeFrom(MessageLite) can only merge messages of the same type."); - } - - return internalMergeFrom((MessageType) other); - } - - protected abstract BuilderType internalMergeFrom(MessageType message); - - /** - * Construct an UninitializedMessageException reporting missing fields in - * the given message. - */ - protected static UninitializedMessageException - newUninitializedMessageException(MessageLite message) { - return new UninitializedMessageException(message); - } - - /** - * Adds the {@code values} to the {@code list}. This is a helper method - * used by generated code. Users should ignore it. - * - * @throws NullPointerException if {@code values} or any of the elements of - * {@code values} is null. When that happens, some elements of - * {@code values} may have already been added to the result {@code list}. - */ - protected static void addAll(final Iterable values, - final Collection list) { - if (values == null) { - throw new NullPointerException(); - } - if (values instanceof LazyStringList) { - // For StringOrByteStringLists, check the underlying elements to avoid - // forcing conversions of ByteStrings to Strings. - checkForNullValues(((LazyStringList) values).getUnderlyingElements()); - list.addAll((Collection) values); - } else if (values instanceof Collection) { - checkForNullValues(values); - list.addAll((Collection) values); - } else { - for (final T value : values) { - if (value == null) { - throw new NullPointerException(); - } - list.add(value); - } - } - } - - private static void checkForNullValues(final Iterable values) { - for (final Object value : values) { - if (value == null) { - throw new NullPointerException(); - } - } - } - } -} diff --git a/java/src/main/java/com/google/protobuf/AbstractParser.java b/java/src/main/java/com/google/protobuf/AbstractParser.java deleted file mode 100644 index 66b0ee3b..00000000 --- a/java/src/main/java/com/google/protobuf/AbstractParser.java +++ /dev/null @@ -1,258 +0,0 @@ -// 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. - -package com.google.protobuf; - -import com.google.protobuf.AbstractMessageLite.Builder.LimitedInputStream; - -import java.io.IOException; -import java.io.InputStream; - -/** - * A partial implementation of the {@link Parser} interface which implements - * as many methods of that interface as possible in terms of other methods. - * - * Note: This class implements all the convenience methods in the - * {@link Parser} interface. See {@link Parser} for related javadocs. - * Subclasses need to implement - * {@link Parser#parsePartialFrom(CodedInputStream, ExtensionRegistryLite)} - * - * @author liujisi@google.com (Pherl Liu) - */ -public abstract class AbstractParser - implements Parser { - /** - * Creates an UninitializedMessageException for MessageType. - */ - private UninitializedMessageException - newUninitializedMessageException(MessageType message) { - if (message instanceof AbstractMessageLite) { - return ((AbstractMessageLite) message).newUninitializedMessageException(); - } - return new UninitializedMessageException(message); - } - - /** - * Helper method to check if message is initialized. - * - * @throws InvalidProtocolBufferException if it is not initialized. - * @return The message to check. - */ - private MessageType checkMessageInitialized(MessageType message) - throws InvalidProtocolBufferException { - if (message != null && !message.isInitialized()) { - throw newUninitializedMessageException(message) - .asInvalidProtocolBufferException() - .setUnfinishedMessage(message); - } - return message; - } - - private static final ExtensionRegistryLite EMPTY_REGISTRY - = ExtensionRegistryLite.getEmptyRegistry(); - - @Override - public MessageType parsePartialFrom(CodedInputStream input) - throws InvalidProtocolBufferException { - return parsePartialFrom(input, EMPTY_REGISTRY); - } - - @Override - public MessageType parseFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return checkMessageInitialized( - parsePartialFrom(input, extensionRegistry)); - } - - @Override - public MessageType parseFrom(CodedInputStream input) throws InvalidProtocolBufferException { - return parseFrom(input, EMPTY_REGISTRY); - } - - @Override - public MessageType parsePartialFrom(ByteString data, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - MessageType message; - try { - CodedInputStream input = data.newCodedInput(); - message = parsePartialFrom(input, extensionRegistry); - try { - input.checkLastTagWas(0); - } catch (InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(message); - } - return message; - } catch (InvalidProtocolBufferException e) { - throw e; - } - } - - @Override - public MessageType parsePartialFrom(ByteString data) throws InvalidProtocolBufferException { - return parsePartialFrom(data, EMPTY_REGISTRY); - } - - @Override - public MessageType parseFrom(ByteString data, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return checkMessageInitialized(parsePartialFrom(data, extensionRegistry)); - } - - @Override - public MessageType parseFrom(ByteString data) throws InvalidProtocolBufferException { - return parseFrom(data, EMPTY_REGISTRY); - } - - @Override - public MessageType parsePartialFrom( - byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - try { - CodedInputStream input = CodedInputStream.newInstance(data, off, len); - MessageType message = parsePartialFrom(input, extensionRegistry); - try { - input.checkLastTagWas(0); - } catch (InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(message); - } - return message; - } catch (InvalidProtocolBufferException e) { - throw e; - } - } - - @Override - public MessageType parsePartialFrom(byte[] data, int off, int len) - throws InvalidProtocolBufferException { - return parsePartialFrom(data, off, len, EMPTY_REGISTRY); - } - - @Override - public MessageType parsePartialFrom(byte[] data, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return parsePartialFrom(data, 0, data.length, extensionRegistry); - } - - @Override - public MessageType parsePartialFrom(byte[] data) throws InvalidProtocolBufferException { - return parsePartialFrom(data, 0, data.length, EMPTY_REGISTRY); - } - - @Override - public MessageType parseFrom( - byte[] data, int off, int len, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return checkMessageInitialized( - parsePartialFrom(data, off, len, extensionRegistry)); - } - - @Override - public MessageType parseFrom(byte[] data, int off, int len) - throws InvalidProtocolBufferException { - return parseFrom(data, off, len, EMPTY_REGISTRY); - } - - @Override - public MessageType parseFrom(byte[] data, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return parseFrom(data, 0, data.length, extensionRegistry); - } - - @Override - public MessageType parseFrom(byte[] data) throws InvalidProtocolBufferException { - return parseFrom(data, EMPTY_REGISTRY); - } - - @Override - public MessageType parsePartialFrom(InputStream input, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - CodedInputStream codedInput = CodedInputStream.newInstance(input); - MessageType message = parsePartialFrom(codedInput, extensionRegistry); - try { - codedInput.checkLastTagWas(0); - } catch (InvalidProtocolBufferException e) { - throw e.setUnfinishedMessage(message); - } - return message; - } - - @Override - public MessageType parsePartialFrom(InputStream input) throws InvalidProtocolBufferException { - return parsePartialFrom(input, EMPTY_REGISTRY); - } - - @Override - public MessageType parseFrom(InputStream input, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return checkMessageInitialized( - parsePartialFrom(input, extensionRegistry)); - } - - @Override - public MessageType parseFrom(InputStream input) throws InvalidProtocolBufferException { - return parseFrom(input, EMPTY_REGISTRY); - } - - @Override - public MessageType parsePartialDelimitedFrom( - InputStream input, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - int size; - try { - int firstByte = input.read(); - if (firstByte == -1) { - return null; - } - size = CodedInputStream.readRawVarint32(firstByte, input); - } catch (IOException e) { - throw new InvalidProtocolBufferException(e.getMessage()); - } - InputStream limitedInput = new LimitedInputStream(input, size); - return parsePartialFrom(limitedInput, extensionRegistry); - } - - @Override - public MessageType parsePartialDelimitedFrom(InputStream input) - throws InvalidProtocolBufferException { - return parsePartialDelimitedFrom(input, EMPTY_REGISTRY); - } - - @Override - public MessageType parseDelimitedFrom(InputStream input, ExtensionRegistryLite extensionRegistry) - throws InvalidProtocolBufferException { - return checkMessageInitialized( - parsePartialDelimitedFrom(input, extensionRegistry)); - } - - @Override - public MessageType parseDelimitedFrom(InputStream input) throws InvalidProtocolBufferException { - return parseDelimitedFrom(input, EMPTY_REGISTRY); - } -} diff --git a/java/src/main/java/com/google/protobuf/AbstractProtobufList.java b/java/src/main/java/com/google/protobuf/AbstractProtobufList.java deleted file mode 100644 index b17db6e0..00000000 --- a/java/src/main/java/com/google/protobuf/AbstractProtobufList.java +++ /dev/null @@ -1,180 +0,0 @@ -// 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. - -package com.google.protobuf; - -import com.google.protobuf.Internal.ProtobufList; - -import java.util.AbstractList; -import java.util.Collection; -import java.util.List; -import java.util.RandomAccess; - -/** - * An abstract implementation of {@link ProtobufList} which manages mutability semantics. All mutate - * methods must check if the list is mutable before proceeding. Subclasses must invoke - * {@link #ensureIsMutable()} manually when overriding those methods. - *

- * This implementation assumes all subclasses are array based, supporting random access. - */ -abstract class AbstractProtobufList extends AbstractList implements ProtobufList { - - protected static final int DEFAULT_CAPACITY = 10; - - /** - * Whether or not this list is modifiable. - */ - private boolean isMutable; - - /** - * Constructs a mutable list by default. - */ - AbstractProtobufList() { - isMutable = true; - } - - @Override - public boolean equals(Object o) { - if (o == this) { - return true; - } - if (!(o instanceof List)) { - return false; - } - // Handle lists that do not support RandomAccess as efficiently as possible by using an iterator - // based approach in our super class. Otherwise our index based approach will avoid those - // allocations. - if (!(o instanceof RandomAccess)) { - return super.equals(o); - } - - List other = (List) o; - final int size = size(); - if (size != other.size()) { - return false; - } - for (int i = 0; i < size; i++) { - if (!get(i).equals(other.get(i))) { - return false; - } - } - return true; - } - - @Override - public int hashCode() { - final int size = size(); - int hashCode = 1; - for (int i = 0; i < size; i++) { - hashCode = (31 * hashCode) + get(i).hashCode(); - } - return hashCode; - } - - @Override - public boolean add(E e) { - ensureIsMutable(); - return super.add(e); - } - - @Override - public void add(int index, E element) { - ensureIsMutable(); - super.add(index, element); - } - - @Override - public boolean addAll(Collection c) { - ensureIsMutable(); - return super.addAll(c); - } - - @Override - public boolean addAll(int index, Collection c) { - ensureIsMutable(); - return super.addAll(index, c); - } - - @Override - public void clear() { - ensureIsMutable(); - super.clear(); - } - - @Override - public boolean isModifiable() { - return isMutable; - } - - @Override - public final void makeImmutable() { - isMutable = false; - } - - @Override - public E remove(int index) { - ensureIsMutable(); - return super.remove(index); - } - - @Override - public boolean remove(Object o) { - ensureIsMutable(); - return super.remove(o); - } - - @Override - public boolean removeAll(Collection c) { - ensureIsMutable(); - return super.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) { - ensureIsMutable(); - return super.retainAll(c); - } - - @Override - public E set(int index, E element) { - ensureIsMutable(); - return super.set(index, element); - } - - /** - * Throws an {@link UnsupportedOperationException} if the list is immutable. Subclasses are - * responsible for invoking this method on mutate operations. - */ - protected void ensureIsMutable() { - if (!isMutable) { - throw new UnsupportedOperationException(); - } - } -} diff --git a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java deleted file mode 100644 index d535efb9..00000000 --- a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java +++ /dev/null @@ -1,51 +0,0 @@ -// 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. - -package com.google.protobuf; - -/** - *

Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel} - * is the blocking equivalent to {@link RpcChannel}. - * - * @author kenton@google.com Kenton Varda - * @author cpovirk@google.com Chris Povirk - */ -public interface BlockingRpcChannel { - /** - * Call the given method of the remote service and blocks until it returns. - * {@code callBlockingMethod()} is the blocking equivalent to - * {@link RpcChannel#callMethod}. - */ - Message callBlockingMethod( - Descriptors.MethodDescriptor method, - RpcController controller, - Message request, - Message responsePrototype) throws ServiceException; -} diff --git a/java/src/main/java/com/google/protobuf/BlockingService.java b/java/src/main/java/com/google/protobuf/BlockingService.java deleted file mode 100644 index d01f0b8f..00000000 --- a/java/src/main/java/com/google/protobuf/BlockingService.java +++ /dev/null @@ -1,64 +0,0 @@ -// 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. - -package com.google.protobuf; - -/** - * Blocking equivalent to {@link Service}. - * - * @author kenton@google.com Kenton Varda - * @author cpovirk@google.com Chris Povirk - */ -public interface BlockingService { - /** - * Equivalent to {@link Service#getDescriptorForType}. - */ - Descriptors.ServiceDescriptor getDescriptorForType(); - - /** - * Equivalent to {@link Service#callMethod}, except that - * {@code callBlockingMethod()} returns the result of the RPC or throws a - * {@link ServiceException} if there is a failure, rather than passing the - * information to a callback. - */ - Message callBlockingMethod(Descriptors.MethodDescriptor method, - RpcController controller, - Message request) throws ServiceException; - - /** - * Equivalent to {@link Service#getRequestPrototype}. - */ - Message getRequestPrototype(Descriptors.MethodDescriptor method); - - /** - * Equivalent to {@link Service#getResponsePrototype}. - */ - Message getResponsePrototype(Descriptors.MethodDescriptor method); -} From 4755bdc5f99f3c0b224eeb1539f27b131bfd915d Mon Sep 17 00:00:00 2001 From: Thomas Van Lenten Date: Tue, 10 May 2016 10:28:09 -0400 Subject: [PATCH 123/123] Declare an init and avoid passing NULL to initWithValue:count: Fixes https://github.com/google/protobuf/issues/1189 --- objectivec/GPBArray.h | 34 +++++++----- objectivec/GPBArray.m | 121 ++++++++++++++++++++++++------------------ 2 files changed, 90 insertions(+), 65 deletions(-) diff --git a/objectivec/GPBArray.h b/objectivec/GPBArray.h index 8c6396a9..afda57f3 100644 --- a/objectivec/GPBArray.h +++ b/objectivec/GPBArray.h @@ -53,9 +53,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValueArray:(GPBInt32Array *)array; + (instancetype)arrayWithCapacity:(NSUInteger)count; +- (instancetype)init NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValues:(const int32_t [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBInt32Array *)array; - (instancetype)initWithCapacity:(NSUInteger)count; @@ -92,9 +93,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValueArray:(GPBUInt32Array *)array; + (instancetype)arrayWithCapacity:(NSUInteger)count; +- (instancetype)init NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValues:(const uint32_t [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBUInt32Array *)array; - (instancetype)initWithCapacity:(NSUInteger)count; @@ -131,9 +133,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValueArray:(GPBInt64Array *)array; + (instancetype)arrayWithCapacity:(NSUInteger)count; +- (instancetype)init NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValues:(const int64_t [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBInt64Array *)array; - (instancetype)initWithCapacity:(NSUInteger)count; @@ -170,9 +173,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValueArray:(GPBUInt64Array *)array; + (instancetype)arrayWithCapacity:(NSUInteger)count; +- (instancetype)init NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValues:(const uint64_t [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBUInt64Array *)array; - (instancetype)initWithCapacity:(NSUInteger)count; @@ -209,9 +213,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValueArray:(GPBFloatArray *)array; + (instancetype)arrayWithCapacity:(NSUInteger)count; +- (instancetype)init NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValues:(const float [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBFloatArray *)array; - (instancetype)initWithCapacity:(NSUInteger)count; @@ -248,9 +253,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValueArray:(GPBDoubleArray *)array; + (instancetype)arrayWithCapacity:(NSUInteger)count; +- (instancetype)init NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValues:(const double [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBDoubleArray *)array; - (instancetype)initWithCapacity:(NSUInteger)count; @@ -287,9 +293,10 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValueArray:(GPBBoolArray *)array; + (instancetype)arrayWithCapacity:(NSUInteger)count; +- (instancetype)init NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValues:(const BOOL [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBBoolArray *)array; - (instancetype)initWithCapacity:(NSUInteger)count; @@ -330,12 +337,13 @@ NS_ASSUME_NONNULL_BEGIN + (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func capacity:(NSUInteger)count; -- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func; +- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func + NS_DESIGNATED_INITIALIZER; // Initializes the array, copying the values. - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func rawValues:(const int32_t [])values - count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; + count:(NSUInteger)count; - (instancetype)initWithValueArray:(GPBEnumArray *)array; - (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func capacity:(NSUInteger)count; @@ -422,9 +430,10 @@ NS_ASSUME_NONNULL_END //%+ (instancetype)arrayWithValueArray:(GPB##NAME##Array *)array; //%+ (instancetype)arrayWithCapacity:(NSUInteger)count; //% +//%- (instancetype)init NS_DESIGNATED_INITIALIZER; //%// Initializes the array, copying the values. //%- (instancetype)initWithValues:(const TYPE [])values -//% count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +//% count:(NSUInteger)count; //%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array; //%- (instancetype)initWithCapacity:(NSUInteger)count; //% @@ -455,12 +464,13 @@ NS_ASSUME_NONNULL_END //%+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func //% capacity:(NSUInteger)count; //% -//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func; +//%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func +//% NS_DESIGNATED_INITIALIZER; //% //%// Initializes the array, copying the values. //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func //% rawValues:(const TYPE [])values -//% count:(NSUInteger)count NS_DESIGNATED_INITIALIZER; +//% count:(NSUInteger)count; //%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array; //%- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func //% capacity:(NSUInteger)count; diff --git a/objectivec/GPBArray.m b/objectivec/GPBArray.m index 60b08ad1..426c7cbd 100644 --- a/objectivec/GPBArray.m +++ b/objectivec/GPBArray.m @@ -75,7 +75,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { //%@synthesize count = _count; //% //%+ (instancetype)array { -//% return [[[self alloc] initWithValues:NULL count:0] autorelease]; +//% return [[[self alloc] init] autorelease]; //%} //% //%+ (instancetype)arrayWithValue:(TYPE)value { @@ -93,7 +93,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { //%} //% //%- (instancetype)init { -//% return [self initWithValues:NULL count:0]; +//% self = [super init]; +//% // No work needed; +//% return self; //%} //% //%- (instancetype)initWithValueArray:(GPB##NAME##Array *)array { @@ -101,11 +103,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { //%} //% //%- (instancetype)initWithValues:(const TYPE [])values count:(NSUInteger)count { -//% self = [super init]; +//% self = [self init]; //% if (self) { //% if (count && values) { -//% _values = malloc(count * sizeof(TYPE)); -//% if (values != NULL) { +//% _values = reallocf(_values, count * sizeof(TYPE)); +//% if (_values != NULL) { //% _capacity = count; //% memcpy(_values, values, count * sizeof(TYPE)); //% _count = count; @@ -299,7 +301,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize count = _count; + (instancetype)array { - return [[[self alloc] initWithValues:NULL count:0] autorelease]; + return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithValue:(int32_t)value { @@ -317,7 +319,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValues:NULL count:0]; + self = [super init]; + // No work needed; + return self; } - (instancetype)initWithValueArray:(GPBInt32Array *)array { @@ -325,11 +329,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValues:(const int32_t [])values count:(NSUInteger)count { - self = [super init]; + self = [self init]; if (self) { if (count && values) { - _values = malloc(count * sizeof(int32_t)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(int32_t)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(int32_t)); _count = count; @@ -544,7 +548,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize count = _count; + (instancetype)array { - return [[[self alloc] initWithValues:NULL count:0] autorelease]; + return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithValue:(uint32_t)value { @@ -562,7 +566,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValues:NULL count:0]; + self = [super init]; + // No work needed; + return self; } - (instancetype)initWithValueArray:(GPBUInt32Array *)array { @@ -570,11 +576,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValues:(const uint32_t [])values count:(NSUInteger)count { - self = [super init]; + self = [self init]; if (self) { if (count && values) { - _values = malloc(count * sizeof(uint32_t)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(uint32_t)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(uint32_t)); _count = count; @@ -789,7 +795,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize count = _count; + (instancetype)array { - return [[[self alloc] initWithValues:NULL count:0] autorelease]; + return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithValue:(int64_t)value { @@ -807,7 +813,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValues:NULL count:0]; + self = [super init]; + // No work needed; + return self; } - (instancetype)initWithValueArray:(GPBInt64Array *)array { @@ -815,11 +823,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValues:(const int64_t [])values count:(NSUInteger)count { - self = [super init]; + self = [self init]; if (self) { if (count && values) { - _values = malloc(count * sizeof(int64_t)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(int64_t)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(int64_t)); _count = count; @@ -1034,7 +1042,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize count = _count; + (instancetype)array { - return [[[self alloc] initWithValues:NULL count:0] autorelease]; + return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithValue:(uint64_t)value { @@ -1052,7 +1060,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValues:NULL count:0]; + self = [super init]; + // No work needed; + return self; } - (instancetype)initWithValueArray:(GPBUInt64Array *)array { @@ -1060,11 +1070,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValues:(const uint64_t [])values count:(NSUInteger)count { - self = [super init]; + self = [self init]; if (self) { if (count && values) { - _values = malloc(count * sizeof(uint64_t)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(uint64_t)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(uint64_t)); _count = count; @@ -1279,7 +1289,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize count = _count; + (instancetype)array { - return [[[self alloc] initWithValues:NULL count:0] autorelease]; + return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithValue:(float)value { @@ -1297,7 +1307,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValues:NULL count:0]; + self = [super init]; + // No work needed; + return self; } - (instancetype)initWithValueArray:(GPBFloatArray *)array { @@ -1305,11 +1317,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValues:(const float [])values count:(NSUInteger)count { - self = [super init]; + self = [self init]; if (self) { if (count && values) { - _values = malloc(count * sizeof(float)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(float)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(float)); _count = count; @@ -1524,7 +1536,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize count = _count; + (instancetype)array { - return [[[self alloc] initWithValues:NULL count:0] autorelease]; + return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithValue:(double)value { @@ -1542,7 +1554,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValues:NULL count:0]; + self = [super init]; + // No work needed; + return self; } - (instancetype)initWithValueArray:(GPBDoubleArray *)array { @@ -1550,11 +1564,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValues:(const double [])values count:(NSUInteger)count { - self = [super init]; + self = [self init]; if (self) { if (count && values) { - _values = malloc(count * sizeof(double)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(double)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(double)); _count = count; @@ -1769,7 +1783,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize count = _count; + (instancetype)array { - return [[[self alloc] initWithValues:NULL count:0] autorelease]; + return [[[self alloc] init] autorelease]; } + (instancetype)arrayWithValue:(BOOL)value { @@ -1787,7 +1801,9 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValues:NULL count:0]; + self = [super init]; + // No work needed; + return self; } - (instancetype)initWithValueArray:(GPBBoolArray *)array { @@ -1795,11 +1811,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValues:(const BOOL [])values count:(NSUInteger)count { - self = [super init]; + self = [self init]; if (self) { if (count && values) { - _values = malloc(count * sizeof(BOOL)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(BOOL)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(BOOL)); _count = count; @@ -2015,15 +2031,11 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { @synthesize validationFunc = _validationFunc; + (instancetype)array { - return [[[self alloc] initWithValidationFunction:NULL - rawValues:NULL - count:0] autorelease]; + return [[[self alloc] initWithValidationFunction:NULL] autorelease]; } + (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func { - return [[[self alloc] initWithValidationFunction:func - rawValues:NULL - count:0] autorelease]; + return [[[self alloc] initWithValidationFunction:func] autorelease]; } + (instancetype)arrayWithValidationFunction:(GPBEnumValidationFunc)func @@ -2043,7 +2055,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)init { - return [self initWithValidationFunction:NULL rawValues:NULL count:0]; + return [self initWithValidationFunction:NULL]; } - (instancetype)initWithValueArray:(GPBEnumArray *)array { @@ -2053,18 +2065,21 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { } - (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func { - return [self initWithValidationFunction:func rawValues:NULL count:0]; + self = [super init]; + if (self) { + _validationFunc = (func != NULL ? func : ArrayDefault_IsValidValue); + } + return self; } - (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func rawValues:(const int32_t [])values count:(NSUInteger)count { - self = [super init]; + self = [self initWithValidationFunction:func]; if (self) { - _validationFunc = (func != NULL ? func : ArrayDefault_IsValidValue); if (count && values) { - _values = malloc(count * sizeof(int32_t)); - if (values != NULL) { + _values = reallocf(_values, count * sizeof(int32_t)); + if (_values != NULL) { _capacity = count; memcpy(_values, values, count * sizeof(int32_t)); _count = count; @@ -2081,7 +2096,7 @@ static BOOL ArrayDefault_IsValidValue(int32_t value) { - (instancetype)initWithValidationFunction:(GPBEnumValidationFunc)func capacity:(NSUInteger)count { - self = [self initWithValidationFunction:func rawValues:NULL count:0]; + self = [self initWithValidationFunction:func]; if (self && count) { [self internalResizeToCapacity:count]; }