Merge remote-tracking branch 'refs/remotes/google/master'

This commit is contained in:
Jos Hickson 2016-05-11 09:23:46 +01:00
commit 2b22b611a8
566 changed files with 52382 additions and 16802 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -10,7 +10,7 @@ os:
# The Objective C build needs Xcode 7.0 or later.
osx_image: xcode7.2
script:
- ./travis.sh $CONFIG
- ./tests.sh $CONFIG
env:
- CONFIG=cpp
- CONFIG=cpp_distcheck
@ -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

98
BUILD
View File

@ -15,16 +15,58 @@ 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({
":android": [],
"//conditions:default": ["-lpthread"],
})
load(
"protobuf",
"cc_proto_library",
"py_proto_library",
"internal_gen_well_known_protos_java",
"internal_protobuf_py_tests",
)
config_setting(
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",
},
)
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 = [
@ -54,7 +96,12 @@ cc_library(
"src/google/protobuf/wire_format_lite.cc",
],
hdrs = glob(["src/google/protobuf/**/*.h"]),
copts = COPTS,
copts = select({
":ios_armv7": IOS_ARM_COPTS,
":ios_armv7s": IOS_ARM_COPTS,
":ios_arm64": IOS_ARM_COPTS,
"//conditions:default": COPTS,
}),
includes = ["src/"],
linkopts = LINK_OPTS,
visibility = ["//visibility:public"],
@ -119,7 +166,12 @@ cc_library(
"src/google/protobuf/wrappers.pb.cc",
],
hdrs = glob(["src/**/*.h"]),
copts = COPTS,
copts = select({
":ios_armv7": IOS_ARM_COPTS,
":ios_armv7s": IOS_ARM_COPTS,
":ios_arm64": IOS_ARM_COPTS,
"//conditions:default": COPTS,
}),
includes = ["src/"],
linkopts = LINK_OPTS,
visibility = ["//visibility:public"],
@ -152,6 +204,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,
@ -208,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",
@ -318,6 +377,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",
@ -378,6 +439,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",
@ -402,7 +464,9 @@ 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_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",
"src/google/protobuf/repeated_field_unittest.cc",
@ -457,16 +521,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(
@ -479,6 +535,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
################################################################################
@ -495,6 +564,7 @@ py_library(
"python/google/protobuf/internal/test_util.py",
],
),
srcs_version = "PY2AND3",
imports = ["python"],
)
@ -579,6 +649,7 @@ py_proto_library(
include = "src",
default_runtime = "",
protoc = ":protoc",
srcs_version = "PY2AND3",
deps = [":protobuf_python"],
)
@ -591,6 +662,7 @@ py_proto_library(
include = "python",
default_runtime = ":protobuf_python",
protoc = ":protoc",
srcs_version = "PY2AND3",
deps = [":python_common_test_protos"],
)

View File

@ -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; \
@ -154,6 +158,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 \
@ -193,6 +198,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 +250,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 +263,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 +272,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 +305,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 \
@ -381,13 +394,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 \

View File

@ -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}',

View File

@ -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",
)

69
benchmarks/Makefile.am Normal file
View File

@ -0,0 +1,69 @@
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 = \
$(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
$(benchmarks_protoc_outputs): protoc_middleman
$(benchmarks_protoc_outputs_proto2): protoc_middleman2
CLEANFILES = \
$(benchmarks_protoc_outputs) \
$(benchmarks_protoc_outputs_proto2) \
protoc_middleman \
protoc_middleman2 \
dataset.*
MAINTAINERCLEANFILES = \
Makefile.in
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

28
benchmarks/README.md Normal file
View File

@ -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.

View File

@ -1,11 +1,14 @@
// Benchmark messages for proto2.
syntax = "proto2";
package benchmarks;
package benchmarks.proto2;
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];

View File

@ -0,0 +1,76 @@
// Benchmark messages for proto3.
syntax = "proto3";
package benchmarks.proto3;
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;
}

View File

@ -0,0 +1,63 @@
// 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_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 known message defined
// in those files.
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;
}

View File

@ -0,0 +1,117 @@
// 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 <fstream>
#include <iostream>
#include "benchmarks.pb.h"
using benchmarks::BenchmarkDataset;
using google::protobuf::Descriptor;
using google::protobuf::DescriptorPool;
using google::protobuf::Message;
using google::protobuf::MessageFactory;
std::set<std::string> 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<std::string>& 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::ofstream writer;
std::string fname = file_prefix + name + file_suffix;
writer.open(fname.c_str());
dataset.SerializeToOstream(&writer);
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<std::string> payloads;
payloads.push_back(payload);
WriteFileWithPayloads(name, message_name, payloads);
}
std::string ReadFile(const std::string& 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/ "
"directory.\n";
return std::string((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
}
int main() {
WriteFile("google_message1_proto3", "benchmarks.proto3.GoogleMessage1",
ReadFile("google_message1.dat"));
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.proto2.GoogleMessage2",
ReadFile("google_message2.dat"));
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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 " +

View File

@ -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();
}
}

View File

@ -17,11 +17,114 @@ protoc_outputs = \
conformance.pb.h
other_language_protoc_outputs = \
conformance.rb \
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
@ -30,6 +133,7 @@ bin_PROGRAMS = conformance-test-runner conformance-cpp
# automatically.
EXTRA_DIST = \
ConformanceJava.java \
ConformanceJavaLite.java \
README.md \
conformance.proto \
conformance_python.py \
@ -88,6 +192,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 +203,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 +215,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 +230,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 +256,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

View File

@ -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

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8"?>
<package>
<metadata>
<id>Google.Protobuf.Tools</id>
<title>Google Protocol Buffers tools</title>
<summary>Tools for Protocol Buffers - Google's data interchange format.</summary>
<description>See project site for more info.</description>
<version>3.0.0-beta2</version>
<authors>Google Inc.</authors>
<owners>protobuf-packages</owners>
<licenseUrl>https://github.com/google/protobuf/blob/master/LICENSE</licenseUrl>
<projectUrl>https://github.com/google/protobuf</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<releaseNotes>Tools for Protocol Buffers</releaseNotes>
<copyright>Copyright 2015, Google Inc.</copyright>
<tags>Protocol Buffers Binary Serialization Format Google proto proto3</tags>
</metadata>
<files>
<file src="protoc\windows_x86\protoc.exe" target="tools\windows_x86\protoc.exe" />
<file src="protoc\windows_x64\protoc.exe" target="tools\windows_x64\protoc.exe" />
<file src="protoc\linux_x86\protoc" target="tools\linux_x86\protoc" />
<file src="protoc\linux_x64\protoc" target="tools\linux_x64\protoc" />
<file src="protoc\macosx_x86\protoc" target="tools\macosx_x86\protoc" />
<file src="protoc\macosx_x64\protoc" target="tools\macosx_x64\protoc" />
<file src="..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
<file src="..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
</files>
</package>

View File

@ -116,4 +116,11 @@ message TestJsonFieldOrdering {
string o2_string = 3;
}
}
}
message TestJsonName {
// 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"];
}

View File

@ -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.");

View File

@ -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 {
/// <summary>Field number for the "type" field.</summary>
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;
}
}

View File

@ -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;
}

View File

@ -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 {
/// <summary>Field number for the "requested_output_format" field.</summary>
public const int RequestedOutputFormatFieldNumber = 3;
private global::Conformance.WireFormat requestedOutputFormat_ = global::Conformance.WireFormat.UNSPECIFIED;
private global::Conformance.WireFormat requestedOutputFormat_ = 0;
/// <summary>
/// Which format should the testee serialize its message to?
/// </summary>
@ -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 {
/// <summary>Field number for the "optional_nested_enum" field.</summary>
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 {
/// <summary>Field number for the "optional_foreign_enum" field.</summary>
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,
/// <summary>
/// Intentionally negative.
/// </summary>
NEG = -1,
[pbr::OriginalName("NEG")] Neg = -1,
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]

View File

@ -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);

View File

@ -58,7 +58,7 @@ namespace Google.Protobuf
new FieldCodecTestData<float>(FieldCodec.ForFloat(100), 1234.5f, "Float"),
new FieldCodecTestData<double>(FieldCodec.ForDouble(100), 1234567890.5d, "Double"),
new FieldCodecTestData<ForeignEnum>(
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<ForeignMessage>(
FieldCodec.ForMessage(100, ForeignMessage.Parser), new ForeignMessage { C = 10 }, "Message"),
};

View File

@ -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<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(data));
}
@ -720,4 +720,4 @@ namespace Google.Protobuf
Assert.AreEqual("{ \"c\": 31 }", writer.ToString());
}
}
}
}

View File

@ -59,5 +59,24 @@ 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);
// 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<TestJsonName>("{ \"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));
}
}
}

View File

@ -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));
}
@ -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)]
@ -481,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()
{

View File

@ -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")]
@ -810,6 +810,17 @@ namespace Google.Protobuf
Assert.AreEqual(original, parser.Parse<Any>(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<Any>(json));
}
[Test]
public void Any_UnknownType()
{
@ -886,9 +897,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 +933,4 @@ namespace Google.Protobuf
return '"' + text + '"';
}
}
}
}

View File

@ -249,7 +249,6 @@ namespace Google.Protobuf
[TestCase("[,", 1)]
[TestCase("{", 1)]
[TestCase("{,", 1)]
[TestCase("{", 1)]
[TestCase("{[", 1)]
[TestCase("{{", 1)]
[TestCase("{0", 1)]

View File

@ -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++)

View File

@ -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
};

View File

@ -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"
};
}
}
}
}

View File

@ -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());

View File

@ -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,
}
}

View File

@ -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

View File

@ -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
@ -63,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
@ -353,7 +356,7 @@ namespace UnitTest.Issues.TestProtos {
/// <summary>Field number for the "value" field.</summary>
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 {
@ -398,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;
@ -409,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);
}
@ -419,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);
@ -431,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_);
@ -617,7 +620,7 @@ namespace UnitTest.Issues.TestProtos {
/// <summary>Field number for the "EnumValue" field.</summary>
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_; }
@ -662,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;
}
@ -682,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);
}
@ -699,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);
@ -721,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_);
@ -1399,6 +1402,166 @@ namespace UnitTest.Issues.TestProtos {
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class TestJsonName : pb::IMessage<TestJsonName> {
private static readonly pb::MessageParser<TestJsonName> _parser = new pb::MessageParser<TestJsonName>(() => new TestJsonName());
public static pb::MessageParser<TestJsonName> 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);
}
/// <summary>Field number for the "name" field.</summary>
public const int NameFieldNumber = 1;
private string name_ = "";
/// <summary>
/// Message for testing the effects for of the json_name option
/// </summary>
public string Name {
get { return name_; }
set {
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "description" field.</summary>
public const int DescriptionFieldNumber = 2;
private string description_ = "";
public string Description {
get { return description_; }
set {
description_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "guid" field.</summary>
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
}

View File

@ -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,
}
/// <summary>
/// Test an enum that has multiple values with the same number.
/// </summary>
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,
}
/// <summary>
/// Test an enum with large, unordered values.
/// </summary>
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,
/// <summary>
/// In proto3, value 0 must be the first one specified
/// SPARSE_F = 0;
/// </summary>
SPARSE_G = 2,
[pbr::OriginalName("SPARSE_G")] SparseG = 2,
}
#endregion
@ -505,7 +505,7 @@ namespace Google.Protobuf.TestProtos {
/// <summary>Field number for the "single_nested_enum" field.</summary>
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 {
/// <summary>Field number for the "single_foreign_enum" field.</summary>
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 {
/// <summary>Field number for the "single_import_enum" field.</summary>
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,
/// <summary>
/// Intentionally negative.
/// </summary>
NEG = -1,
[pbr::OriginalName("NEG")] Neg = -1,
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
@ -2793,7 +2793,7 @@ namespace Google.Protobuf.TestProtos {
/// <summary>Field number for the "EnumField" field.</summary>
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 {
/// <summary>Field number for the "sparse_enum" field.</summary>
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;
}
}

View File

@ -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<TestAllTypes>();
Assert.AreEqual(message, unpacked);
}
[Test]
public void ToString_WithValues()
{

View File

@ -117,6 +117,7 @@
<Compile Include="Reflection\MethodDescriptor.cs" />
<Compile Include="Reflection\OneofAccessor.cs" />
<Compile Include="Reflection\OneofDescriptor.cs" />
<Compile Include="Reflection\OriginalNameAttribute.cs" />
<Compile Include="Reflection\PackageDescriptor.cs" />
<Compile Include="Reflection\PartialClasses.cs" />
<Compile Include="Reflection\ReflectionUtil.cs" />

View File

@ -23,7 +23,6 @@
<group targetFramework="xamarin.ios" />
<group targetFramework="monotouch" />
<group targetFramework="monoandroid" />
<!-- Dependencies for newer, more granular platforms (.NET Core etc) -->
<group targetFramework="dotnet">
<dependency id="System.Collections" version="4.0.0" />
@ -34,10 +33,12 @@
<dependency id="System.Linq.Expressions" version="4.0.0" />
<dependency id="System.ObjectModel" version="4.0.0" />
<dependency id="System.Reflection" version="4.0.0" />
<dependency id="System.Reflection.Extensions" version="4.0.0" />
<dependency id="System.Runtime" version="4.0.0" />
<dependency id="System.Runtime.Extensions" version="4.0.0" />
<dependency id="System.Text.Encoding" version="4.0.0" />
<dependency id="System.Text.RegularExpressions" version="4.0.0" />
<dependency id="System.Threading" version="4.0.0" />
</group>
</dependencies>
</metadata>
@ -49,18 +50,5 @@
<file src="bin/ReleaseSigned/Google.Protobuf.pdb" target="lib/dotnet" />
<file src="bin/ReleaseSigned/Google.Protobuf.xml" target="lib/dotnet" />
<file src="**\*.cs" target="src" />
<file src="..\..\..\cmake\Release\protoc.exe" target="tools" />
<file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\api.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\descriptor.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\duration.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\empty.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\field_mask.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\source_context.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\struct.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\timestamp.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\any.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\type.proto" target="tools\google\protobuf" />
<file src="..\..\..\src\google\protobuf\wrappers.proto" target="tools\google\protobuf" />
</files>
</package>

View File

@ -39,6 +39,7 @@ using Google.Protobuf.WellKnownTypes;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
namespace Google.Protobuf
{
@ -237,11 +238,13 @@ namespace Google.Protobuf
{
writer.Write(PropertySeparator);
}
WriteString(writer, ToCamelCase(accessor.Descriptor.Name));
WriteString(writer, accessor.Descriptor.JsonName);
writer.Write(NameValueSeparator);
WriteValue(writer, value);
first = false;
}
}
return !first;
}
@ -418,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
{
@ -563,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)
{
@ -604,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)
{
@ -875,5 +869,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<System.Type, Dictionary<object, string>> dictionaries
= new Dictionary<System.Type, Dictionary<object, string>>();
internal static string GetOriginalName(object value)
{
var enumType = value.GetType();
Dictionary<object, string> 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<object, string> GetNameMapping(System.Type enumType) =>
enumType.GetTypeInfo().DeclaredFields
.Where(f => f.IsStatic)
.ToDictionary(f => f.GetValue(null),
f => f.GetCustomAttributes<OriginalNameAttribute>()
.FirstOrDefault()
// If the attribute hasn't been applied, fall back to the name of the field.
?.Name ?? f.Name);
}
}
}

View File

@ -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)

View File

@ -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),
@ -1291,7 +1290,7 @@ namespace Google.Protobuf.Reflection {
/// <summary>Field number for the "label" field.</summary>
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 +1300,7 @@ namespace Google.Protobuf.Reflection {
/// <summary>Field number for the "type" field.</summary>
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;
/// <summary>
/// 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 +1428,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 +1456,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 +1494,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 +1531,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 +1623,59 @@ namespace Google.Protobuf.Reflection {
/// 0 is reserved for errors.
/// Order is weird for historical reasons.
/// </summary>
TYPE_DOUBLE = 1,
TYPE_FLOAT = 2,
[pbr::OriginalName("TYPE_DOUBLE")] Double = 1,
[pbr::OriginalName("TYPE_FLOAT")] Float = 2,
/// <summary>
/// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
/// negative values are likely.
/// </summary>
TYPE_INT64 = 3,
TYPE_UINT64 = 4,
[pbr::OriginalName("TYPE_INT64")] Int64 = 3,
[pbr::OriginalName("TYPE_UINT64")] Uint64 = 4,
/// <summary>
/// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
/// negative values are likely.
/// </summary>
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,
/// <summary>
/// Tag-delimited aggregate.
/// </summary>
TYPE_GROUP = 10,
[pbr::OriginalName("TYPE_GROUP")] Group = 10,
/// <summary>
/// Length-delimited aggregate.
/// </summary>
TYPE_MESSAGE = 11,
[pbr::OriginalName("TYPE_MESSAGE")] Message = 11,
/// <summary>
/// New in version 2.
/// </summary>
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,
/// <summary>
/// Uses ZigZag encoding.
/// </summary>
TYPE_SINT32 = 17,
[pbr::OriginalName("TYPE_SINT32")] Sint32 = 17,
/// <summary>
/// Uses ZigZag encoding.
/// </summary>
TYPE_SINT64 = 18,
[pbr::OriginalName("TYPE_SINT64")] Sint64 = 18,
}
internal enum Label {
/// <summary>
/// 0 is reserved for errors
/// </summary>
LABEL_OPTIONAL = 1,
LABEL_REQUIRED = 2,
[pbr::OriginalName("LABEL_OPTIONAL")] Optional = 1,
[pbr::OriginalName("LABEL_REQUIRED")] Required = 2,
/// <summary>
/// TODO(sanjay): Should we add LABEL_MAP?
/// </summary>
LABEL_REPEATED = 3,
[pbr::OriginalName("LABEL_REPEATED")] Repeated = 3,
}
}
@ -2563,7 +2562,6 @@ namespace Google.Protobuf.Reflection {
ccEnableArenas_ = other.ccEnableArenas_;
objcClassPrefix_ = other.objcClassPrefix_;
csharpNamespace_ = other.csharpNamespace_;
javananoUseDeprecatedPackage_ = other.javananoUseDeprecatedPackage_;
uninterpretedOption_ = other.uninterpretedOption_.Clone();
}
@ -2666,7 +2664,7 @@ namespace Google.Protobuf.Reflection {
/// <summary>Field number for the "optimize_for" field.</summary>
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 {
@ -2790,21 +2788,6 @@ namespace Google.Protobuf.Reflection {
}
}
/// <summary>Field number for the "javanano_use_deprecated_package" field.</summary>
public const int JavananoUseDeprecatedPackageFieldNumber = 38;
private bool javananoUseDeprecatedPackage_;
/// <summary>
/// Whether the nano proto compiler should generate in the deprecated non-nano
/// suffixed package.
/// </summary>
[global::System.ObsoleteAttribute()]
public bool JavananoUseDeprecatedPackage {
get { return javananoUseDeprecatedPackage_; }
set {
javananoUseDeprecatedPackage_ = value;
}
}
/// <summary>Field number for the "uninterpreted_option" field.</summary>
public const int UninterpretedOptionFieldNumber = 999;
private static readonly pb::FieldCodec<global::Google.Protobuf.Reflection.UninterpretedOption> _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;
}
@ -2854,7 +2836,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();
@ -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;
}
@ -2881,7 +2862,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);
}
@ -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);
}
@ -2953,7 +2930,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) {
@ -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;
}
@ -3006,7 +2980,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) {
@ -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;
@ -3125,15 +3092,15 @@ namespace Google.Protobuf.Reflection {
/// <summary>
/// Generate complete code for parsing, serialization,
/// </summary>
SPEED = 1,
[pbr::OriginalName("SPEED")] Speed = 1,
/// <summary>
/// etc.
/// </summary>
CODE_SIZE = 2,
[pbr::OriginalName("CODE_SIZE")] CodeSize = 2,
/// <summary>
/// Generate code using MessageLite and the lite runtime.
/// </summary>
LITE_RUNTIME = 3,
[pbr::OriginalName("LITE_RUNTIME")] LiteRuntime = 3,
}
}
@ -3436,7 +3403,7 @@ namespace Google.Protobuf.Reflection {
/// <summary>Field number for the "ctype" field.</summary>
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;
/// <summary>
/// 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 +3436,7 @@ namespace Google.Protobuf.Reflection {
/// <summary>Field number for the "jstype" field.</summary>
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;
/// <summary>
/// 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 +3558,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 +3573,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 +3589,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 +3602,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 +3628,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 +3696,24 @@ namespace Google.Protobuf.Reflection {
/// <summary>
/// Default mode.
/// </summary>
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 {
/// <summary>
/// Use the default type.
/// </summary>
JS_NORMAL = 0,
[pbr::OriginalName("JS_NORMAL")] JsNormal = 0,
/// <summary>
/// Use JavaScript strings.
/// </summary>
JS_STRING = 1,
[pbr::OriginalName("JS_STRING")] JsString = 1,
/// <summary>
/// Use JavaScript numbers.
/// </summary>
JS_NUMBER = 2,
[pbr::OriginalName("JS_NUMBER")] JsNumber = 2,
}
}

View File

@ -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
/// </summary>
public sealed class FieldDescriptor : DescriptorBase, IComparable<FieldDescriptor>
{
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;
/// <summary>
/// Get the field's containing message type.
/// </summary>
public MessageDescriptor ContainingType { get; }
/// <summary>
/// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
/// </summary>
public OneofDescriptor ContainingOneof { get; }
/// <summary>
/// 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 <c>json_name</c> option in the .proto file.
/// </summary>
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,14 +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;
}
/// <summary>
/// The brief name of the descriptor's target.
/// </summary>
public override string Name { get { return proto.Name; } }
internal FieldDescriptorProto Proto { get { return proto; } }
public override string Name => Proto.Name;
/// <summary>
/// Returns the accessor for this field.
@ -110,7 +124,7 @@ namespace Google.Protobuf.Reflection
/// and this property will return null.
/// </para>
/// </remarks>
public IFieldAccessor Accessor { get { return accessor; } }
public IFieldAccessor Accessor => accessor;
/// <summary>
/// Maps a field type as included in the .proto file to a FieldType.
@ -119,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");
@ -163,62 +177,32 @@ namespace Google.Protobuf.Reflection
/// <summary>
/// Returns <c>true</c> if this field is a repeated field; <c>false</c> otherwise.
/// </summary>
public bool IsRepeated
{
get { return Proto.Label == FieldDescriptorProto.Types.Label.LABEL_REPEATED; }
}
public bool IsRepeated => Proto.Label == FieldDescriptorProto.Types.Label.Repeated;
/// <summary>
/// Returns <c>true</c> if this field is a map field; <c>false</c> otherwise.
/// </summary>
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;
/// <summary>
/// Returns <c>true</c> if this field is a packed, repeated field; <c>false</c> otherwise.
/// </summary>
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; }
}
/// <summary>
/// Get the field's containing message type.
/// </summary>
public MessageDescriptor ContainingType
{
get { return containingType; }
}
/// <summary>
/// Returns the oneof containing this field, or <c>null</c> if it is not part of a oneof.
/// </summary>
public OneofDescriptor ContainingOneof
{
get { return containingOneof; }
}
Proto.Options == null || Proto.Options.Packed;
/// <summary>
/// Returns the type of the field.
/// </summary>
public FieldType FieldType
{
get { return fieldType; }
}
public FieldType FieldType => fieldType;
/// <summary>
/// Returns the field number declared in the proto file.
/// </summary>
public int FieldNumber
{
get { return Proto.Number; }
}
public int FieldNumber => Proto.Number;
/// <summary>
/// Compares this descriptor with another one, ordering in "canonical" order
@ -228,7 +212,7 @@ namespace Google.Protobuf.Reflection
/// </summary>
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.");
@ -331,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...)
@ -346,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)

View File

@ -102,8 +102,8 @@ namespace Google.Protobuf.Reflection
var map = new Dictionary<string, FieldDescriptor>();
foreach (var field in fields)
{
map[JsonFormatter.ToCamelCase(field.Name)] = field;
map[field.Name] = field;
map[field.JsonName] = field;
}
return new ReadOnlyDictionary<string, FieldDescriptor>(map);
}

View File

@ -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
{
/// <summary>
/// Specifies the original name (in the .proto file) of a named element,
/// such as an enum value.
/// </summary>
[AttributeUsage(AttributeTargets.Field)]
public class OriginalNameAttribute : Attribute
{
/// <summary>
/// The name of the element in the .proto file.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Constructs a new attribute instance for the given name.
/// </summary>
/// <param name="name">The name of the element in the .proto file.</param>
public OriginalNameAttribute(string name)
{
Name = ProtoPreconditions.CheckNotNull(name, nameof(name));
}
}
}

View File

@ -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
/// <summary>
/// `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(&amp;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_ = "";
/// <summary>
/// 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:
@ -110,6 +139,8 @@ namespace Google.Protobuf.WellKnownTypes {
/// * 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
@ -132,7 +163,7 @@ namespace Google.Protobuf.WellKnownTypes {
public const int ValueFieldNumber = 2;
private pb::ByteString value_ = pb::ByteString.Empty;
/// <summary>
/// Must be valid serialized data of the above specified type.
/// Must be a valid serialized protocol buffer of the above specified type.
/// </summary>
public pb::ByteString Value {
get { return value_; }

View File

@ -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;
/// <summary>
/// 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.
/// </summary>
/// <param name="typeUrl">The URL to extract the type name from</param>
/// <returns>The type name</returns>
internal static string GetTypeName(string typeUrl)
{
return "type.googleapis.com/" + descriptor.FullName;
int lastSlash = typeUrl.LastIndexOf('/');
return lastSlash == -1 ? "" : typeUrl.Substring(lastSlash + 1);
}
/// <summary>
@ -55,25 +71,37 @@ namespace Google.Protobuf.WellKnownTypes
// Note: this doesn't perform as well is it might. We could take a MessageParser<T> 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;
}
/// <summary>
/// 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".
/// </summary>
/// <param name="message">The message to pack.</param>
/// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
public static Any Pack(IMessage message)
public static Any Pack(IMessage message) => Pack(message, DefaultPrefix);
/// <summary>
/// Packs the specified message into an Any message using the specified type URL prefix.
/// </summary>
/// <param name="message">The message to pack.</param>
/// <param name="typeUrlPrefix">The prefix for the type URL.</param>
/// <returns>An Any message with the content and type URL of <paramref name="message"/>.</returns>
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()
};
}
}
}

View File

@ -185,7 +185,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// <summary>Field number for the "syntax" field.</summary>
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;
/// <summary>
/// The source syntax of the service.
/// </summary>
@ -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 {
/// <summary>Field number for the "syntax" field.</summary>
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;
/// <summary>
/// The source syntax of this method.
/// </summary>
@ -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;
}
}

View File

@ -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[] {

View File

@ -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[] {

View File

@ -86,7 +86,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// 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
@ -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.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class FieldMask : pb::IMessage<FieldMask> {

View File

@ -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[] {
@ -59,7 +60,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// <summary>
/// Null value.
/// </summary>
NULL_VALUE = 0,
[pbr::OriginalName("NULL_VALUE")] NullValue = 0,
}
#endregion
@ -108,7 +109,7 @@ namespace Google.Protobuf.WellKnownTypes {
= new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>.Codec(pb::FieldCodec.ForString(10), pb::FieldCodec.ForMessage(18, global::Google.Protobuf.WellKnownTypes.Value.Parser), 10);
private readonly pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> fields_ = new pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value>();
/// <summary>
/// Map of dynamically typed values.
/// Unordered map of dynamically typed values.
/// </summary>
public pbc::MapField<string, global::Google.Protobuf.WellKnownTypes.Value> Fields {
get { return fields_; }
@ -234,7 +235,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// Represents a null value.
/// </summary>
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;

View File

@ -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[] {

View File

@ -79,11 +79,11 @@ namespace Google.Protobuf.WellKnownTypes {
/// <summary>
/// Syntax `proto2`.
/// </summary>
SYNTAX_PROTO2 = 0,
[pbr::OriginalName("SYNTAX_PROTO2")] Proto2 = 0,
/// <summary>
/// Syntax `proto3`.
/// </summary>
SYNTAX_PROTO3 = 1,
[pbr::OriginalName("SYNTAX_PROTO3")] Proto3 = 1,
}
#endregion
@ -188,7 +188,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// <summary>Field number for the "syntax" field.</summary>
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;
/// <summary>
/// The source syntax.
/// </summary>
@ -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 {
/// <summary>Field number for the "kind" field.</summary>
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;
/// <summary>
/// The field type.
/// </summary>
@ -384,7 +384,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// <summary>Field number for the "cardinality" field.</summary>
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;
/// <summary>
/// The field cardinality.
/// </summary>
@ -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 {
/// <summary>
/// Field type unknown.
/// </summary>
TYPE_UNKNOWN = 0,
[pbr::OriginalName("TYPE_UNKNOWN")] TypeUnknown = 0,
/// <summary>
/// Field type double.
/// </summary>
TYPE_DOUBLE = 1,
[pbr::OriginalName("TYPE_DOUBLE")] TypeDouble = 1,
/// <summary>
/// Field type float.
/// </summary>
TYPE_FLOAT = 2,
[pbr::OriginalName("TYPE_FLOAT")] TypeFloat = 2,
/// <summary>
/// Field type int64.
/// </summary>
TYPE_INT64 = 3,
[pbr::OriginalName("TYPE_INT64")] TypeInt64 = 3,
/// <summary>
/// Field type uint64.
/// </summary>
TYPE_UINT64 = 4,
[pbr::OriginalName("TYPE_UINT64")] TypeUint64 = 4,
/// <summary>
/// Field type int32.
/// </summary>
TYPE_INT32 = 5,
[pbr::OriginalName("TYPE_INT32")] TypeInt32 = 5,
/// <summary>
/// Field type fixed64.
/// </summary>
TYPE_FIXED64 = 6,
[pbr::OriginalName("TYPE_FIXED64")] TypeFixed64 = 6,
/// <summary>
/// Field type fixed32.
/// </summary>
TYPE_FIXED32 = 7,
[pbr::OriginalName("TYPE_FIXED32")] TypeFixed32 = 7,
/// <summary>
/// Field type bool.
/// </summary>
TYPE_BOOL = 8,
[pbr::OriginalName("TYPE_BOOL")] TypeBool = 8,
/// <summary>
/// Field type string.
/// </summary>
TYPE_STRING = 9,
[pbr::OriginalName("TYPE_STRING")] TypeString = 9,
/// <summary>
/// Field type group. Proto2 syntax only, and deprecated.
/// </summary>
TYPE_GROUP = 10,
[pbr::OriginalName("TYPE_GROUP")] TypeGroup = 10,
/// <summary>
/// Field type message.
/// </summary>
TYPE_MESSAGE = 11,
[pbr::OriginalName("TYPE_MESSAGE")] TypeMessage = 11,
/// <summary>
/// Field type bytes.
/// </summary>
TYPE_BYTES = 12,
[pbr::OriginalName("TYPE_BYTES")] TypeBytes = 12,
/// <summary>
/// Field type uint32.
/// </summary>
TYPE_UINT32 = 13,
[pbr::OriginalName("TYPE_UINT32")] TypeUint32 = 13,
/// <summary>
/// Field type enum.
/// </summary>
TYPE_ENUM = 14,
[pbr::OriginalName("TYPE_ENUM")] TypeEnum = 14,
/// <summary>
/// Field type sfixed32.
/// </summary>
TYPE_SFIXED32 = 15,
[pbr::OriginalName("TYPE_SFIXED32")] TypeSfixed32 = 15,
/// <summary>
/// Field type sfixed64.
/// </summary>
TYPE_SFIXED64 = 16,
[pbr::OriginalName("TYPE_SFIXED64")] TypeSfixed64 = 16,
/// <summary>
/// Field type sint32.
/// </summary>
TYPE_SINT32 = 17,
[pbr::OriginalName("TYPE_SINT32")] TypeSint32 = 17,
/// <summary>
/// Field type sint64.
/// </summary>
TYPE_SINT64 = 18,
[pbr::OriginalName("TYPE_SINT64")] TypeSint64 = 18,
}
/// <summary>
@ -794,19 +794,19 @@ namespace Google.Protobuf.WellKnownTypes {
/// <summary>
/// For fields with unknown cardinality.
/// </summary>
CARDINALITY_UNKNOWN = 0,
[pbr::OriginalName("CARDINALITY_UNKNOWN")] Unknown = 0,
/// <summary>
/// For optional fields.
/// </summary>
CARDINALITY_OPTIONAL = 1,
[pbr::OriginalName("CARDINALITY_OPTIONAL")] Optional = 1,
/// <summary>
/// For required fields. Proto2 syntax only.
/// </summary>
CARDINALITY_REQUIRED = 2,
[pbr::OriginalName("CARDINALITY_REQUIRED")] Required = 2,
/// <summary>
/// For repeated fields.
/// </summary>
CARDINALITY_REPEATED = 3,
[pbr::OriginalName("CARDINALITY_REPEATED")] Repeated = 3,
}
}
@ -900,7 +900,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// <summary>Field number for the "syntax" field.</summary>
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;
/// <summary>
/// The source syntax.
/// </summary>
@ -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;
}
}

View File

@ -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[] {

674
docs/swift/DesignDoc.md Normal file
View File

@ -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 Apples 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 Swifts 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 Swifts
`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 doesnt 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 (Swifts 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 Apples 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.
Swifts 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 dont 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, its
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 its 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.

147
docs/third_party.md Normal file
View File

@ -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)

View File

@ -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%.*}
@ -92,9 +95,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

View File

@ -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<String> 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<BuilderType extends Builder>
extends AbstractMessageLite.Builder<BuilderType>
public static abstract class Builder<BuilderType extends Builder<BuilderType>>
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<FieldDescriptor, Object> entry :
getAllFields().entrySet()) {
@ -322,14 +331,22 @@ public abstract class AbstractMessage extends AbstractMessageLite
return (BuilderType) this;
}
@Override
public List<String> 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

View File

@ -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<MessageType, BuilderType>,
BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
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<BuilderType extends Builder>
public abstract static class Builder<
MessageType extends AbstractMessageLite<MessageType, BuilderType>,
BuilderType extends Builder<MessageType, BuilderType>>
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

View File

@ -78,26 +78,27 @@ public abstract class AbstractParser<MessageType extends MessageLite>
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<MessageType extends MessageLite>
}
}
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<MessageType extends MessageLite>
}
}
@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<MessageType extends MessageLite>
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<MessageType extends MessageLite>
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);
}
}

View File

@ -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.
* <p>
* This implementation assumes all subclasses are array based, supporting random access.
*/
abstract class AbstractProtobufList<E> extends AbstractList<E> implements ProtobufList<E> {
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<E> extends AbstractList<E> 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();

View File

@ -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<Boolean> 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<Boolean> 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);

View File

@ -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<SoftReference<byte[]>> BUFFER =
new ThreadLocal<SoftReference<byte[]>>();
/**
* 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<byte[]> sr = BUFFER.get();
return sr == null ? null : sr.get();
}
private static void setBuffer(byte[] value) {
BUFFER.set(new SoftReference<byte[]>(value));
}
}

View File

@ -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:
*
* <p/><b>Traditional write operations:</b>
* (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.
*
* <p/><b>Lazy write operations:</b> 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.
*
* <p>NOTE: This method <strong>MUST NOT</strong> 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.
*
* <p>NOTE: This method <strong>MUST NOT</strong> 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.
*
* <p>NOTE: This method <strong>MUST NOT</strong> 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.
*
* <p>NOTE: This method <strong>MUST NOT</strong> 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;
}

View File

@ -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<Byte>, Serializable {
* Empty {@code ByteString}.
*/
public static final ByteString EMPTY = new LiteralByteString(Internal.EMPTY_BYTE_ARRAY);
/**
* An interface to efficiently copy {@code byte[]}.
*
* <p>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<Byte>, 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<Byte>, 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<Byte>, 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<Byte>, Serializable {
}
/**
* Writes the complete contents of this byte string to
* the specified output stream argument.
*
* <p>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<Byte>, 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<Byte>, 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}.
*
* <p>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<Byte>, 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<Byte>, 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<Byte>, 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);

View File

@ -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;

View File

@ -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
@ -272,7 +284,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 {
@ -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 {
* </pre>
* {@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(
@ -1123,7 +1168,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; }
@ -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) {

View File

@ -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<Double> 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<Double> 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

View File

@ -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<FieldDescriptor, Object> 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<DynamicMessage> getParserForType() {
return new AbstractParser<DynamicMessage>() {
@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<FieldDescriptor, Object> 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) {

View File

@ -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;

View File

@ -42,6 +42,7 @@ public abstract class Extension<ContainingType extends MessageLite, Type>
public abstract Descriptors.FieldDescriptor getDescriptor();
/** Returns whether or not this extension is a Lite Extension. */
@Override
final boolean isLite() {
return false;
}

View File

@ -120,6 +120,25 @@ final class FieldSet<FieldDescriptorType extends
public boolean isImmutable() {
return isImmutable;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof FieldSet)) {
return false;
}
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

View File

@ -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<Float> 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<Float> 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<Float> 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

View File

@ -80,6 +80,7 @@ public abstract class GeneratedMessage extends AbstractMessage
unknownFields = builder.getUnknownFields();
}
@Override
public Parser<? extends GeneratedMessage> 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<FieldDescriptor, Object> 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 <BuilderType extends Builder>
public abstract static class Builder <BuilderType extends Builder<BuilderType>>
extends AbstractMessage.Builder<BuilderType> {
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<FieldDescriptor, Object> 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. */
@ -795,6 +797,8 @@ public abstract class GeneratedMessage extends AbstractMessage
extends GeneratedMessage
implements ExtendableMessageOrBuilder<MessageType> {
private static final long serialVersionUID = 1L;
private final FieldSet<FieldDescriptor> extensions;
protected ExtendableMessage() {
@ -821,9 +825,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 <Type> boolean hasExtension(
final ExtensionLite<MessageType, Type> extensionLite) {
@Override
public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@ -831,7 +834,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 <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extensionLite) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@ -842,10 +845,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> Type getExtension(
final ExtensionLite<MessageType, Type> extensionLite) {
public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@ -867,11 +869,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> Type getExtension(
final ExtensionLite<MessageType, List<Type>> extensionLite,
final int index) {
final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@ -1019,7 +1020,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());
@ -1103,7 +1106,7 @@ public abstract class GeneratedMessage extends AbstractMessage
@SuppressWarnings("unchecked")
public abstract static class ExtendableBuilder<
MessageType extends ExtendableMessage,
BuilderType extends ExtendableBuilder>
BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
extends Builder<BuilderType>
implements ExtendableMessageOrBuilder<MessageType> {
@ -1155,9 +1158,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 <Type> boolean hasExtension(
final ExtensionLite<MessageType, Type> extensionLite) {
@Override
public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@ -1165,7 +1167,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 <Type> int getExtensionCount(
final ExtensionLite<MessageType, List<Type>> extensionLite) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
@ -1176,9 +1178,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> Type getExtension(
final ExtensionLite<MessageType, Type> extensionLite) {
@Override
public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
Extension<MessageType, Type> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@ -1200,10 +1201,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> Type getExtension(
final ExtensionLite<MessageType, List<Type>> extensionLite,
final int index) {
final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
verifyExtensionContainingType(extension);
@ -1456,10 +1456,9 @@ public abstract class GeneratedMessage extends AbstractMessage
// obtained.
return new GeneratedExtension<ContainingType, Type>(
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,
@ -1487,6 +1486,7 @@ public abstract class GeneratedMessage extends AbstractMessage
private volatile FieldDescriptor descriptor;
protected abstract FieldDescriptor loadDescriptor();
@Override
public FieldDescriptor getDescriptor() {
if (descriptor == null) {
synchronized (this) {
@ -1516,6 +1516,7 @@ public abstract class GeneratedMessage extends AbstractMessage
// obtained.
return new GeneratedExtension<ContainingType, Type>(
new CachedDescriptorRetriever() {
@Override
protected FieldDescriptor loadDescriptor() {
return scope.getDescriptorForType().findFieldByName(name);
}
@ -1542,17 +1543,18 @@ public abstract class GeneratedMessage extends AbstractMessage
// used to obtain the extension's FieldDescriptor.
return new GeneratedExtension<ContainingType, Type>(
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);
}
}
},
@ -1634,12 +1636,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;
@ -1649,6 +1652,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(
@ -1661,10 +1665,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;
}
@ -1675,7 +1681,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();
@ -1700,7 +1706,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()) {
@ -1724,7 +1730,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();
@ -1748,7 +1754,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()) {
@ -1759,22 +1765,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()) {
@ -2124,49 +2130,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) {
@ -2176,6 +2190,7 @@ public abstract class GeneratedMessage extends AbstractMessage
}
return (Boolean) invokeOrDie(hasMethod, message);
}
@Override
public boolean has(GeneratedMessage.Builder builder) {
if (!hasHasMethod) {
if (isOneofField) {
@ -2185,27 +2200,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.");
}
@ -2249,18 +2269,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.
@ -2271,54 +2296,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.");
}
@ -2355,6 +2390,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++) {
@ -2363,6 +2399,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++) {
@ -2371,14 +2408,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) {
@ -2386,63 +2426,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.");
}

View File

@ -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<Integer> 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<Integer> 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<Integer> 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

View File

@ -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;
/**
@ -51,10 +52,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 +409,7 @@ public class Internal {
public static final CodedInputStream EMPTY_CODED_INPUT_STREAM =
CodedInputStream.newInstance(EMPTY_BYTE_ARRAY);
/**
* Provides an immutable view of {@code List<T>} around a {@code List<F>}.
*
@ -454,10 +458,13 @@ public class Internal {
public static <T extends EnumLite> Converter<Integer, T> newEnumConverter(
final EnumLiteMap<T> enumMap, final T unrecognizedValue) {
return new Converter<Integer, T>() {
@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();
}
@ -570,8 +577,10 @@ public class Internal {
/**
* Extends {@link List} to add the capability to make the list immutable and inspect if it is
* modifiable.
* <p>
* All implementations must support efficient random access.
*/
public static interface ProtobufList<E> extends List<E> {
public static interface ProtobufList<E> extends List<E>, RandomAccess {
/**
* Makes this list immutable. All subsequent modifications will throw an
@ -583,6 +592,11 @@ public 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<E> mutableCopyWithCapacity(int capacity);
}
/**
@ -597,14 +611,20 @@ public 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);
}
/**
@ -619,14 +639,20 @@ public 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);
}
/**
@ -641,14 +667,20 @@ public 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);
}
/**
@ -663,14 +695,20 @@ public 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);
}
/**
@ -685,13 +723,19 @@ public 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);
}
}

View File

@ -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;
@ -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<K, Object> next() {
Entry<K, ?> entry = iterator.next();
if (entry.getValue() instanceof LazyField) {
@ -146,7 +146,7 @@ public class LazyField extends LazyFieldLite {
return (Entry<K, Object>) entry;
}
// @Override
@Override
public void remove() {
iterator.remove();
}

View File

@ -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;
@ -94,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.
*/
@ -230,6 +308,46 @@ public class LazyFieldLite {
return;
}
}
/**
* Merges another instance's contents from a stream.
*
* <p>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 +377,12 @@ public class LazyFieldLite {
* parsed. Be careful when using this method.
*/
public int getSerializedSize() {
if (delayedBytes != null) {
return delayedBytes.size();
} else if (memoizedBytes != null) {
// 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) {
return delayedBytes.size();
} else if (value != null) {
return value.getSerializedSize();
} else {
@ -274,12 +394,14 @@ 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;
}
// 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;
}
synchronized (this) {
if (memoizedBytes != null) {
return memoizedBytes;
@ -311,18 +433,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;
}
}
}

View File

@ -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;
/**
@ -64,7 +64,7 @@ import java.util.RandomAccess;
*/
public class LazyStringArrayList extends AbstractProtobufList<String>
implements LazyStringList, RandomAccess {
private static final LazyStringArrayList EMPTY_LIST = new LazyStringArrayList();
static {
EMPTY_LIST.makeImmutable();
@ -80,11 +80,11 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
private final List<Object> list;
public LazyStringArrayList() {
list = new ArrayList<Object>();
this(DEFAULT_CAPACITY);
}
public LazyStringArrayList(int intialCapacity) {
list = new ArrayList<Object>(intialCapacity);
this(new ArrayList<Object>(intialCapacity));
}
public LazyStringArrayList(LazyStringList from) {
@ -93,7 +93,21 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
}
public LazyStringArrayList(List<String> from) {
list = new ArrayList<Object>(from);
this(new ArrayList<Object>(from));
}
private LazyStringArrayList(ArrayList<Object> list) {
this.list = list;
}
@Override
public LazyStringArrayList mutableCopyWithCapacity(int capacity) {
if (capacity < size()) {
throw new IllegalArgumentException();
}
ArrayList<Object> newList = new ArrayList<Object>(capacity);
newList.addAll(list);
return new LazyStringArrayList(newList);
}
@Override
@ -170,7 +184,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return ret;
}
// @Override
@Override
public boolean addAllByteString(Collection<? extends ByteString> values) {
ensureIsMutable();
boolean ret = list.addAll(values);
@ -178,7 +192,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
return ret;
}
// @Override
@Override
public boolean addAllByteArray(Collection<byte[]> c) {
ensureIsMutable();
boolean ret = list.addAll(c);
@ -201,14 +215,14 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
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<String>
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<String>
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<String>
return b;
}
// @Override
@Override
public void set(int index, ByteString s) {
setAndReturn(index, s);
}
@ -250,7 +264,7 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
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<String>
}
}
// @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<String>
}
}
// @Override
@Override
public List<byte[]> asByteArrayList() {
return new ByteArrayListView(this);
}
@ -393,12 +407,12 @@ public class LazyStringArrayList extends AbstractProtobufList<String>
}
}
// @Override
@Override
public List<ByteString> asByteStringList() {
return new ByteStringListView(this);
}
// @Override
@Override
public LazyStringList getUnmodifiableView() {
if (isModifiable()) {
return new UnmodifiableLazyStringList(this);

View File

@ -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<Long> 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<Long> 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<Long> 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

View File

@ -41,7 +41,8 @@ import java.io.IOException;
*
* Protobuf internal. Users shouldn't use.
*/
public class MapEntryLite<K, V> extends AbstractMessageLite {
public class MapEntryLite<K, V>
extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>> {
private static class Metadata<K, V> {
public final MapEntryLite<K, V> defaultInstance;
public final WireFormat.FieldType keyType;
@ -233,7 +234,7 @@ public class MapEntryLite<K, V> extends AbstractMessageLite {
* Builder used to create {@link MapEntryLite} messages.
*/
public static class Builder<K, V>
extends AbstractMessageLite.Builder<Builder<K, V>> {
extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> {
private final Metadata<K, V> metadata;
private K key;
private V value;
@ -327,5 +328,10 @@ public class MapEntryLite<K, V> extends AbstractMessageLite {
this.value = entry.value;
return this;
}
@Override
protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -93,15 +93,18 @@ public class MapField<K, V> 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<K, V> map) {
MapEntry<K, V> entry = (MapEntry<K, V>) message;
map.put(entry.getKey(), entry.getValue());
}
@Override
public Message getMessageDefaultInstance() {
return defaultEntry;
}

View File

@ -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<? extends Message> 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;
}
}

View File

@ -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:<br>
* * For singular primitive fields, if the field is set in {@code other},
* then {@code other}'s value overwrites the value in this message.<br>
* * 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.<br>
* * 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.

View File

@ -0,0 +1,239 @@
// 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.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 {
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
* the objcet instance. This acts as an indicator that this should not be relied on for
* comparisons.
*
* <p>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<String, Method> nameToNoArgMethod = new HashMap<String, Method>();
Map<String, Method> nameToMethod = new HashMap<String, Method>();
Set<String> getters = new TreeSet<String>();
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 (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,
camelCaseToSnakeCase(camelCase),
GeneratedMessageLite.invokeOrDie(listMethod, messageLite));
continue;
}
}
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 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;
}
}
if (messageLite instanceof GeneratedMessageLite.ExtendableMessage) {
Iterator<Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object>> iter =
((GeneratedMessageLite.ExtendableMessage<?, ?>) messageLite).extensions.iterator();
while (iter.hasNext()) {
Map.Entry<GeneratedMessageLite.ExtensionDescriptor, Object> entry = iter.next();
printField(buffer, indent, "[" + entry.getKey().getNumber() + "]", entry.getValue());
}
}
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.
*
* <p>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());
}
}
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 builder.toString();
}
}

View File

@ -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();
/**

View File

@ -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");
}
}
/**

View File

@ -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

View File

@ -30,7 +30,6 @@
package com.google.protobuf;
import java.io.IOException;
import java.io.InputStream;
/**

View File

@ -38,7 +38,7 @@ import java.util.List;
/**
* Implements {@link ProtobufList} for non-primitive and {@link String} types.
*/
class ProtobufArrayList<E> extends AbstractProtobufList<E> {
final class ProtobufArrayList<E> extends AbstractProtobufList<E> {
private static final ProtobufArrayList<Object> EMPTY_LIST = new ProtobufArrayList<Object>();
static {
@ -51,17 +51,23 @@ class ProtobufArrayList<E> extends AbstractProtobufList<E> {
}
private final List<E> list;
ProtobufArrayList() {
list = new ArrayList<E>();
this(new ArrayList<E>(DEFAULT_CAPACITY));
}
ProtobufArrayList(List<E> toCopy) {
list = new ArrayList<E>(toCopy);
private ProtobufArrayList(List<E> list) {
this.list = list;
}
ProtobufArrayList(int capacity) {
list = new ArrayList<E>(capacity);
@Override
public ProtobufArrayList<E> mutableCopyWithCapacity(int capacity) {
if (capacity < size()) {
throw new IllegalArgumentException();
}
List<E> newList = new ArrayList<E>(capacity);
newList.addAll(list);
return new ProtobufArrayList<E>(newList);
}
@Override

View File

@ -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();
/**

View File

@ -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);
}

View File

@ -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}.
*
* <p>Most of the operation here is inspired by the now-famous paper <a
* href="http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
* href="https://web.archive.org/web/20060202015456/http://www.cs.ubc.ca/local/reading/proceedings/spe91-95/spe/vol25/issue12/spe986.pdf">
* BAP95 </a> 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.
*
* <p>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 {
*
* <p>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<ByteBuffer> 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<ByteBuffer> result = new ArrayList<ByteBuffer>();
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() {

Some files were not shown because too many files have changed in this diff Show More