ADD: added new version of protobuf

This commit is contained in:
Henry Winkel
2022-12-20 10:09:28 +01:00
parent 4a79559129
commit 1e2b3dda7b
1513 changed files with 123720 additions and 83381 deletions

View File

@@ -14,7 +14,4 @@ tab_width = 4
# New line preferences
end_of_line = lf
insert_final_newline = false
trim_trailing_whitespace = true
[*.cs]
csharp_space_after_cast = true
trim_trailing_whitespace = true

View File

@@ -18,7 +18,6 @@ lib/NUnit
# Untracked files
#
.vs
.cr
*.user
*.suo
*.nupkg

View File

@@ -3,87 +3,14 @@
# See also code generation logic under /src/google/protobuf/compiler/csharp.
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
load("//:protobuf.bzl", "internal_csharp_proto_library")
load("//build_defs:internal_shell.bzl", "inline_sh_test")
load("//conformance:defs.bzl", "conformance_test")
################################################################################
# Tests
################################################################################
conformance_test(
name = "conformance_test",
failure_list = "//conformance:failure_list_csharp.txt",
testee = "//conformance:conformance_csharp",
text_format_failure_list = "//conformance:text_format_failure_list_csharp.txt",
)
################################################################################
# CSharp Runtime
################################################################################
filegroup(
name = "srcs",
pkg_files(
name = "dist_files",
srcs = glob([
"keys/*",
"protos/*",
"src/**/*.cs*", # .cs and .csproj
], exclude = [
# Exclude generated files.
"src/*/obj/**/*"
]) + [
"src/Directory.Build.props",
"src/Google.Protobuf.Test/testprotos.pb",
"src/Google.Protobuf.sln",
],
visibility = [
"//csharp:__subpackages__",
"//conformance:__subpackages__"
],
)
filegroup(
name = "wkt_cs_srcs",
srcs = [
"src/Google.Protobuf/Reflection/Descriptor.cs",
"src/Google.Protobuf/WellKnownTypes/Any.cs",
"src/Google.Protobuf/WellKnownTypes/Api.cs",
"src/Google.Protobuf/WellKnownTypes/Duration.cs",
"src/Google.Protobuf/WellKnownTypes/Empty.cs",
"src/Google.Protobuf/WellKnownTypes/FieldMask.cs",
"src/Google.Protobuf/WellKnownTypes/SourceContext.cs",
"src/Google.Protobuf/WellKnownTypes/Struct.cs",
"src/Google.Protobuf/WellKnownTypes/Timestamp.cs",
"src/Google.Protobuf/WellKnownTypes/Type.cs",
"src/Google.Protobuf/WellKnownTypes/Wrappers.cs",
],
visibility = ["//src/google/protobuf/compiler/csharp:__pkg__"],
)
inline_sh_test(
name = "tests",
srcs = [
":srcs",
"src/Google.Protobuf.sln",
"//csharp/src/Google.Protobuf.Conformance:srcs",
],
cmd = """
pushd `dirname $(location src/Google.Protobuf.sln)`/..
dotnet restore src/Google.Protobuf.sln
dotnet build -c Release src/Google.Protobuf.sln
dotnet test -c Release -f netcoreapp3.1 src/Google.Protobuf.Test/Google.Protobuf.Test.csproj
popd
""",
)
################################################################################
# Distribution files
################################################################################
pkg_files(
name = "dist_files",
srcs = [
":srcs",
".editorconfig",
".gitignore",
"BUILD.bazel",
@@ -93,20 +20,15 @@ pkg_files(
"NuGet.Config",
"README.md",
"build_packages.bat",
"build_release.sh",
"build_tools.sh",
"buildall.bat",
"buildall.sh",
"generate_protos.sh",
"install_dotnet_sdk.ps1",
"//csharp/src/Google.Protobuf.Conformance:dist_files",
"src/Google.Protobuf.Benchmarks/wrapper_benchmark_messages.proto",
"src/Google.Protobuf.Test/testprotos.pb",
"src/Google.Protobuf.sln",
],
strip_prefix = strip_prefix.from_root(""),
visibility = ["//pkg:__pkg__"],
)
sh_binary(
name = "release",
srcs = ["build_release.sh"],
args = ["$(location build_release.sh)"],
)

View File

@@ -5,7 +5,7 @@
<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.21.8</version>
<version>3.21.12</version>
<authors>Google Inc.</authors>
<owners>protobuf-packages</owners>
<licenseUrl>https://github.com/protocolbuffers/protobuf/blob/main/LICENSE</licenseUrl>

View File

@@ -16,32 +16,36 @@ To generate C# files from your `.proto` files, invoke `protoc` with the
Supported platforms
===================
The runtime library is built as a class library, supporting targets of:
The runtime library is built as a portable class library, supporting:
- .NET 4.5+ (`net45`)
- .NET Standard 1.1 and 2.0 (`netstandard1.1` and `netstandard2.0`)
- .NET 5+ (`net50`)
- .NET 4.5
- Windows 8
- Windows Phone Silverlight 8
- Windows Phone 8.1
- .NET Core
You should be able to use Protocol Buffers in Visual Studio 2012 and
all later versions. This includes all code generated by `protoc`,
which only uses features from C# 3 and earlier. When compiling generated
code with old compilers (before C# 7.2) you need to define the
`GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE` symbol in your project
so that the generated classes don't implement `IBufferMessage`, which uses
`ref struct` types.
which only uses features from C# 3 and earlier.
Building
========
Open the `src/Google.Protobuf.sln` solution in Visual Studio 2022 or
Open the `src/Google.Protobuf.sln` solution in Visual Studio 2017 or
later.
Although *users* of this project are only expected to have Visual
Studio 2012 or later, *developers* of the library are required to
have Visual Studio 2022 or later, as the library uses C# 10 features
in its implementation and runs tests under .NET 6. These features
have no impact when using the compiled code - they're only relevant
when building the `Google.Protobuf` assembly.
have Visual Studio 2017 or later, as the library uses C# 6 features
in its implementation, as well as the new Visual Studio 2017 csproj
format. These features have no impact when using the compiled code -
they're only relevant when building the `Google.Protobuf` assembly.
In order to run and debug the AddressBook example in the IDE, you must
install the optional component, ".Net Core 1.0 - 1.1 development tools
for Web" (as it's labelled in current versions of the VS2017
installer), above and beyond the main .NET Core cross-platform
development feature.
Testing
=======
@@ -52,11 +56,20 @@ run using the Visual Studio Test Explorer or `dotnet test`.
.NET 3.5
========
We don't support .NET 3.5. It *used* to be feasible to build this library
targeting .NET 3.5, but a number of changes requiring newer runtime/framework
features have been added over time. While it would no doubt be *possible* to
rework the current implementation to allow most of the functionality to be built
in .NET 3.5, this would create an undue maintenance burden.
We don't officially support .NET 3.5. However, there has been some effort
to make enabling .NET 3.5 support relatively painless in case you require it.
There's no guarantee that this will continue in the future, so rely on .NET
3.5 support at your peril.
To enable .NET 3.5 support, you must edit the `TargetFrameworks` elements of
[src/Google.Protobuf/Google.Protobuf.csproj](src/Google.Protobuf/Google.Protobuf.csproj)
(and [src/Google.Protobuf.Test/Google.Protobuf.Test.csproj](src/Google.Protobuf.Test/Google.Protobuf.Test.csproj)
if you want to run the unit tests):
Open the .csproj file in a text editor and simply add `net35` to the list of
target frameworks, noting that the `TargetFrameworks` element appears twice in
the file (once in the first `PropertyGroup` element, and again in the second
`PropertyGroup` element, i.e., the one with the conditional).
History of C# protobufs
=======================
@@ -68,9 +81,9 @@ and maintained by Google. All the development will be done in open, under this r
The previous project differs from this project in a number of ways:
- The old code only supported proto2; the new code initially only supported
- The old code only supported proto2; the new code only supports
proto3 (so no unknown fields, no required/optional distinction, no
extensions); since then proto2 support has been added
extensions)
- The old code was based on immutable message types and builders for
them
- The old code did not support maps or `oneof`

View File

@@ -1,11 +0,0 @@
#!/bin/bash
cd $(dirname $(readlink $BASH_SOURCE))
# Disable some unwanted dotnet options
set DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true
set DOTNET_CLI_TELEMETRY_OPTOUT=true
# Builds Google.Protobuf NuGet packages
dotnet restore -s /lib/csharp/ src/Google.Protobuf/Google.Protobuf.csproj
dotnet pack --no-restore -c Release src/Google.Protobuf.sln -p:ContinuousIntegrationBuild=true

View File

@@ -1,16 +0,0 @@
load("//build_defs:internal_shell.bzl", "inline_sh_test")
# Run csharp compatibility test between 3.0.0 and the current version.
inline_sh_test(
name = "tests",
srcs = ["test.sh"],
tools = ["//:protoc"],
deps = glob([
"src/**/*.cs*", # .cs and .csproj
"protos/**/*.proto",
]) + [
"//csharp:srcs",
"//:well_known_protos",
],
cmd = "$(location test.sh) 3.0.0 $(rootpath //:protoc)"
)

View File

@@ -6,7 +6,6 @@
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<IsPackable>False</IsPackable>
<LangVersion>8.0</LangVersion>
</PropertyGroup>
<ItemGroup>

View File

@@ -27,8 +27,6 @@ function run_test() {
set -ex
PROTOC=$(realpath ${2:-../../../bazel-bin/protoc})
# Change to the script's directory.
cd $(dirname $0)
@@ -47,7 +45,7 @@ OLD_VERSION_PROTOC=https://repo1.maven.org/maven2/com/google/protobuf/protoc/$OL
echo "Running compatibility tests with $OLD_VERSION"
# Check protoc
[ -f $PROTOC ] || {
[ -f ../../../src/protoc ] || {
echo "[ERROR]: Please build protoc first."
exit 1
}
@@ -70,12 +68,12 @@ run_test "./old_protoc" "./old_protoc"
# Test A.2:
# proto set 1: use new version
# proto set 2 which may import protos in set 1: use old version
run_test "$PROTOC" "./old_protoc"
run_test "../../../src/protoc" "./old_protoc"
# Test A.3:
# proto set 1: use old version
# proto set 2 which may import protos in set 1: use new version
run_test "./old_protoc" "$PROTOC"
run_test "./old_protoc" "../../../src/protoc"
rm old_protoc
rm keys -r

View File

@@ -11,19 +11,17 @@ pushd $(dirname $0)/..
# Protocol buffer compiler to use. If the PROTOC variable is set,
# use that. Otherwise, probe for expected locations under both
# Windows and Unix.
PROTOC_LOCATIONS=(
"bazel-bin/protoc"
"solution/Debug/protoc.exe"
"cmake/build/Debug/protoc.exe"
"cmake/build/Release/protoc.exe"
)
if [ -z "$PROTOC" ]; then
for protoc in "${PROTOC_LOCATIONS[@]}"; do
if [ -x "$protoc" ]; then
PROTOC="$protoc"
fi
done
if [ -z "$PROTOC" ]; then
# TODO(jonskeet): Use an array and a for loop instead?
if [ -x solution/Debug/protoc.exe ]; then
PROTOC=solution/Debug/protoc.exe
elif [ -x cmake/build/Debug/protoc.exe ]; then
PROTOC=cmake/build/Debug/protoc.exe
elif [ -x cmake/build/Release/protoc.exe ]; then
PROTOC=cmake/build/Release/protoc.exe
elif [ -x src/protoc ]; then
PROTOC=src/protoc
else
echo "Unable to find protocol buffer compiler."
exit 1
fi
@@ -42,8 +40,7 @@ $PROTOC -Isrc --csharp_out=csharp/src/Google.Protobuf \
src/google/protobuf/struct.proto \
src/google/protobuf/timestamp.proto \
src/google/protobuf/type.proto \
src/google/protobuf/wrappers.proto \
src/google/protobuf/compiler/plugin.proto
src/google/protobuf/wrappers.proto
# Test protos
# Note that this deliberately does *not* include old_extensions1.proto
@@ -76,3 +73,17 @@ $PROTOC -Isrc -Icsharp/protos \
# AddressBook sample protos
$PROTOC -Iexamples -Isrc --csharp_out=csharp/src/AddressBook \
examples/addressbook.proto
$PROTOC -Iconformance -Isrc --csharp_out=csharp/src/Google.Protobuf.Conformance \
conformance/conformance.proto
# Benchmark protos
$PROTOC -Ibenchmarks \
benchmarks/datasets/google_message1/proto3/*.proto \
benchmarks/benchmarks.proto \
--csharp_out=csharp/src/Google.Protobuf.Benchmarks
# C# only benchmark protos
$PROTOC -Isrc -Icsharp/src/Google.Protobuf.Benchmarks \
csharp/src/Google.Protobuf.Benchmarks/*.proto \
--csharp_out=csharp/src/Google.Protobuf.Benchmarks

View File

@@ -59,12 +59,10 @@ message NegativeEnumMessage {
// Decorate fields with [deprecated=true] as [System.Obsolete]
message DeprecatedChild {
option deprecated = true;
}
enum DeprecatedEnum {
option deprecated = true;
DEPRECATED_ZERO = 0 [deprecated = true];
DEPRECATED_ZERO = 0;
one = 1;
}
@@ -171,20 +169,4 @@ message OneofWithNoneName {
string x = 1;
string y = 2;
}
}
// Issue 8810
message DisambiguateCommonMembers {
int32 disambiguate_common_members = 1;
int32 types = 2;
int32 descriptor = 3;
int32 equals = 4;
int32 to_string = 5;
int32 get_hash_code = 6;
int32 write_to = 7;
int32 clone = 8;
int32 calculate_size = 9;
int32 merge_from = 10;
int32 on_construction = 11;
int32 parser = 12;
}
}

View File

@@ -107,8 +107,10 @@ namespace Google.Protobuf.Examples.AddressBook
if (File.Exists(args[0]))
{
using Stream file = File.OpenRead(args[0]);
addressBook = AddressBook.Parser.ParseFrom(file);
using (Stream file = File.OpenRead(args[0]))
{
addressBook = AddressBook.Parser.ParseFrom(file);
}
}
else
{

View File

@@ -1,7 +0,0 @@
<Project>
<PropertyGroup>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,89 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 Benchmarks;
using Google.Protobuf.Reflection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace Google.Protobuf.Benchmarks
{
/// <summary>
/// The configuration for a single serialization test, loaded from a dataset.
/// </summary>
public class BenchmarkDatasetConfig
{
private static readonly Dictionary<string, MessageParser> parsersByMessageName =
typeof(GoogleMessageBenchmark).Assembly.GetTypes()
.Where(t => typeof(IMessage).IsAssignableFrom(t))
.ToDictionary(
t => ((MessageDescriptor) t.GetProperty("Descriptor", BindingFlags.Static | BindingFlags.Public).GetValue(null)).FullName,
t => ((MessageParser) t.GetProperty("Parser", BindingFlags.Static | BindingFlags.Public).GetValue(null)));
public MessageParser Parser { get; }
public List<byte[]> Payloads { get; }
public string Name { get; }
public BenchmarkDatasetConfig(string resource, string shortName = null)
{
var data = LoadData(resource);
var dataset = BenchmarkDataset.Parser.ParseFrom(data);
if (!parsersByMessageName.TryGetValue(dataset.MessageName, out var parser))
{
throw new ArgumentException($"No parser for message {dataset.MessageName} in this assembly");
}
Parser = parser;
Payloads = new List<byte[]>(dataset.Payload.Select(p => p.ToByteArray()));
Name = shortName ?? dataset.Name;
}
private static byte[] LoadData(string resource)
{
using (var stream = typeof(GoogleMessageBenchmark).Assembly.GetManifestResourceStream($"Google.Protobuf.Benchmarks.{resource}"))
{
if (stream == null)
{
throw new ArgumentException($"Unable to load embedded resource {resource}");
}
var copy = new MemoryStream();
stream.CopyTo(copy);
return copy.ToArray();
}
}
public override string ToString() => Name;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,325 @@
// <auto-generated>
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: benchmarks.proto
// </auto-generated>
#pragma warning disable 1591, 0612, 3021, 8981
#region Designer generated code
using pb = global::Google.Protobuf;
using pbc = global::Google.Protobuf.Collections;
using pbr = global::Google.Protobuf.Reflection;
using scg = global::System.Collections.Generic;
namespace Benchmarks {
/// <summary>Holder for reflection information generated from benchmarks.proto</summary>
public static partial class BenchmarksReflection {
#region Descriptor
/// <summary>File descriptor for benchmarks.proto</summary>
public static pbr::FileDescriptor Descriptor {
get { return descriptor; }
}
private static pbr::FileDescriptor descriptor;
static BenchmarksReflection() {
byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat(
"ChBiZW5jaG1hcmtzLnByb3RvEgpiZW5jaG1hcmtzIkcKEEJlbmNobWFya0Rh",
"dGFzZXQSDAoEbmFtZRgBIAEoCRIUCgxtZXNzYWdlX25hbWUYAiABKAkSDwoH",
"cGF5bG9hZBgDIAMoDEIgCh5jb20uZ29vZ2xlLnByb3RvYnVmLmJlbmNobWFy",
"a3NiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(null, null, new pbr::GeneratedClrTypeInfo[] {
new pbr::GeneratedClrTypeInfo(typeof(global::Benchmarks.BenchmarkDataset), global::Benchmarks.BenchmarkDataset.Parser, new[]{ "Name", "MessageName", "Payload" }, null, null, null, null)
}));
}
#endregion
}
#region Messages
public sealed partial class BenchmarkDataset : pb::IMessage<BenchmarkDataset>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<BenchmarkDataset> _parser = new pb::MessageParser<BenchmarkDataset>(() => new BenchmarkDataset());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<BenchmarkDataset> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::Benchmarks.BenchmarksReflection.Descriptor.MessageTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public BenchmarkDataset() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public BenchmarkDataset(BenchmarkDataset other) : this() {
name_ = other.name_;
messageName_ = other.messageName_;
payload_ = other.payload_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public BenchmarkDataset Clone() {
return new BenchmarkDataset(this);
}
/// <summary>Field number for the "name" field.</summary>
public const int NameFieldNumber = 1;
private string name_ = "";
/// <summary>
/// Name of the benchmark dataset. This should be unique across all datasets.
/// Should only contain word characters: [a-zA-Z0-9_]
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string Name {
get { return name_; }
set {
name_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "message_name" field.</summary>
public const int MessageNameFieldNumber = 2;
private string messageName_ = "";
/// <summary>
/// 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.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string MessageName {
get { return messageName_; }
set {
messageName_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Field number for the "payload" field.</summary>
public const int PayloadFieldNumber = 3;
private static readonly pb::FieldCodec<pb::ByteString> _repeated_payload_codec
= pb::FieldCodec.ForBytes(26);
private readonly pbc::RepeatedField<pb::ByteString> payload_ = new pbc::RepeatedField<pb::ByteString>();
/// <summary>
/// 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 &lt; 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.
/// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pbc::RepeatedField<pb::ByteString> Payload {
get { return payload_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as BenchmarkDataset);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(BenchmarkDataset other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Name != other.Name) return false;
if (MessageName != other.MessageName) return false;
if(!payload_.Equals(other.payload_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (MessageName.Length != 0) hash ^= MessageName.GetHashCode();
hash ^= payload_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (Name.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Name);
}
if (MessageName.Length != 0) {
output.WriteRawTag(18);
output.WriteString(MessageName);
}
payload_.WriteTo(output, _repeated_payload_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (Name.Length != 0) {
output.WriteRawTag(10);
output.WriteString(Name);
}
if (MessageName.Length != 0) {
output.WriteRawTag(18);
output.WriteString(MessageName);
}
payload_.WriteTo(ref output, _repeated_payload_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (Name.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Name);
}
if (MessageName.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(MessageName);
}
size += payload_.CalculateSize(_repeated_payload_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(BenchmarkDataset other) {
if (other == null) {
return;
}
if (other.Name.Length != 0) {
Name = other.Name;
}
if (other.MessageName.Length != 0) {
MessageName = other.MessageName;
}
payload_.Add(other.payload_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
Name = input.ReadString();
break;
}
case 18: {
MessageName = input.ReadString();
break;
}
case 26: {
payload_.AddEntriesFrom(input, _repeated_payload_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
Name = input.ReadString();
break;
}
case 18: {
MessageName = input.ReadString();
break;
}
case 26: {
payload_.AddEntriesFrom(ref input, _repeated_payload_codec);
break;
}
}
}
}
#endif
}
#endregion
}
#endregion Designer generated code

View File

@@ -0,0 +1,72 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 BenchmarkDotNet.Attributes;
namespace Google.Protobuf.Benchmarks
{
/// <summary>
/// Benchmarks using ByteString.
/// </summary>
[MemoryDiagnoser]
public class ByteStringBenchmark
{
private const int Zero = 0;
private const int Kilobyte = 1024;
private const int _128Kilobytes = 1024 * 128;
private const int Megabyte = 1024 * 1024;
private const int _10Megabytes = 1024 * 1024 * 10;
byte[] byteBuffer;
[GlobalSetup]
public void GlobalSetup()
{
byteBuffer = new byte[PayloadSize];
}
[Params(Zero, Kilobyte, _128Kilobytes, Megabyte, _10Megabytes)]
public int PayloadSize { get; set; }
[Benchmark]
public ByteString CopyFrom()
{
return ByteString.CopyFrom(byteBuffer);
}
[Benchmark]
public ByteString UnsafeWrap()
{
return UnsafeByteOperations.UnsafeWrap(byteBuffer);
}
}
}

View File

@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<IsPackable>False</IsPackable>
<DebugType>pdbonly</DebugType>
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Google.Protobuf.Test\ReadOnlySequenceFactory.cs" Link="ReadOnlySequenceFactory.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<ProjectReference Include="..\Google.Protobuf\Google.Protobuf.csproj" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="..\..\..\benchmarks\datasets\google_message1\proto3\dataset.google_message1_proto3.pb" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,124 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 BenchmarkDotNet.Attributes;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Google.Protobuf.Benchmarks
{
/// <summary>
/// Benchmark for serializing and deserializing of standard datasets that are also
/// measured by benchmarks in other languages.
/// Over time we may wish to test the various different approaches to serialization and deserialization separately.
/// See https://github.com/protocolbuffers/protobuf/blob/main/benchmarks/README.md
/// See https://github.com/protocolbuffers/protobuf/blob/main/docs/performance.md
/// </summary>
[MemoryDiagnoser]
public class GoogleMessageBenchmark
{
/// <summary>
/// All the datasets to be tested. Add more datasets to the array as they're available.
/// (When C# supports proto2, this will increase significantly.)
/// </summary>
public static BenchmarkDatasetConfig[] DatasetConfigurations => new[]
{
// short name is specified to make results table more readable
new BenchmarkDatasetConfig("dataset.google_message1_proto3.pb", "goog_msg1_proto3")
};
[ParamsSource(nameof(DatasetConfigurations))]
public BenchmarkDatasetConfig Dataset { get; set; }
private MessageParser parser;
/// <summary>
/// Each data set can contain multiple messages in a single file.
/// Each "write" operation should write each message in turn, and each "parse"
/// operation should parse each message in turn.
/// </summary>
private List<SubTest> subTests;
[GlobalSetup]
public void GlobalSetup()
{
parser = Dataset.Parser;
subTests = Dataset.Payloads.Select(p => new SubTest(p, parser.ParseFrom(p))).ToList();
}
[Benchmark]
public void WriteToStream() => subTests.ForEach(item => item.WriteToStream());
[Benchmark]
public void ToByteArray() => subTests.ForEach(item => item.ToByteArray());
[Benchmark]
public void ParseFromByteArray() => subTests.ForEach(item => item.ParseFromByteArray(parser));
[Benchmark]
public void ParseFromStream() => subTests.ForEach(item => item.ParseFromStream(parser));
private class SubTest
{
private readonly Stream destinationStream;
private readonly Stream sourceStream;
private readonly byte[] data;
private readonly IMessage message;
public SubTest(byte[] data, IMessage message)
{
destinationStream = new MemoryStream(data.Length);
sourceStream = new MemoryStream(data);
this.data = data;
this.message = message;
}
public void Reset() => destinationStream.Position = 0;
public void WriteToStream()
{
destinationStream.Position = 0;
message.WriteTo(destinationStream);
}
public void ToByteArray() => message.ToByteArray();
public void ParseFromByteArray(MessageParser parser) => parser.ParseFrom(data);
public void ParseFromStream(MessageParser parser)
{
sourceStream.Position = 0;
parser.ParseFrom(sourceStream);
}
}
}
}

View File

@@ -0,0 +1,258 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 BenchmarkDotNet.Attributes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Buffers;
using Google.Protobuf.WellKnownTypes;
using Benchmarks.Proto3;
namespace Google.Protobuf.Benchmarks
{
/// <summary>
/// Benchmark that tests parsing performance for various messages.
/// </summary>
[MemoryDiagnoser]
public class ParseMessagesBenchmark
{
const int MaxMessages = 100;
SubTest manyWrapperFieldsTest = new SubTest(CreateManyWrapperFieldsMessage(), ManyWrapperFieldsMessage.Parser, () => new ManyWrapperFieldsMessage(), MaxMessages);
SubTest manyPrimitiveFieldsTest = new SubTest(CreateManyPrimitiveFieldsMessage(), ManyPrimitiveFieldsMessage.Parser, () => new ManyPrimitiveFieldsMessage(), MaxMessages);
SubTest repeatedFieldTest = new SubTest(CreateRepeatedFieldMessage(), GoogleMessage1.Parser, () => new GoogleMessage1(), MaxMessages);
SubTest emptyMessageTest = new SubTest(new Empty(), Empty.Parser, () => new Empty(), MaxMessages);
public IEnumerable<int> MessageCountValues => new[] { 10, 100 };
[GlobalSetup]
public void GlobalSetup()
{
}
[Benchmark]
public IMessage ManyWrapperFieldsMessage_ParseFromByteArray()
{
return manyWrapperFieldsTest.ParseFromByteArray();
}
[Benchmark]
public IMessage ManyWrapperFieldsMessage_ParseFromReadOnlySequence()
{
return manyWrapperFieldsTest.ParseFromReadOnlySequence();
}
[Benchmark]
public IMessage ManyPrimitiveFieldsMessage_ParseFromByteArray()
{
return manyPrimitiveFieldsTest.ParseFromByteArray();
}
[Benchmark]
public IMessage ManyPrimitiveFieldsMessage_ParseFromReadOnlySequence()
{
return manyPrimitiveFieldsTest.ParseFromReadOnlySequence();
}
[Benchmark]
public IMessage RepeatedFieldMessage_ParseFromByteArray()
{
return repeatedFieldTest.ParseFromByteArray();
}
[Benchmark]
public IMessage RepeatedFieldMessage_ParseFromReadOnlySequence()
{
return repeatedFieldTest.ParseFromReadOnlySequence();
}
[Benchmark]
public IMessage EmptyMessage_ParseFromByteArray()
{
return emptyMessageTest.ParseFromByteArray();
}
[Benchmark]
public IMessage EmptyMessage_ParseFromReadOnlySequence()
{
return emptyMessageTest.ParseFromReadOnlySequence();
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
{
manyWrapperFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyWrapperFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
{
manyWrapperFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
{
manyPrimitiveFieldsTest.ParseDelimitedMessagesFromByteArray(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyPrimitiveFieldsMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
{
manyPrimitiveFieldsTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void RepeatedFieldMessage_ParseDelimitedMessagesFromByteArray(int messageCount)
{
repeatedFieldTest.ParseDelimitedMessagesFromByteArray(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void RepeatedFieldMessage_ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
{
repeatedFieldTest.ParseDelimitedMessagesFromReadOnlySequence(messageCount);
}
public static ManyWrapperFieldsMessage CreateManyWrapperFieldsMessage()
{
// Example data match data of an internal benchmarks
return new ManyWrapperFieldsMessage()
{
Int64Field19 = 123,
Int64Field37 = 1000032,
Int64Field26 = 3453524500,
DoubleField79 = 1.2,
DoubleField25 = 234,
DoubleField9 = 123.3,
DoubleField28 = 23,
DoubleField7 = 234,
DoubleField50 = 2.45
};
}
public static ManyPrimitiveFieldsMessage CreateManyPrimitiveFieldsMessage()
{
// Example data match data of an internal benchmarks
return new ManyPrimitiveFieldsMessage()
{
Int64Field19 = 123,
Int64Field37 = 1000032,
Int64Field26 = 3453524500,
DoubleField79 = 1.2,
DoubleField25 = 234,
DoubleField9 = 123.3,
DoubleField28 = 23,
DoubleField7 = 234,
DoubleField50 = 2.45
};
}
public static GoogleMessage1 CreateRepeatedFieldMessage()
{
// Message with a repeated fixed length item collection
var message = new GoogleMessage1();
for (ulong i = 0; i < 1000; i++)
{
message.Field5.Add(i);
}
return message;
}
private class SubTest
{
private readonly IMessage message;
private readonly MessageParser parser;
private readonly Func<IMessage> factory;
private readonly byte[] data;
private readonly byte[] multipleMessagesData;
private ReadOnlySequence<byte> dataSequence;
private ReadOnlySequence<byte> multipleMessagesDataSequence;
public SubTest(IMessage message, MessageParser parser, Func<IMessage> factory, int maxMessageCount)
{
this.message = message;
this.parser = parser;
this.factory = factory;
this.data = message.ToByteArray();
this.multipleMessagesData = CreateBufferWithMultipleMessages(message, maxMessageCount);
this.dataSequence = new ReadOnlySequence<byte>(this.data);
this.multipleMessagesDataSequence = new ReadOnlySequence<byte>(this.multipleMessagesData);
}
public IMessage ParseFromByteArray() => parser.ParseFrom(data);
public IMessage ParseFromReadOnlySequence() => parser.ParseFrom(dataSequence);
public void ParseDelimitedMessagesFromByteArray(int messageCount)
{
var input = new CodedInputStream(multipleMessagesData);
for (int i = 0; i < messageCount; i++)
{
var msg = factory();
input.ReadMessage(msg);
}
}
public void ParseDelimitedMessagesFromReadOnlySequence(int messageCount)
{
ParseContext.Initialize(multipleMessagesDataSequence, out ParseContext ctx);
for (int i = 0; i < messageCount; i++)
{
var msg = factory();
ctx.ReadMessage(msg);
}
}
private static byte[] CreateBufferWithMultipleMessages(IMessage msg, int msgCount)
{
var ms = new MemoryStream();
var cos = new CodedOutputStream(ms);
for (int i = 0; i < msgCount; i++)
{
cos.WriteMessage(msg);
}
cos.Flush();
return ms.ToArray();
}
}
}
}

View File

@@ -0,0 +1,536 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 BenchmarkDotNet.Attributes;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Buffers;
namespace Google.Protobuf.Benchmarks
{
/// <summary>
/// Benchmarks throughput when parsing raw primitives.
/// </summary>
[MemoryDiagnoser]
public class ParseRawPrimitivesBenchmark
{
// key is the encodedSize of varint values
Dictionary<int, byte[]> varintInputBuffers;
byte[] doubleInputBuffer;
byte[] floatInputBuffer;
byte[] fixedIntInputBuffer;
// key is the encodedSize of string values
Dictionary<int, byte[]> stringInputBuffers;
Dictionary<int, ReadOnlySequence<byte>> stringInputBuffersSegmented;
Random random = new Random(417384220); // random but deterministic seed
public IEnumerable<int> StringEncodedSizes => new[] { 1, 4, 10, 105, 10080 };
public IEnumerable<int> StringSegmentedEncodedSizes => new[] { 105, 10080 };
[GlobalSetup]
public void GlobalSetup()
{
// add some extra values that we won't read just to make sure we are far enough from the end of the buffer
// which allows the parser fastpath to always kick in.
const int paddingValueCount = 100;
varintInputBuffers = new Dictionary<int, byte[]>();
for (int encodedSize = 1; encodedSize <= 10; encodedSize++)
{
byte[] buffer = CreateBufferWithRandomVarints(random, BytesToParse / encodedSize, encodedSize, paddingValueCount);
varintInputBuffers.Add(encodedSize, buffer);
}
doubleInputBuffer = CreateBufferWithRandomDoubles(random, BytesToParse / sizeof(double), paddingValueCount);
floatInputBuffer = CreateBufferWithRandomFloats(random, BytesToParse / sizeof(float), paddingValueCount);
fixedIntInputBuffer = CreateBufferWithRandomData(random, BytesToParse / sizeof(long), sizeof(long), paddingValueCount);
stringInputBuffers = new Dictionary<int, byte[]>();
foreach (var encodedSize in StringEncodedSizes)
{
byte[] buffer = CreateBufferWithStrings(BytesToParse / encodedSize, encodedSize, encodedSize < 10 ? 10 : 1 );
stringInputBuffers.Add(encodedSize, buffer);
}
stringInputBuffersSegmented = new Dictionary<int, ReadOnlySequence<byte>>();
foreach (var encodedSize in StringSegmentedEncodedSizes)
{
byte[] buffer = CreateBufferWithStrings(BytesToParse / encodedSize, encodedSize, encodedSize < 10 ? 10 : 1);
stringInputBuffersSegmented.Add(encodedSize, ReadOnlySequenceFactory.CreateWithContent(buffer, segmentSize: 128, addEmptySegmentDelimiters: false));
}
}
// Total number of bytes that each benchmark will parse.
// Measuring the time taken to parse buffer of given size makes it easier to compare parsing speed for different
// types and makes it easy to calculate the througput (in MB/s)
// 10800 bytes is chosen because it is divisible by all possible encoded sizes for all primitive types {1..10}
[Params(10080)]
public int BytesToParse { get; set; }
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
public int ParseRawVarint32_CodedInputStream(int encodedSize)
{
CodedInputStream cis = new CodedInputStream(varintInputBuffers[encodedSize]);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadInt32();
}
return sum;
}
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
public int ParseRawVarint32_ParseContext(int encodedSize)
{
InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadInt32();
}
return sum;
}
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
[Arguments(6)]
[Arguments(7)]
[Arguments(8)]
[Arguments(9)]
[Arguments(10)]
public long ParseRawVarint64_CodedInputStream(int encodedSize)
{
CodedInputStream cis = new CodedInputStream(varintInputBuffers[encodedSize]);
long sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadInt64();
}
return sum;
}
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
[Arguments(6)]
[Arguments(7)]
[Arguments(8)]
[Arguments(9)]
[Arguments(10)]
public long ParseRawVarint64_ParseContext(int encodedSize)
{
InitializeParseContext(varintInputBuffers[encodedSize], out ParseContext ctx);
long sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadInt64();
}
return sum;
}
[Benchmark]
public uint ParseFixed32_CodedInputStream()
{
const int encodedSize = sizeof(uint);
CodedInputStream cis = new CodedInputStream(fixedIntInputBuffer);
uint sum = 0;
for (uint i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadFixed32();
}
return sum;
}
[Benchmark]
public uint ParseFixed32_ParseContext()
{
const int encodedSize = sizeof(uint);
InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
uint sum = 0;
for (uint i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadFixed32();
}
return sum;
}
[Benchmark]
public ulong ParseFixed64_CodedInputStream()
{
const int encodedSize = sizeof(ulong);
CodedInputStream cis = new CodedInputStream(fixedIntInputBuffer);
ulong sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadFixed64();
}
return sum;
}
[Benchmark]
public ulong ParseFixed64_ParseContext()
{
const int encodedSize = sizeof(ulong);
InitializeParseContext(fixedIntInputBuffer, out ParseContext ctx);
ulong sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadFixed64();
}
return sum;
}
[Benchmark]
public float ParseRawFloat_CodedInputStream()
{
const int encodedSize = sizeof(float);
CodedInputStream cis = new CodedInputStream(floatInputBuffer);
float sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadFloat();
}
return sum;
}
[Benchmark]
public float ParseRawFloat_ParseContext()
{
const int encodedSize = sizeof(float);
InitializeParseContext(floatInputBuffer, out ParseContext ctx);
float sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadFloat();
}
return sum;
}
[Benchmark]
public double ParseRawDouble_CodedInputStream()
{
const int encodedSize = sizeof(double);
CodedInputStream cis = new CodedInputStream(doubleInputBuffer);
double sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadDouble();
}
return sum;
}
[Benchmark]
public double ParseRawDouble_ParseContext()
{
const int encodedSize = sizeof(double);
InitializeParseContext(doubleInputBuffer, out ParseContext ctx);
double sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadDouble();
}
return sum;
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public int ParseString_CodedInputStream(int encodedSize)
{
CodedInputStream cis = new CodedInputStream(stringInputBuffers[encodedSize]);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadString().Length;
}
return sum;
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public int ParseString_ParseContext(int encodedSize)
{
InitializeParseContext(stringInputBuffers[encodedSize], out ParseContext ctx);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadString().Length;
}
return sum;
}
[Benchmark]
[ArgumentsSource(nameof(StringSegmentedEncodedSizes))]
public int ParseString_ParseContext_MultipleSegments(int encodedSize)
{
InitializeParseContext(stringInputBuffersSegmented[encodedSize], out ParseContext ctx);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadString().Length;
}
return sum;
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public int ParseBytes_CodedInputStream(int encodedSize)
{
CodedInputStream cis = new CodedInputStream(stringInputBuffers[encodedSize]);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += cis.ReadBytes().Length;
}
return sum;
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public int ParseBytes_ParseContext(int encodedSize)
{
InitializeParseContext(stringInputBuffers[encodedSize], out ParseContext ctx);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadBytes().Length;
}
return sum;
}
[Benchmark]
[ArgumentsSource(nameof(StringSegmentedEncodedSizes))]
public int ParseBytes_ParseContext_MultipleSegments(int encodedSize)
{
InitializeParseContext(stringInputBuffersSegmented[encodedSize], out ParseContext ctx);
int sum = 0;
for (int i = 0; i < BytesToParse / encodedSize; i++)
{
sum += ctx.ReadBytes().Length;
}
return sum;
}
private static void InitializeParseContext(byte[] buffer, out ParseContext ctx)
{
ParseContext.Initialize(new ReadOnlySequence<byte>(buffer), out ctx);
}
private static void InitializeParseContext(ReadOnlySequence<byte> buffer, out ParseContext ctx)
{
ParseContext.Initialize(buffer, out ctx);
}
private static byte[] CreateBufferWithRandomVarints(Random random, int valueCount, int encodedSize, int paddingValueCount)
{
MemoryStream ms = new MemoryStream();
CodedOutputStream cos = new CodedOutputStream(ms);
for (int i = 0; i < valueCount + paddingValueCount; i++)
{
cos.WriteUInt64(RandomUnsignedVarint(random, encodedSize, false));
}
cos.Flush();
var buffer = ms.ToArray();
if (buffer.Length != encodedSize * (valueCount + paddingValueCount))
{
throw new InvalidOperationException($"Unexpected output buffer length {buffer.Length}");
}
return buffer;
}
private static byte[] CreateBufferWithRandomFloats(Random random, int valueCount, int paddingValueCount)
{
MemoryStream ms = new MemoryStream();
CodedOutputStream cos = new CodedOutputStream(ms);
for (int i = 0; i < valueCount + paddingValueCount; i++)
{
cos.WriteFloat((float)random.NextDouble());
}
cos.Flush();
var buffer = ms.ToArray();
return buffer;
}
private static byte[] CreateBufferWithRandomDoubles(Random random, int valueCount, int paddingValueCount)
{
MemoryStream ms = new MemoryStream();
CodedOutputStream cos = new CodedOutputStream(ms);
for (int i = 0; i < valueCount + paddingValueCount; i++)
{
cos.WriteDouble(random.NextDouble());
}
cos.Flush();
var buffer = ms.ToArray();
return buffer;
}
private static byte[] CreateBufferWithRandomData(Random random, int valueCount, int encodedSize, int paddingValueCount)
{
int bufferSize = (valueCount + paddingValueCount) * encodedSize;
byte[] buffer = new byte[bufferSize];
random.NextBytes(buffer);
return buffer;
}
/// <summary>
/// Generate a random value that will take exactly "encodedSize" bytes when varint-encoded.
/// </summary>
public static ulong RandomUnsignedVarint(Random random, int encodedSize, bool fitsIn32Bits)
{
Span<byte> randomBytesBuffer = stackalloc byte[8];
if (encodedSize < 1 || encodedSize > 10 || (fitsIn32Bits && encodedSize > 5))
{
throw new ArgumentException("Illegal encodedSize value requested", nameof(encodedSize));
}
const int bitsPerByte = 7;
ulong result = 0;
while (true)
{
random.NextBytes(randomBytesBuffer);
ulong randomValue = BinaryPrimitives.ReadUInt64LittleEndian(randomBytesBuffer);
// only use the number of random bits we need
ulong bitmask = encodedSize < 10 ? ((1UL << (encodedSize * bitsPerByte)) - 1) : ulong.MaxValue;
result = randomValue & bitmask;
if (fitsIn32Bits)
{
// make sure the resulting value is representable by a uint.
result &= uint.MaxValue;
}
if (encodedSize == 10)
{
// for 10-byte values the highest bit always needs to be set (7*9=63)
result |= ulong.MaxValue;
break;
}
// some random values won't require the full "encodedSize" bytes, check that at least
// one of the top 7 bits is set. Retrying is fine since it only happens rarely
if (encodedSize == 1 || (result & (0x7FUL << ((encodedSize - 1) * bitsPerByte))) != 0)
{
break;
}
}
return result;
}
private static byte[] CreateBufferWithStrings(int valueCount, int encodedSize, int paddingValueCount)
{
var str = CreateStringWithEncodedSize(encodedSize);
MemoryStream ms = new MemoryStream();
CodedOutputStream cos = new CodedOutputStream(ms);
for (int i = 0; i < valueCount + paddingValueCount; i++)
{
cos.WriteString(str);
}
cos.Flush();
var buffer = ms.ToArray();
if (buffer.Length != encodedSize * (valueCount + paddingValueCount))
{
throw new InvalidOperationException($"Unexpected output buffer length {buffer.Length}");
}
return buffer;
}
public static string CreateStringWithEncodedSize(int encodedSize)
{
var str = new string('a', encodedSize);
while (CodedOutputStream.ComputeStringSize(str) > encodedSize)
{
str = str.Substring(1);
}
if (CodedOutputStream.ComputeStringSize(str) != encodedSize)
{
throw new InvalidOperationException($"Generated string with wrong encodedSize");
}
return str;
}
public static string CreateNonAsciiStringWithEncodedSize(int encodedSize)
{
if (encodedSize < 3)
{
throw new ArgumentException("Illegal encoded size for a string with non-ascii chars.");
}
var twoByteChar = '\u00DC'; // U-umlaut, UTF8 encoding has 2 bytes
var str = new string(twoByteChar, encodedSize / 2);
while (CodedOutputStream.ComputeStringSize(str) > encodedSize)
{
str = str.Substring(1);
}
// add padding of ascii characters to reach the desired encoded size.
while (CodedOutputStream.ComputeStringSize(str) < encodedSize)
{
str += 'a';
}
// Note that for a few specific encodedSize values, it might be impossible to generate
// the string with the desired encodedSize using the algorithm above. For testing purposes, checking that
// the encoded size we got is actually correct is good enough.
if (CodedOutputStream.ComputeStringSize(str) != encodedSize)
{
throw new InvalidOperationException($"Generated string with wrong encodedSize");
}
return str;
}
}
}

View File

@@ -0,0 +1,49 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 BenchmarkDotNet.Running;
namespace Google.Protobuf.Benchmarks
{
class Program
{
// typical usage: dotnet run -c Release -f netcoreapp3.1
// (this can profile both .net core and .net framework; for some reason
// if you start from "-f net461", it goes horribly wrong)
public static void Main(string[] args)
{
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,198 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 BenchmarkDotNet.Attributes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Buffers;
using Google.Protobuf.WellKnownTypes;
namespace Google.Protobuf.Benchmarks
{
/// <summary>
/// Benchmark that tests writing performance for various messages.
/// </summary>
[MemoryDiagnoser]
public class WriteMessagesBenchmark
{
const int MaxMessages = 100;
SubTest manyWrapperFieldsTest = new SubTest(ParseMessagesBenchmark.CreateManyWrapperFieldsMessage(), MaxMessages);
SubTest manyPrimitiveFieldsTest = new SubTest(ParseMessagesBenchmark.CreateManyPrimitiveFieldsMessage(), MaxMessages);
SubTest emptyMessageTest = new SubTest(new Empty(), MaxMessages);
public IEnumerable<int> MessageCountValues => new[] { 10, 100 };
[GlobalSetup]
public void GlobalSetup()
{
}
[Benchmark]
public byte[] ManyWrapperFieldsMessage_ToByteArray()
{
return manyWrapperFieldsTest.ToByteArray();
}
[Benchmark]
public byte[] ManyWrapperFieldsMessage_WriteToCodedOutputStream()
{
return manyWrapperFieldsTest.WriteToCodedOutputStream_PreAllocatedBuffer();
}
[Benchmark]
public byte[] ManyWrapperFieldsMessage_WriteToSpan()
{
return manyWrapperFieldsTest.WriteToSpan_PreAllocatedBuffer();
}
[Benchmark]
public byte[] ManyPrimitiveFieldsMessage_ToByteArray()
{
return manyPrimitiveFieldsTest.ToByteArray();
}
[Benchmark]
public byte[] ManyPrimitiveFieldsMessage_WriteToCodedOutputStream()
{
return manyPrimitiveFieldsTest.WriteToCodedOutputStream_PreAllocatedBuffer();
}
[Benchmark]
public byte[] ManyPrimitiveFieldsMessage_WriteToSpan()
{
return manyPrimitiveFieldsTest.WriteToSpan_PreAllocatedBuffer();
}
[Benchmark]
public byte[] EmptyMessage_ToByteArray()
{
return emptyMessageTest.ToByteArray();
}
[Benchmark]
public byte[] EmptyMessage_WriteToCodedOutputStream()
{
return emptyMessageTest.WriteToCodedOutputStream_PreAllocatedBuffer();
}
[Benchmark]
public byte[] EmptyMessage_WriteToSpan()
{
return emptyMessageTest.WriteToSpan_PreAllocatedBuffer();
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyWrapperFieldsMessage_WriteDelimitedMessagesToCodedOutputStream(int messageCount)
{
manyWrapperFieldsTest.WriteDelimitedMessagesToCodedOutputStream_PreAllocatedBuffer(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyWrapperFieldsMessage_WriteDelimitedMessagesToSpan(int messageCount)
{
manyWrapperFieldsTest.WriteDelimitedMessagesToSpan_PreAllocatedBuffer(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyPrimitiveFieldsMessage_WriteDelimitedMessagesToCodedOutputStream(int messageCount)
{
manyPrimitiveFieldsTest.WriteDelimitedMessagesToCodedOutputStream_PreAllocatedBuffer(messageCount);
}
[Benchmark]
[ArgumentsSource(nameof(MessageCountValues))]
public void ManyPrimitiveFieldsMessage_WriteDelimitedMessagesToSpan(int messageCount)
{
manyPrimitiveFieldsTest.WriteDelimitedMessagesToSpan_PreAllocatedBuffer(messageCount);
}
private class SubTest
{
private readonly IMessage message;
private readonly byte[] outputBuffer;
private readonly byte[] multipleMessagesOutputBuffer;
public SubTest(IMessage message, int maxMessageCount)
{
this.message = message;
int messageSize = message.CalculateSize();
this.outputBuffer = new byte[messageSize];
this.multipleMessagesOutputBuffer = new byte[maxMessageCount * (messageSize + CodedOutputStream.ComputeLengthSize(messageSize))];
}
public byte[] ToByteArray() => message.ToByteArray();
public byte[] WriteToCodedOutputStream_PreAllocatedBuffer()
{
var cos = new CodedOutputStream(outputBuffer); // use pre-existing output buffer
message.WriteTo(cos);
return outputBuffer;
}
public byte[] WriteToSpan_PreAllocatedBuffer()
{
var span = new Span<byte>(outputBuffer); // use pre-existing output buffer
message.WriteTo(span);
return outputBuffer;
}
public byte[] WriteDelimitedMessagesToCodedOutputStream_PreAllocatedBuffer(int messageCount)
{
var cos = new CodedOutputStream(multipleMessagesOutputBuffer); // use pre-existing output buffer
for (int i = 0; i < messageCount; i++)
{
cos.WriteMessage(message);
}
return multipleMessagesOutputBuffer;
}
public byte[] WriteDelimitedMessagesToSpan_PreAllocatedBuffer(int messageCount)
{
var span = new Span<byte>(multipleMessagesOutputBuffer); // use pre-existing output buffer
WriteContext.Initialize(ref span, out WriteContext ctx);
for (int i = 0; i < messageCount; i++)
{
ctx.WriteMessage(message);
}
return multipleMessagesOutputBuffer;
}
}
}
}

View File

@@ -0,0 +1,519 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2019 Google Inc. All rights reserved.
// https://github.com/protocolbuffers/protobuf
//
// 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 BenchmarkDotNet.Attributes;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Buffers;
using System.Text;
namespace Google.Protobuf.Benchmarks
{
/// <summary>
/// Benchmarks throughput when writing raw primitives.
/// </summary>
[MemoryDiagnoser]
public class WriteRawPrimitivesBenchmark
{
// key is the encodedSize of varint values
Dictionary<int, uint[]> varint32Values;
Dictionary<int, ulong[]> varint64Values;
double[] doubleValues;
float[] floatValues;
// key is the encodedSize of string values
Dictionary<int, string[]> stringValues;
// key is the encodedSize of string values
Dictionary<int, string[]> nonAsciiStringValues;
// key is the encodedSize of string values
Dictionary<int, ByteString[]> byteStringValues;
// the buffer to which all the data will be written
byte[] outputBuffer;
Random random = new Random(417384220); // random but deterministic seed
public IEnumerable<int> StringEncodedSizes => new[] { 1, 4, 10, 105, 10080 };
public IEnumerable<int> NonAsciiStringEncodedSizes => new[] { 4, 10, 105, 10080 };
[GlobalSetup]
public void GlobalSetup()
{
outputBuffer = new byte[BytesToWrite];
varint32Values = new Dictionary<int, uint[]>();
varint64Values = new Dictionary<int, ulong[]>();
for (int encodedSize = 1; encodedSize <= 10; encodedSize++)
{
if (encodedSize <= 5)
{
varint32Values.Add(encodedSize, CreateRandomVarints32(random, BytesToWrite / encodedSize, encodedSize));
}
varint64Values.Add(encodedSize, CreateRandomVarints64(random, BytesToWrite / encodedSize, encodedSize));
}
doubleValues = CreateRandomDoubles(random, BytesToWrite / sizeof(double));
floatValues = CreateRandomFloats(random, BytesToWrite / sizeof(float));
stringValues = new Dictionary<int, string[]>();
byteStringValues = new Dictionary<int, ByteString[]>();
foreach(var encodedSize in StringEncodedSizes)
{
stringValues.Add(encodedSize, CreateStrings(BytesToWrite / encodedSize, encodedSize));
byteStringValues.Add(encodedSize, CreateByteStrings(BytesToWrite / encodedSize, encodedSize));
}
nonAsciiStringValues = new Dictionary<int, string[]>();
foreach(var encodedSize in NonAsciiStringEncodedSizes)
{
nonAsciiStringValues.Add(encodedSize, CreateNonAsciiStrings(BytesToWrite / encodedSize, encodedSize));
}
}
// Total number of bytes that each benchmark will write.
// Measuring the time taken to write buffer of given size makes it easier to compare parsing speed for different
// types and makes it easy to calculate the througput (in MB/s)
// 10800 bytes is chosen because it is divisible by all possible encoded sizes for all primitive types {1..10}
[Params(10080)]
public int BytesToWrite { get; set; }
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
public void WriteRawVarint32_CodedOutputStream(int encodedSize)
{
var values = varint32Values[encodedSize];
var cos = new CodedOutputStream(outputBuffer);
for (int i = 0; i < values.Length; i++)
{
cos.WriteRawVarint32(values[i]);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
public void WriteRawVarint32_WriteContext(int encodedSize)
{
var values = varint32Values[encodedSize];
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
for (int i = 0; i < values.Length; i++)
{
ctx.WriteUInt32(values[i]);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
[Arguments(6)]
[Arguments(7)]
[Arguments(8)]
[Arguments(9)]
[Arguments(10)]
public void WriteRawVarint64_CodedOutputStream(int encodedSize)
{
var values = varint64Values[encodedSize];
var cos = new CodedOutputStream(outputBuffer);
for (int i = 0; i < values.Length; i++)
{
cos.WriteRawVarint64(values[i]);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
[Arguments(1)]
[Arguments(2)]
[Arguments(3)]
[Arguments(4)]
[Arguments(5)]
[Arguments(6)]
[Arguments(7)]
[Arguments(8)]
[Arguments(9)]
[Arguments(10)]
public void WriteRawVarint64_WriteContext(int encodedSize)
{
var values = varint64Values[encodedSize];
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
for (int i = 0; i < values.Length; i++)
{
ctx.WriteUInt64(values[i]);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteFixed32_CodedOutputStream()
{
const int encodedSize = sizeof(uint);
var cos = new CodedOutputStream(outputBuffer);
for (int i = 0; i < BytesToWrite / encodedSize; i++)
{
cos.WriteFixed32(12345);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteFixed32_WriteContext()
{
const int encodedSize = sizeof(uint);
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
for (uint i = 0; i < BytesToWrite / encodedSize; i++)
{
ctx.WriteFixed32(12345);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteFixed64_CodedOutputStream()
{
const int encodedSize = sizeof(ulong);
var cos = new CodedOutputStream(outputBuffer);
for(int i = 0; i < BytesToWrite / encodedSize; i++)
{
cos.WriteFixed64(123456789);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteFixed64_WriteContext()
{
const int encodedSize = sizeof(ulong);
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
for (uint i = 0; i < BytesToWrite / encodedSize; i++)
{
ctx.WriteFixed64(123456789);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteRawTag_OneByte_WriteContext()
{
const int encodedSize = 1;
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
for (uint i = 0; i < BytesToWrite / encodedSize; i++)
{
ctx.WriteRawTag(16);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteRawTag_TwoBytes_WriteContext()
{
const int encodedSize = 2;
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
for (uint i = 0; i < BytesToWrite / encodedSize; i++)
{
ctx.WriteRawTag(137, 6);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteRawTag_ThreeBytes_WriteContext()
{
const int encodedSize = 3;
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
for (uint i = 0; i < BytesToWrite / encodedSize; i++)
{
ctx.WriteRawTag(160, 131, 1);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void Baseline_WriteContext()
{
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
ctx.state.position = outputBuffer.Length;
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteRawFloat_CodedOutputStream()
{
var cos = new CodedOutputStream(outputBuffer);
foreach (var value in floatValues)
{
cos.WriteFloat(value);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteRawFloat_WriteContext()
{
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
foreach (var value in floatValues)
{
ctx.WriteFloat(value);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteRawDouble_CodedOutputStream()
{
var cos = new CodedOutputStream(outputBuffer);
foreach (var value in doubleValues)
{
cos.WriteDouble(value);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
public void WriteRawDouble_WriteContext()
{
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
foreach (var value in doubleValues)
{
ctx.WriteDouble(value);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public void WriteString_CodedOutputStream(int encodedSize)
{
var values = stringValues[encodedSize];
var cos = new CodedOutputStream(outputBuffer);
foreach (var value in values)
{
cos.WriteString(value);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public void WriteString_WriteContext(int encodedSize)
{
var values = stringValues[encodedSize];
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
foreach (var value in values)
{
ctx.WriteString(value);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
[ArgumentsSource(nameof(NonAsciiStringEncodedSizes))]
public void WriteNonAsciiString_CodedOutputStream(int encodedSize)
{
var values = nonAsciiStringValues[encodedSize];
var cos = new CodedOutputStream(outputBuffer);
foreach (var value in values)
{
cos.WriteString(value);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
[ArgumentsSource(nameof(NonAsciiStringEncodedSizes))]
public void WriteNonAsciiString_WriteContext(int encodedSize)
{
var values = nonAsciiStringValues[encodedSize];
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
foreach (var value in values)
{
ctx.WriteString(value);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public void WriteBytes_CodedOutputStream(int encodedSize)
{
var values = byteStringValues[encodedSize];
var cos = new CodedOutputStream(outputBuffer);
foreach (var value in values)
{
cos.WriteBytes(value);
}
cos.Flush();
cos.CheckNoSpaceLeft();
}
[Benchmark]
[ArgumentsSource(nameof(StringEncodedSizes))]
public void WriteBytes_WriteContext(int encodedSize)
{
var values = byteStringValues[encodedSize];
var span = new Span<byte>(outputBuffer);
WriteContext.Initialize(ref span, out WriteContext ctx);
foreach (var value in values)
{
ctx.WriteBytes(value);
}
ctx.Flush();
ctx.CheckNoSpaceLeft();
}
private static uint[] CreateRandomVarints32(Random random, int valueCount, int encodedSize)
{
var result = new uint[valueCount];
for (int i = 0; i < valueCount; i++)
{
result[i] = (uint) ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, true);
}
return result;
}
private static ulong[] CreateRandomVarints64(Random random, int valueCount, int encodedSize)
{
var result = new ulong[valueCount];
for (int i = 0; i < valueCount; i++)
{
result[i] = ParseRawPrimitivesBenchmark.RandomUnsignedVarint(random, encodedSize, false);
}
return result;
}
private static float[] CreateRandomFloats(Random random, int valueCount)
{
var result = new float[valueCount];
for (int i = 0; i < valueCount; i++)
{
result[i] = (float)random.NextDouble();
}
return result;
}
private static double[] CreateRandomDoubles(Random random, int valueCount)
{
var result = new double[valueCount];
for (int i = 0; i < valueCount; i++)
{
result[i] = random.NextDouble();
}
return result;
}
private static string[] CreateStrings(int valueCount, int encodedSize)
{
var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize);
var result = new string[valueCount];
for (int i = 0; i < valueCount; i++)
{
result[i] = str;
}
return result;
}
private static string[] CreateNonAsciiStrings(int valueCount, int encodedSize)
{
var str = ParseRawPrimitivesBenchmark.CreateNonAsciiStringWithEncodedSize(encodedSize);
var result = new string[valueCount];
for (int i = 0; i < valueCount; i++)
{
result[i] = str;
}
return result;
}
private static ByteString[] CreateByteStrings(int valueCount, int encodedSize)
{
var str = ParseRawPrimitivesBenchmark.CreateStringWithEncodedSize(encodedSize);
var result = new ByteString[valueCount];
for (int i = 0; i < valueCount; i++)
{
result[i] = ByteString.CopyFrom(Encoding.UTF8.GetBytes(str));
}
return result;
}
}
}

View File

@@ -0,0 +1,237 @@
syntax = "proto3";
package google.protobuf.benchmarks;
import "google/protobuf/wrappers.proto";
// a message that has a large number of wrapper fields
// obfuscated version of an internal message
message ManyWrapperFieldsMessage {
google.protobuf.DoubleValue double_field_95 = 95;
google.protobuf.DoubleValue double_field_1 = 1;
google.protobuf.DoubleValue double_field_79 = 79;
google.protobuf.Int64Value int64_field_2 = 2;
google.protobuf.DoubleValue double_field_96 = 96;
google.protobuf.Int64Value int64_field_3 = 3;
google.protobuf.Int64Value int64_field_4 = 4;
google.protobuf.DoubleValue double_field_97 = 97;
google.protobuf.DoubleValue double_field_65 = 65;
google.protobuf.DoubleValue double_field_66 = 66;
google.protobuf.DoubleValue double_field_7 = 7;
google.protobuf.DoubleValue double_field_62 = 62;
google.protobuf.DoubleValue double_field_118 = 118;
google.protobuf.DoubleValue double_field_119 = 119;
google.protobuf.DoubleValue double_field_67 = 67;
google.protobuf.DoubleValue double_field_120 = 120;
google.protobuf.DoubleValue double_field_121 = 121;
google.protobuf.DoubleValue double_field_122 = 122;
google.protobuf.DoubleValue double_field_123 = 123;
google.protobuf.DoubleValue double_field_124 = 124;
google.protobuf.DoubleValue double_field_8 = 8;
google.protobuf.DoubleValue double_field_9 = 9;
google.protobuf.DoubleValue double_field_98 = 98;
google.protobuf.DoubleValue double_field_10 = 10;
google.protobuf.DoubleValue double_field_11 = 11;
google.protobuf.DoubleValue double_field_99 = 99;
google.protobuf.DoubleValue double_field_84 = 84;
google.protobuf.DoubleValue double_field_14 = 14;
google.protobuf.DoubleValue double_field_77 = 77;
google.protobuf.DoubleValue double_field_15 = 15;
google.protobuf.Int64Value int64_field_19 = 19;
google.protobuf.Int64Value int64_field_115 = 115;
google.protobuf.DoubleValue double_field_116 = 116;
google.protobuf.Int64Value int64_field_117 = 117;
google.protobuf.DoubleValue double_field_20 = 20;
google.protobuf.DoubleValue double_field_21 = 21;
google.protobuf.StringValue string_field_73 = 73;
google.protobuf.StringValue string_field_74 = 74;
google.protobuf.DoubleValue double_field_22 = 22;
google.protobuf.DoubleValue double_field_69 = 69;
google.protobuf.DoubleValue double_field_70 = 70;
google.protobuf.DoubleValue double_field_71 = 71;
google.protobuf.DoubleValue double_field_72 = 72;
google.protobuf.DoubleValue double_field_25 = 25;
google.protobuf.Int64Value int64_field_26 = 26;
google.protobuf.DoubleValue double_field_68 = 68;
google.protobuf.DoubleValue double_field_28 = 28;
google.protobuf.DoubleValue double_field_106 = 106;
google.protobuf.DoubleValue double_field_29 = 29;
google.protobuf.DoubleValue double_field_30 = 30;
google.protobuf.DoubleValue double_field_101 = 101;
google.protobuf.DoubleValue double_field_102 = 102;
google.protobuf.DoubleValue double_field_103 = 103;
google.protobuf.DoubleValue double_field_104 = 104;
google.protobuf.DoubleValue double_field_105 = 105;
google.protobuf.DoubleValue double_field_31 = 31;
google.protobuf.Int64Value int64_field_32 = 32;
google.protobuf.DoubleValue double_field_75 = 75;
google.protobuf.DoubleValue double_field_129 = 129;
int32 enum_field_80 = 80;
int32 enum_field_81 = 81;
google.protobuf.Int64Value int64_field_82 = 82;
int32 enum_field_83 = 83;
google.protobuf.Int64Value int64_field_85 = 85;
google.protobuf.Int64Value int64_field_86 = 86;
google.protobuf.Int64Value int64_field_87 = 87;
google.protobuf.Int64Value int64_field_125 = 125;
google.protobuf.Int64Value int64_field_37 = 37;
google.protobuf.DoubleValue double_field_38 = 38;
google.protobuf.Int64Value interactions = 39;
repeated int32 repeated_int_field_100 = 100;
google.protobuf.DoubleValue double_field_40 = 40;
google.protobuf.Int64Value int64_field_41 = 41;
google.protobuf.Int64Value int64_field_126 = 126;
google.protobuf.Int64Value int64_field_127 = 127;
google.protobuf.DoubleValue double_field_128 = 128;
google.protobuf.DoubleValue double_field_109 = 109;
google.protobuf.Int64Value int64_field_110 = 110;
google.protobuf.DoubleValue double_field_111 = 111;
google.protobuf.Int64Value int64_field_112 = 112;
google.protobuf.DoubleValue double_field_113 = 113;
google.protobuf.Int64Value int64_field_114 = 114;
google.protobuf.DoubleValue double_field_42 = 42;
google.protobuf.Int64Value int64_field_43 = 43;
google.protobuf.Int64Value int64_field_44 = 44;
google.protobuf.DoubleValue double_field_45 = 45;
google.protobuf.DoubleValue double_field_46 = 46;
google.protobuf.DoubleValue double_field_78 = 78;
google.protobuf.DoubleValue double_field_88 = 88;
google.protobuf.DoubleValue double_field_47 = 47;
google.protobuf.DoubleValue double_field_89 = 89;
google.protobuf.DoubleValue double_field_48 = 48;
google.protobuf.DoubleValue double_field_49 = 49;
google.protobuf.DoubleValue double_field_50 = 50;
google.protobuf.DoubleValue double_field_90 = 90;
google.protobuf.DoubleValue double_field_51 = 51;
google.protobuf.DoubleValue double_field_91 = 91;
google.protobuf.DoubleValue double_field_92 = 92;
google.protobuf.Int64Value int64_field_107 = 107;
google.protobuf.DoubleValue double_field_93 = 93;
google.protobuf.DoubleValue double_field_108 = 108;
google.protobuf.DoubleValue double_field_52 = 52;
google.protobuf.DoubleValue double_field_53 = 53;
google.protobuf.DoubleValue double_field_94 = 94;
google.protobuf.DoubleValue double_field_54 = 54;
google.protobuf.DoubleValue double_field_55 = 55;
google.protobuf.DoubleValue double_field_56 = 56;
google.protobuf.DoubleValue double_field_57 = 57;
google.protobuf.DoubleValue double_field_58 = 58;
google.protobuf.Int64Value int64_field_59 = 59;
google.protobuf.Int64Value int64_field_60 = 60;
}
// same as ManyWrapperFieldsMessages, but with primitive fields
// for comparison.
message ManyPrimitiveFieldsMessage {
double double_field_95 = 95;
double double_field_1 = 1;
double double_field_79 = 79;
int64 int64_field_2 = 2;
double double_field_96 = 96;
int64 int64_field_3 = 3;
int64 int64_field_4 = 4;
double double_field_97 = 97;
double double_field_65 = 65;
double double_field_66 = 66;
double double_field_7 = 7;
double double_field_62 = 62;
double double_field_118 = 118;
double double_field_119 = 119;
double double_field_67 = 67;
double double_field_120 = 120;
double double_field_121 = 121;
double double_field_122 = 122;
double double_field_123 = 123;
double double_field_124 = 124;
double double_field_8 = 8;
double double_field_9 = 9;
double double_field_98 = 98;
double double_field_10 = 10;
double double_field_11 = 11;
double double_field_99 = 99;
double double_field_84 = 84;
double double_field_14 = 14;
double double_field_77 = 77;
double double_field_15 = 15;
int64 int64_field_19 = 19;
int64 int64_field_115 = 115;
double double_field_116 = 116;
int64 int64_field_117 = 117;
double double_field_20 = 20;
double double_field_21 = 21;
string string_field_73 = 73;
string string_field_74 = 74;
double double_field_22 = 22;
double double_field_69 = 69;
double double_field_70 = 70;
double double_field_71 = 71;
double double_field_72 = 72;
double double_field_25 = 25;
int64 int64_field_26 = 26;
double double_field_68 = 68;
double double_field_28 = 28;
double double_field_106 = 106;
double double_field_29 = 29;
double double_field_30 = 30;
double double_field_101 = 101;
double double_field_102 = 102;
double double_field_103 = 103;
double double_field_104 = 104;
double double_field_105 = 105;
double double_field_31 = 31;
int64 int64_field_32 = 32;
double double_field_75 = 75;
double double_field_129 = 129;
int32 enum_field_80 = 80;
int32 enum_field_81 = 81;
int64 int64_field_82 = 82;
int32 enum_field_83 = 83;
int64 int64_field_85 = 85;
int64 int64_field_86 = 86;
int64 int64_field_87 = 87;
int64 int64_field_125 = 125;
int64 int64_field_37 = 37;
double double_field_38 = 38;
int64 interactions = 39;
repeated int32 repeated_int_field_100 = 100;
double double_field_40 = 40;
int64 int64_field_41 = 41;
int64 int64_field_126 = 126;
int64 int64_field_127 = 127;
double double_field_128 = 128;
double double_field_109 = 109;
int64 int64_field_110 = 110;
double double_field_111 = 111;
int64 int64_field_112 = 112;
double double_field_113 = 113;
int64 int64_field_114 = 114;
double double_field_42 = 42;
int64 int64_field_43 = 43;
int64 int64_field_44 = 44;
double double_field_45 = 45;
double double_field_46 = 46;
double double_field_78 = 78;
double double_field_88 = 88;
double double_field_47 = 47;
double double_field_89 = 89;
double double_field_48 = 48;
double double_field_49 = 49;
double double_field_50 = 50;
double double_field_90 = 90;
double double_field_51 = 51;
double double_field_91 = 91;
double double_field_92 = 92;
int64 int64_field_107 = 107;
double double_field_93 = 93;
double double_field_108 = 108;
double double_field_52 = 52;
double double_field_53 = 53;
double double_field_94 = 94;
double double_field_54 = 54;
double double_field_55 = 55;
double double_field_56 = 56;
double double_field_57 = 57;
double double_field_58 = 58;
int64 int64_field_59 = 59;
int64 int64_field_60 = 60;
}

View File

@@ -1,97 +0,0 @@
load("//build_defs:internal_shell.bzl", "inline_sh_binary")
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
inline_sh_binary(
name = "build_conformance_test",
srcs = ["Google.Protobuf.Conformance.csproj"],
cmd = "dotnet build -c Release $(SRCS)",
visibility = ["//visibility:private"],
)
CONFORMANCE_DEPS = [
"Google.Protobuf.dll",
"Google.Protobuf.Conformance.deps.json",
"Google.Protobuf.Conformance.pdb",
"Google.Protobuf.Conformance.runtimeconfig.json",
"Google.Protobuf.Test.dll",
"Google.Protobuf.Test.TestProtos.dll",
"Microsoft.TestPlatform.CommunicationUtilities.dll",
"Microsoft.TestPlatform.CoreUtilities.dll",
"Microsoft.TestPlatform.CrossPlatEngine.dll",
"Microsoft.TestPlatform.PlatformAbstractions.dll",
"Microsoft.TestPlatform.Utilities.dll",
"Microsoft.VisualStudio.CodeCoverage.Shim.dll",
"Microsoft.VisualStudio.TestPlatform.Common.dll",
"Microsoft.VisualStudio.TestPlatform.ObjectModel.dll",
"NUnit3.TestAdapter.dll",
"Newtonsoft.Json.dll",
"NuGet.Frameworks.dll",
"nunit.engine.api.dll",
"nunit.engine.core.dll",
"nunit.engine.dll",
"nunit.framework.dll",
"testcentric.engine.metadata.dll",
"testhost.dll",
]
filegroup(
name = "srcs",
srcs = [
"Conformance.cs",
"Program.cs",
"Google.Protobuf.Conformance.csproj",
],
visibility = [
"//csharp:__subpackages__",
],
)
genrule(
name = "package_conformance_test",
srcs = [
"Program.cs",
"Google.Protobuf.Conformance.csproj",
"//conformance:conformance_csharp_proto",
"//csharp:srcs",
],
visibility = ["//visibility:private"],
tools = [":build_conformance_test"],
outs = CONFORMANCE_DEPS + ["Google.Protobuf.Conformance.dll"],
cmd = """
SRCDIR=$$(dirname $(location :Program.cs))
cp $(location //conformance:conformance_csharp_proto) $$SRCDIR
DOTNET_CLI_HOME=/tmp ./$(location :build_conformance_test)
cp -r $$SRCDIR/bin/Release/netcoreapp3.1/* $(RULEDIR)
""",
)
filegroup(
name = "conformance_dll",
srcs = ["Google.Protobuf.Conformance.dll"],
data = [":package_conformance_test"],
visibility = ["//conformance:__subpackages__"],
)
filegroup(
name = "conformance_runfiles",
srcs = CONFORMANCE_DEPS,
data = [":package_conformance_test"],
visibility = ["//conformance:__subpackages__"],
)
################################################################################
# Distribution files
################################################################################
pkg_files(
name = "dist_files",
srcs = [
"BUILD.bazel",
"Google.Protobuf.Conformance.csproj",
"Conformance.cs",
"Program.cs",
],
strip_prefix = strip_prefix.from_root(""),
visibility = ["//csharp:__pkg__"],
)

View File

@@ -43,7 +43,7 @@ namespace Google.Protobuf.Conformance
/// </summary>
class Program
{
private static void Main()
private static void Main(string[] args)
{
// This way we get the binary streams instead of readers/writers.
var input = new BinaryReader(Console.OpenStandardInput());
@@ -100,22 +100,32 @@ namespace Google.Protobuf.Conformance
return new ConformanceResponse { Skipped = "CSharp doesn't support skipping unknown fields in json parsing." };
}
var parser = new JsonParser(new JsonParser.Settings(20, typeRegistry));
message = request.MessageType switch
switch (request.MessageType)
{
"protobuf_test_messages.proto3.TestAllTypesProto3" => parser.Parse<ProtobufTestMessages.Proto3.TestAllTypesProto3>(request.JsonPayload),
"protobuf_test_messages.proto2.TestAllTypesProto2" => parser.Parse<ProtobufTestMessages.Proto2.TestAllTypesProto2>(request.JsonPayload),
_ => throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"),
};
case "protobuf_test_messages.proto3.TestAllTypesProto3":
message = parser.Parse<ProtobufTestMessages.Proto3.TestAllTypesProto3>(request.JsonPayload);
break;
case "protobuf_test_messages.proto2.TestAllTypesProto2":
message = parser.Parse<ProtobufTestMessages.Proto2.TestAllTypesProto2>(request.JsonPayload);
break;
default:
throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})");
}
break;
case ConformanceRequest.PayloadOneofCase.ProtobufPayload:
message = request.MessageType switch
switch (request.MessageType)
{
"protobuf_test_messages.proto3.TestAllTypesProto3" => ProtobufTestMessages.Proto3.TestAllTypesProto3.Parser.ParseFrom(request.ProtobufPayload),
"protobuf_test_messages.proto2.TestAllTypesProto2" => ProtobufTestMessages.Proto2.TestAllTypesProto2.Parser
.WithExtensionRegistry(proto2ExtensionRegistry)
.ParseFrom(request.ProtobufPayload),
_ => throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})"),
};
case "protobuf_test_messages.proto3.TestAllTypesProto3":
message = ProtobufTestMessages.Proto3.TestAllTypesProto3.Parser.ParseFrom(request.ProtobufPayload);
break;
case "protobuf_test_messages.proto2.TestAllTypesProto2":
message = ProtobufTestMessages.Proto2.TestAllTypesProto2.Parser
.WithExtensionRegistry(proto2ExtensionRegistry)
.ParseFrom(request.ProtobufPayload);
break;
default:
throw new Exception($" Protobuf request doesn't have specific payload type ({request.MessageType})");
}
break;
case ConformanceRequest.PayloadOneofCase.TextPayload:
return new ConformanceResponse { Skipped = "CSharp doesn't support text format" };

View File

@@ -7,7 +7,7 @@
-->
<PropertyGroup>
<TargetFrameworks>net462;netstandard1.1;netstandard2.0</TargetFrameworks>
<LangVersion>10.0</LangVersion>
<LangVersion>3.0</LangVersion>
<AssemblyOriginatorKeyFile>../../keys/Google.Protobuf.snk</AssemblyOriginatorKeyFile>
<SignAssembly>true</SignAssembly>
<IsPackable>False</IsPackable>

View File

@@ -580,23 +580,23 @@ namespace Google.Protobuf.TestProtos {
if (other == null) {
return;
}
mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
mapInt32Float_.MergeFrom(other.mapInt32Float_);
mapInt32Double_.MergeFrom(other.mapInt32Double_);
mapBoolBool_.MergeFrom(other.mapBoolBool_);
mapStringString_.MergeFrom(other.mapStringString_);
mapInt32Bytes_.MergeFrom(other.mapInt32Bytes_);
mapInt32Enum_.MergeFrom(other.mapInt32Enum_);
mapInt32ForeignMessage_.MergeFrom(other.mapInt32ForeignMessage_);
mapInt32Int32_.Add(other.mapInt32Int32_);
mapInt64Int64_.Add(other.mapInt64Int64_);
mapUint32Uint32_.Add(other.mapUint32Uint32_);
mapUint64Uint64_.Add(other.mapUint64Uint64_);
mapSint32Sint32_.Add(other.mapSint32Sint32_);
mapSint64Sint64_.Add(other.mapSint64Sint64_);
mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
mapInt32Float_.Add(other.mapInt32Float_);
mapInt32Double_.Add(other.mapInt32Double_);
mapBoolBool_.Add(other.mapBoolBool_);
mapStringString_.Add(other.mapStringString_);
mapInt32Bytes_.Add(other.mapInt32Bytes_);
mapInt32Enum_.Add(other.mapInt32Enum_);
mapInt32ForeignMessage_.Add(other.mapInt32ForeignMessage_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1100,7 +1100,7 @@ namespace Google.Protobuf.TestProtos {
if (other == null) {
return;
}
mapInt32Message_.MergeFrom(other.mapInt32Message_);
mapInt32Message_.Add(other.mapInt32Message_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1298,8 +1298,8 @@ namespace Google.Protobuf.TestProtos {
if (other == null) {
return;
}
map1_.MergeFrom(other.map1_);
map2_.MergeFrom(other.map2_);
map1_.Add(other.map1_);
map2_.Add(other.map2_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -1723,21 +1723,21 @@ namespace Google.Protobuf.TestProtos {
if (other == null) {
return;
}
mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
mapInt32Float_.MergeFrom(other.mapInt32Float_);
mapInt32Double_.MergeFrom(other.mapInt32Double_);
mapBoolBool_.MergeFrom(other.mapBoolBool_);
mapInt32Enum_.MergeFrom(other.mapInt32Enum_);
mapInt32ForeignMessage_.MergeFrom(other.mapInt32ForeignMessage_);
mapInt32Int32_.Add(other.mapInt32Int32_);
mapInt64Int64_.Add(other.mapInt64Int64_);
mapUint32Uint32_.Add(other.mapUint32Uint32_);
mapUint64Uint64_.Add(other.mapUint64Uint64_);
mapSint32Sint32_.Add(other.mapSint32Sint32_);
mapSint64Sint64_.Add(other.mapSint64Sint64_);
mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
mapInt32Float_.Add(other.mapInt32Float_);
mapInt32Double_.Add(other.mapInt32Double_);
mapBoolBool_.Add(other.mapBoolBool_);
mapInt32Enum_.Add(other.mapInt32Enum_);
mapInt32ForeignMessage_.Add(other.mapInt32ForeignMessage_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -2031,7 +2031,7 @@ namespace Google.Protobuf.TestProtos {
if (other == null) {
return;
}
type_.MergeFrom(other.type_);
type_.Add(other.type_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -2224,7 +2224,7 @@ namespace Google.Protobuf.TestProtos {
if (other == null) {
return;
}
entry_.MergeFrom(other.entry_);
entry_.Add(other.entry_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}

View File

@@ -213,14 +213,12 @@ namespace ProtobufTestMessages.Proto2 {
"dGlvbmFsX2Jvb2wY7gcgASgIEhcKDnJlcGVhdGVkX2ludDMyGPMHIAMoBRoa",
"Cg1PcHRpb25hbEdyb3VwEgkKAWEYASABKAUiFgoUTnVsbEh5cG90aGVzaXNQ",
"cm90bzIiLwoORW51bU9ubHlQcm90bzIiHQoEQm9vbBIKCgZrRmFsc2UQABIJ",
"CgVrVHJ1ZRABIh8KD09uZVN0cmluZ1Byb3RvMhIMCgRkYXRhGAEgASgJIkYK",
"EVByb3RvV2l0aEtleXdvcmRzEg4KBmlubGluZRgBIAEoBRIPCgdjb25jZXB0",
"GAIgASgJEhAKCHJlcXVpcmVzGAMgAygJKkYKEUZvcmVpZ25FbnVtUHJvdG8y",
"Eg8KC0ZPUkVJR05fRk9PEAASDwoLRk9SRUlHTl9CQVIQARIPCgtGT1JFSUdO",
"X0JBWhACOkoKD2V4dGVuc2lvbl9pbnQzMhIxLnByb3RvYnVmX3Rlc3RfbWVz",
"c2FnZXMucHJvdG8yLlRlc3RBbGxUeXBlc1Byb3RvMhh4IAEoBUI4Cihjb20u",
"Z29vZ2xlLnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8ySAH4AQGiAgZQ",
"cm90bzI="));
"CgVrVHJ1ZRABIh8KD09uZVN0cmluZ1Byb3RvMhIMCgRkYXRhGAEgASgJKkYK",
"EUZvcmVpZ25FbnVtUHJvdG8yEg8KC0ZPUkVJR05fRk9PEAASDwoLRk9SRUlH",
"Tl9CQVIQARIPCgtGT1JFSUdOX0JBWhACOkoKD2V4dGVuc2lvbl9pbnQzMhIx",
"LnByb3RvYnVmX3Rlc3RfbWVzc2FnZXMucHJvdG8yLlRlc3RBbGxUeXBlc1By",
"b3RvMhh4IAEoBUIvCihjb20uZ29vZ2xlLnByb3RvYnVmX3Rlc3RfbWVzc2Fn",
"ZXMucHJvdG8ySAH4AQE="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::ProtobufTestMessages.Proto2.ForeignEnumProto2), }, new pb::Extension[] { TestMessagesProto2Extensions.ExtensionInt32 }, new pbr::GeneratedClrTypeInfo[] {
@@ -233,8 +231,7 @@ namespace ProtobufTestMessages.Proto2 {
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Parser, new[]{ "OptionalInt32", "OptionalString", "NestedMessage", "OptionalGroup", "OptionalBool", "RepeatedInt32" }, null, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup), global::ProtobufTestMessages.Proto2.UnknownToTestAllTypes.Types.OptionalGroup.Parser, new[]{ "A" }, null, null, null, null)}),
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.NullHypothesisProto2), global::ProtobufTestMessages.Proto2.NullHypothesisProto2.Parser, null, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2), global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Parser, null, null, new[]{ typeof(global::ProtobufTestMessages.Proto2.EnumOnlyProto2.Types.Bool) }, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.OneStringProto2), global::ProtobufTestMessages.Proto2.OneStringProto2.Parser, new[]{ "Data" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.ProtoWithKeywords), global::ProtobufTestMessages.Proto2.ProtoWithKeywords.Parser, new[]{ "Inline", "Concept", "Requires" }, null, null, null, null)
new pbr::GeneratedClrTypeInfo(typeof(global::ProtobufTestMessages.Proto2.OneStringProto2), global::ProtobufTestMessages.Proto2.OneStringProto2.Parser, new[]{ "Data" }, null, null, null, null)
}));
}
#endregion
@@ -4345,25 +4342,25 @@ namespace ProtobufTestMessages.Proto2 {
unpackedDouble_.Add(other.unpackedDouble_);
unpackedBool_.Add(other.unpackedBool_);
unpackedNestedEnum_.Add(other.unpackedNestedEnum_);
mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
mapInt32Float_.MergeFrom(other.mapInt32Float_);
mapInt32Double_.MergeFrom(other.mapInt32Double_);
mapBoolBool_.MergeFrom(other.mapBoolBool_);
mapStringString_.MergeFrom(other.mapStringString_);
mapStringBytes_.MergeFrom(other.mapStringBytes_);
mapStringNestedMessage_.MergeFrom(other.mapStringNestedMessage_);
mapStringForeignMessage_.MergeFrom(other.mapStringForeignMessage_);
mapStringNestedEnum_.MergeFrom(other.mapStringNestedEnum_);
mapStringForeignEnum_.MergeFrom(other.mapStringForeignEnum_);
mapInt32Int32_.Add(other.mapInt32Int32_);
mapInt64Int64_.Add(other.mapInt64Int64_);
mapUint32Uint32_.Add(other.mapUint32Uint32_);
mapUint64Uint64_.Add(other.mapUint64Uint64_);
mapSint32Sint32_.Add(other.mapSint32Sint32_);
mapSint64Sint64_.Add(other.mapSint64Sint64_);
mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
mapInt32Float_.Add(other.mapInt32Float_);
mapInt32Double_.Add(other.mapInt32Double_);
mapBoolBool_.Add(other.mapBoolBool_);
mapStringString_.Add(other.mapStringString_);
mapStringBytes_.Add(other.mapStringBytes_);
mapStringNestedMessage_.Add(other.mapStringNestedMessage_);
mapStringForeignMessage_.Add(other.mapStringForeignMessage_);
mapStringNestedEnum_.Add(other.mapStringNestedEnum_);
mapStringForeignEnum_.Add(other.mapStringForeignEnum_);
if (other.HasData) {
if (!HasData) {
Data = new global::ProtobufTestMessages.Proto2.TestAllTypesProto2.Types.Data();
@@ -8303,289 +8300,6 @@ namespace ProtobufTestMessages.Proto2 {
}
public sealed partial class ProtoWithKeywords : pb::IMessage<ProtoWithKeywords>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<ProtoWithKeywords> _parser = new pb::MessageParser<ProtoWithKeywords>(() => new ProtoWithKeywords());
private pb::UnknownFieldSet _unknownFields;
private int _hasBits0;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<ProtoWithKeywords> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::ProtobufTestMessages.Proto2.TestMessagesProto2Reflection.Descriptor.MessageTypes[6]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public ProtoWithKeywords() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public ProtoWithKeywords(ProtoWithKeywords other) : this() {
_hasBits0 = other._hasBits0;
inline_ = other.inline_;
concept_ = other.concept_;
requires_ = other.requires_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public ProtoWithKeywords Clone() {
return new ProtoWithKeywords(this);
}
/// <summary>Field number for the "inline" field.</summary>
public const int InlineFieldNumber = 1;
private readonly static int InlineDefaultValue = 0;
private int inline_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Inline {
get { if ((_hasBits0 & 1) != 0) { return inline_; } else { return InlineDefaultValue; } }
set {
_hasBits0 |= 1;
inline_ = value;
}
}
/// <summary>Gets whether the "inline" field is set</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool HasInline {
get { return (_hasBits0 & 1) != 0; }
}
/// <summary>Clears the value of the "inline" field</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void ClearInline() {
_hasBits0 &= ~1;
}
/// <summary>Field number for the "concept" field.</summary>
public const int ConceptFieldNumber = 2;
private readonly static string ConceptDefaultValue = "";
private string concept_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public string Concept {
get { return concept_ ?? ConceptDefaultValue; }
set {
concept_ = pb::ProtoPreconditions.CheckNotNull(value, "value");
}
}
/// <summary>Gets whether the "concept" field is set</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool HasConcept {
get { return concept_ != null; }
}
/// <summary>Clears the value of the "concept" field</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void ClearConcept() {
concept_ = null;
}
/// <summary>Field number for the "requires" field.</summary>
public const int RequiresFieldNumber = 3;
private static readonly pb::FieldCodec<string> _repeated_requires_codec
= pb::FieldCodec.ForString(26);
private readonly pbc::RepeatedField<string> requires_ = new pbc::RepeatedField<string>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public pbc::RepeatedField<string> Requires {
get { return requires_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as ProtoWithKeywords);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(ProtoWithKeywords other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (Inline != other.Inline) return false;
if (Concept != other.Concept) return false;
if(!requires_.Equals(other.requires_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (HasInline) hash ^= Inline.GetHashCode();
if (HasConcept) hash ^= Concept.GetHashCode();
hash ^= requires_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (HasInline) {
output.WriteRawTag(8);
output.WriteInt32(Inline);
}
if (HasConcept) {
output.WriteRawTag(18);
output.WriteString(Concept);
}
requires_.WriteTo(output, _repeated_requires_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (HasInline) {
output.WriteRawTag(8);
output.WriteInt32(Inline);
}
if (HasConcept) {
output.WriteRawTag(18);
output.WriteString(Concept);
}
requires_.WriteTo(ref output, _repeated_requires_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (HasInline) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Inline);
}
if (HasConcept) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(Concept);
}
size += requires_.CalculateSize(_repeated_requires_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(ProtoWithKeywords other) {
if (other == null) {
return;
}
if (other.HasInline) {
Inline = other.Inline;
}
if (other.HasConcept) {
Concept = other.Concept;
}
requires_.Add(other.requires_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
Inline = input.ReadInt32();
break;
}
case 18: {
Concept = input.ReadString();
break;
}
case 26: {
requires_.AddEntriesFrom(input, _repeated_requires_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 8: {
Inline = input.ReadInt32();
break;
}
case 18: {
Concept = input.ReadString();
break;
}
case 26: {
requires_.AddEntriesFrom(ref input, _repeated_requires_codec);
break;
}
}
}
}
#endif
}
#endregion
}

View File

@@ -3753,25 +3753,25 @@ namespace ProtobufTestMessages.Proto3 {
unpackedDouble_.Add(other.unpackedDouble_);
unpackedBool_.Add(other.unpackedBool_);
unpackedNestedEnum_.Add(other.unpackedNestedEnum_);
mapInt32Int32_.MergeFrom(other.mapInt32Int32_);
mapInt64Int64_.MergeFrom(other.mapInt64Int64_);
mapUint32Uint32_.MergeFrom(other.mapUint32Uint32_);
mapUint64Uint64_.MergeFrom(other.mapUint64Uint64_);
mapSint32Sint32_.MergeFrom(other.mapSint32Sint32_);
mapSint64Sint64_.MergeFrom(other.mapSint64Sint64_);
mapFixed32Fixed32_.MergeFrom(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.MergeFrom(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.MergeFrom(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.MergeFrom(other.mapSfixed64Sfixed64_);
mapInt32Float_.MergeFrom(other.mapInt32Float_);
mapInt32Double_.MergeFrom(other.mapInt32Double_);
mapBoolBool_.MergeFrom(other.mapBoolBool_);
mapStringString_.MergeFrom(other.mapStringString_);
mapStringBytes_.MergeFrom(other.mapStringBytes_);
mapStringNestedMessage_.MergeFrom(other.mapStringNestedMessage_);
mapStringForeignMessage_.MergeFrom(other.mapStringForeignMessage_);
mapStringNestedEnum_.MergeFrom(other.mapStringNestedEnum_);
mapStringForeignEnum_.MergeFrom(other.mapStringForeignEnum_);
mapInt32Int32_.Add(other.mapInt32Int32_);
mapInt64Int64_.Add(other.mapInt64Int64_);
mapUint32Uint32_.Add(other.mapUint32Uint32_);
mapUint64Uint64_.Add(other.mapUint64Uint64_);
mapSint32Sint32_.Add(other.mapSint32Sint32_);
mapSint64Sint64_.Add(other.mapSint64Sint64_);
mapFixed32Fixed32_.Add(other.mapFixed32Fixed32_);
mapFixed64Fixed64_.Add(other.mapFixed64Fixed64_);
mapSfixed32Sfixed32_.Add(other.mapSfixed32Sfixed32_);
mapSfixed64Sfixed64_.Add(other.mapSfixed64Sfixed64_);
mapInt32Float_.Add(other.mapInt32Float_);
mapInt32Double_.Add(other.mapInt32Double_);
mapBoolBool_.Add(other.mapBoolBool_);
mapStringString_.Add(other.mapStringString_);
mapStringBytes_.Add(other.mapStringBytes_);
mapStringNestedMessage_.Add(other.mapStringNestedMessage_);
mapStringForeignMessage_.Add(other.mapStringForeignMessage_);
mapStringNestedEnum_.Add(other.mapStringNestedEnum_);
mapStringForeignEnum_.Add(other.mapStringForeignEnum_);
if (other.optionalBoolWrapper_ != null) {
if (optionalBoolWrapper_ == null || other.OptionalBoolWrapper != false) {
OptionalBoolWrapper = other.OptionalBoolWrapper;

View File

@@ -24112,7 +24112,7 @@ namespace Google.Protobuf.TestProtos.Proto2 {
if (other == null) {
return;
}
foo_.MergeFrom(other.foo_);
foo_.Add(other.foo_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
@@ -30708,7 +30708,7 @@ namespace Google.Protobuf.TestProtos.Proto2 {
}
OptionalGroup.MergeFrom(other.OptionalGroup);
}
stringStringMap_.MergeFrom(other.stringStringMap_);
stringStringMap_.Add(other.stringStringMap_);
switch (other.OneofFieldCase) {
case OneofFieldOneofCase.OneofUint32:
OneofUint32 = other.OneofUint32;

View File

@@ -30,44 +30,37 @@ namespace UnitTest.Issues.TestProtos {
"EiwKBXZhbHVlGAEgASgOMh0udW5pdHRlc3RfaXNzdWVzLk5lZ2F0aXZlRW51",
"bRIxCgZ2YWx1ZXMYAiADKA4yHS51bml0dGVzdF9pc3N1ZXMuTmVnYXRpdmVF",
"bnVtQgIQABI4Cg1wYWNrZWRfdmFsdWVzGAMgAygOMh0udW5pdHRlc3RfaXNz",
"dWVzLk5lZ2F0aXZlRW51bUICEAEiFQoPRGVwcmVjYXRlZENoaWxkOgIYASK5",
"AgoXRGVwcmVjYXRlZEZpZWxkc01lc3NhZ2USGgoOUHJpbWl0aXZlVmFsdWUY",
"ASABKAVCAhgBEhoKDlByaW1pdGl2ZUFycmF5GAIgAygFQgIYARI6CgxNZXNz",
"YWdlVmFsdWUYAyABKAsyIC51bml0dGVzdF9pc3N1ZXMuRGVwcmVjYXRlZENo",
"aWxkQgIYARI6CgxNZXNzYWdlQXJyYXkYBCADKAsyIC51bml0dGVzdF9pc3N1",
"ZXMuRGVwcmVjYXRlZENoaWxkQgIYARI2CglFbnVtVmFsdWUYBSABKA4yHy51",
"bml0dGVzdF9pc3N1ZXMuRGVwcmVjYXRlZEVudW1CAhgBEjYKCUVudW1BcnJh",
"eRgGIAMoDjIfLnVuaXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkRW51bUICGAEi",
"GQoJSXRlbUZpZWxkEgwKBGl0ZW0YASABKAUiRAoNUmVzZXJ2ZWROYW1lcxIN",
"CgV0eXBlcxgBIAEoBRISCgpkZXNjcmlwdG9yGAIgASgFGhAKDlNvbWVOZXN0",
"ZWRUeXBlIqABChVUZXN0SnNvbkZpZWxkT3JkZXJpbmcSEwoLcGxhaW5faW50",
"MzIYBCABKAUSEwoJbzFfc3RyaW5nGAIgASgJSAASEgoIbzFfaW50MzIYBSAB",
"KAVIABIUCgxwbGFpbl9zdHJpbmcYASABKAkSEgoIbzJfaW50MzIYBiABKAVI",
"ARITCglvMl9zdHJpbmcYAyABKAlIAUIECgJvMUIECgJvMiJLCgxUZXN0SnNv",
"bk5hbWUSDAoEbmFtZRgBIAEoCRIZCgtkZXNjcmlwdGlvbhgCIAEoCVIEZGVz",
"YxISCgRndWlkGAMgASgJUgRleGlkIn8KDE9uZW9mTWVyZ2luZxIOCgR0ZXh0",
"GAEgASgJSAASNgoGbmVzdGVkGAIgASgLMiQudW5pdHRlc3RfaXNzdWVzLk9u",
"ZW9mTWVyZ2luZy5OZXN0ZWRIABoeCgZOZXN0ZWQSCQoBeBgBIAEoBRIJCgF5",
"GAIgASgFQgcKBXZhbHVlImsKFk51bGxWYWx1ZU91dHNpZGVTdHJ1Y3QSFgoM",
"c3RyaW5nX3ZhbHVlGAEgASgJSAASMAoKbnVsbF92YWx1ZRgCIAEoDjIaLmdv",
"b2dsZS5wcm90b2J1Zi5OdWxsVmFsdWVIAEIHCgV2YWx1ZSJFChNOdWxsVmFs",
"dWVOb3RJbk9uZW9mEi4KCm51bGxfdmFsdWUYAiABKA4yGi5nb29nbGUucHJv",
"dG9idWYuTnVsbFZhbHVlImAKF01peGVkUmVndWxhckFuZE9wdGlvbmFsEhUK",
"DXJlZ3VsYXJfZmllbGQYASABKAkSGwoOb3B0aW9uYWxfZmllbGQYAiABKAlI",
"AIgBAUIRCg9fb3B0aW9uYWxfZmllbGQiOQoST25lb2ZXaXRoTm9uZUZpZWxk",
"EgsKAXgYASABKAlIABIOCgRub25lGAIgASgJSABCBgoEdGVzdCI1ChFPbmVv",
"ZldpdGhOb25lTmFtZRILCgF4GAEgASgJSAASCwoBeRgCIAEoCUgAQgYKBG5v",
"bmUikwIKGURpc2FtYmlndWF0ZUNvbW1vbk1lbWJlcnMSIwobZGlzYW1iaWd1",
"YXRlX2NvbW1vbl9tZW1iZXJzGAEgASgFEg0KBXR5cGVzGAIgASgFEhIKCmRl",
"c2NyaXB0b3IYAyABKAUSDgoGZXF1YWxzGAQgASgFEhEKCXRvX3N0cmluZxgF",
"IAEoBRIVCg1nZXRfaGFzaF9jb2RlGAYgASgFEhAKCHdyaXRlX3RvGAcgASgF",
"Eg0KBWNsb25lGAggASgFEhYKDmNhbGN1bGF0ZV9zaXplGAkgASgFEhIKCm1l",
"cmdlX2Zyb20YCiABKAUSFwoPb25fY29uc3RydWN0aW9uGAsgASgFEg4KBnBh",
"cnNlchgMIAEoBSpVCgxOZWdhdGl2ZUVudW0SFgoSTkVHQVRJVkVfRU5VTV9a",
"RVJPEAASFgoJRml2ZUJlbG93EPv//////////wESFQoITWludXNPbmUQ////",
"////////ASo2Cg5EZXByZWNhdGVkRW51bRIXCg9ERVBSRUNBVEVEX1pFUk8Q",
"ABoCCAESBwoDb25lEAEaAhgBQh2qAhpVbml0VGVzdC5Jc3N1ZXMuVGVzdFBy",
"b3Rvc2IGcHJvdG8z"));
"dWVzLk5lZ2F0aXZlRW51bUICEAEiEQoPRGVwcmVjYXRlZENoaWxkIrkCChdE",
"ZXByZWNhdGVkRmllbGRzTWVzc2FnZRIaCg5QcmltaXRpdmVWYWx1ZRgBIAEo",
"BUICGAESGgoOUHJpbWl0aXZlQXJyYXkYAiADKAVCAhgBEjoKDE1lc3NhZ2VW",
"YWx1ZRgDIAEoCzIgLnVuaXR0ZXN0X2lzc3Vlcy5EZXByZWNhdGVkQ2hpbGRC",
"AhgBEjoKDE1lc3NhZ2VBcnJheRgEIAMoCzIgLnVuaXR0ZXN0X2lzc3Vlcy5E",
"ZXByZWNhdGVkQ2hpbGRCAhgBEjYKCUVudW1WYWx1ZRgFIAEoDjIfLnVuaXR0",
"ZXN0X2lzc3Vlcy5EZXByZWNhdGVkRW51bUICGAESNgoJRW51bUFycmF5GAYg",
"AygOMh8udW5pdHRlc3RfaXNzdWVzLkRlcHJlY2F0ZWRFbnVtQgIYASIZCglJ",
"dGVtRmllbGQSDAoEaXRlbRgBIAEoBSJECg1SZXNlcnZlZE5hbWVzEg0KBXR5",
"cGVzGAEgASgFEhIKCmRlc2NyaXB0b3IYAiABKAUaEAoOU29tZU5lc3RlZFR5",
"cGUioAEKFVRlc3RKc29uRmllbGRPcmRlcmluZxITCgtwbGFpbl9pbnQzMhgE",
"IAEoBRITCglvMV9zdHJpbmcYAiABKAlIABISCghvMV9pbnQzMhgFIAEoBUgA",
"EhQKDHBsYWluX3N0cmluZxgBIAEoCRISCghvMl9pbnQzMhgGIAEoBUgBEhMK",
"CW8yX3N0cmluZxgDIAEoCUgBQgQKAm8xQgQKAm8yIksKDFRlc3RKc29uTmFt",
"ZRIMCgRuYW1lGAEgASgJEhkKC2Rlc2NyaXB0aW9uGAIgASgJUgRkZXNjEhIK",
"BGd1aWQYAyABKAlSBGV4aWQifwoMT25lb2ZNZXJnaW5nEg4KBHRleHQYASAB",
"KAlIABI2CgZuZXN0ZWQYAiABKAsyJC51bml0dGVzdF9pc3N1ZXMuT25lb2ZN",
"ZXJnaW5nLk5lc3RlZEgAGh4KBk5lc3RlZBIJCgF4GAEgASgFEgkKAXkYAiAB",
"KAVCBwoFdmFsdWUiawoWTnVsbFZhbHVlT3V0c2lkZVN0cnVjdBIWCgxzdHJp",
"bmdfdmFsdWUYASABKAlIABIwCgpudWxsX3ZhbHVlGAIgASgOMhouZ29vZ2xl",
"LnByb3RvYnVmLk51bGxWYWx1ZUgAQgcKBXZhbHVlIkUKE051bGxWYWx1ZU5v",
"dEluT25lb2YSLgoKbnVsbF92YWx1ZRgCIAEoDjIaLmdvb2dsZS5wcm90b2J1",
"Zi5OdWxsVmFsdWUiYAoXTWl4ZWRSZWd1bGFyQW5kT3B0aW9uYWwSFQoNcmVn",
"dWxhcl9maWVsZBgBIAEoCRIbCg5vcHRpb25hbF9maWVsZBgCIAEoCUgAiAEB",
"QhEKD19vcHRpb25hbF9maWVsZCI5ChJPbmVvZldpdGhOb25lRmllbGQSCwoB",
"eBgBIAEoCUgAEg4KBG5vbmUYAiABKAlIAEIGCgR0ZXN0IjUKEU9uZW9mV2l0",
"aE5vbmVOYW1lEgsKAXgYASABKAlIABILCgF5GAIgASgJSABCBgoEbm9uZSpV",
"CgxOZWdhdGl2ZUVudW0SFgoSTkVHQVRJVkVfRU5VTV9aRVJPEAASFgoJRml2",
"ZUJlbG93EPv//////////wESFQoITWludXNPbmUQ////////////ASouCg5E",
"ZXByZWNhdGVkRW51bRITCg9ERVBSRUNBVEVEX1pFUk8QABIHCgNvbmUQAUId",
"qgIaVW5pdFRlc3QuSXNzdWVzLlRlc3RQcm90b3NiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.StructReflection.Descriptor, },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::UnitTest.Issues.TestProtos.NegativeEnum), typeof(global::UnitTest.Issues.TestProtos.DeprecatedEnum), }, null, new pbr::GeneratedClrTypeInfo[] {
@@ -84,8 +77,7 @@ namespace UnitTest.Issues.TestProtos {
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.NullValueNotInOneof), global::UnitTest.Issues.TestProtos.NullValueNotInOneof.Parser, new[]{ "NullValue" }, null, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.MixedRegularAndOptional), global::UnitTest.Issues.TestProtos.MixedRegularAndOptional.Parser, new[]{ "RegularField", "OptionalField" }, new[]{ "OptionalField" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneField), global::UnitTest.Issues.TestProtos.OneofWithNoneField.Parser, new[]{ "X", "None" }, new[]{ "Test" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneName), global::UnitTest.Issues.TestProtos.OneofWithNoneName.Parser, new[]{ "X", "Y" }, new[]{ "None" }, null, null, null),
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.DisambiguateCommonMembers), global::UnitTest.Issues.TestProtos.DisambiguateCommonMembers.Parser, new[]{ "DisambiguateCommonMembers_", "Types_", "Descriptor_", "Equals_", "ToString_", "GetHashCode_", "WriteTo_", "Clone_", "CalculateSize_", "MergeFrom_", "OnConstruction_", "Parser_" }, null, null, null, null)
new pbr::GeneratedClrTypeInfo(typeof(global::UnitTest.Issues.TestProtos.OneofWithNoneName), global::UnitTest.Issues.TestProtos.OneofWithNoneName.Parser, new[]{ "X", "Y" }, new[]{ "None" }, null, null, null)
}));
}
#endregion
@@ -98,9 +90,7 @@ namespace UnitTest.Issues.TestProtos {
[pbr::OriginalName("MinusOne")] MinusOne = -1,
}
[global::System.ObsoleteAttribute]
public enum DeprecatedEnum {
[global::System.ObsoleteAttribute]
[pbr::OriginalName("DEPRECATED_ZERO")] DeprecatedZero = 0,
[pbr::OriginalName("one")] One = 1,
}
@@ -829,7 +819,6 @@ namespace UnitTest.Issues.TestProtos {
}
[global::System.ObsoleteAttribute]
public sealed partial class DeprecatedChild : pb::IMessage<DeprecatedChild>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
@@ -4358,605 +4347,6 @@ namespace UnitTest.Issues.TestProtos {
}
/// <summary>
/// Issue 8810
/// </summary>
public sealed partial class DisambiguateCommonMembers : pb::IMessage<DisambiguateCommonMembers>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<DisambiguateCommonMembers> _parser = new pb::MessageParser<DisambiguateCommonMembers>(() => new DisambiguateCommonMembers());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pb::MessageParser<DisambiguateCommonMembers> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public static pbr::MessageDescriptor Descriptor {
get { return global::UnitTest.Issues.TestProtos.UnittestIssuesReflection.Descriptor.MessageTypes[14]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public DisambiguateCommonMembers() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public DisambiguateCommonMembers(DisambiguateCommonMembers other) : this() {
disambiguateCommonMembers_ = other.disambiguateCommonMembers_;
types_ = other.types_;
descriptor_ = other.descriptor_;
equals_ = other.equals_;
toString_ = other.toString_;
getHashCode_ = other.getHashCode_;
writeTo_ = other.writeTo_;
clone_ = other.clone_;
calculateSize_ = other.calculateSize_;
mergeFrom_ = other.mergeFrom_;
onConstruction_ = other.onConstruction_;
parser_ = other.parser_;
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public DisambiguateCommonMembers Clone() {
return new DisambiguateCommonMembers(this);
}
/// <summary>Field number for the "disambiguate_common_members" field.</summary>
public const int DisambiguateCommonMembers_FieldNumber = 1;
private int disambiguateCommonMembers_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int DisambiguateCommonMembers_ {
get { return disambiguateCommonMembers_; }
set {
disambiguateCommonMembers_ = value;
}
}
/// <summary>Field number for the "types" field.</summary>
public const int Types_FieldNumber = 2;
private int types_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Types_ {
get { return types_; }
set {
types_ = value;
}
}
/// <summary>Field number for the "descriptor" field.</summary>
public const int Descriptor_FieldNumber = 3;
private int descriptor_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Descriptor_ {
get { return descriptor_; }
set {
descriptor_ = value;
}
}
/// <summary>Field number for the "equals" field.</summary>
public const int Equals_FieldNumber = 4;
private int equals_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Equals_ {
get { return equals_; }
set {
equals_ = value;
}
}
/// <summary>Field number for the "to_string" field.</summary>
public const int ToString_FieldNumber = 5;
private int toString_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int ToString_ {
get { return toString_; }
set {
toString_ = value;
}
}
/// <summary>Field number for the "get_hash_code" field.</summary>
public const int GetHashCode_FieldNumber = 6;
private int getHashCode_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int GetHashCode_ {
get { return getHashCode_; }
set {
getHashCode_ = value;
}
}
/// <summary>Field number for the "write_to" field.</summary>
public const int WriteTo_FieldNumber = 7;
private int writeTo_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int WriteTo_ {
get { return writeTo_; }
set {
writeTo_ = value;
}
}
/// <summary>Field number for the "clone" field.</summary>
public const int Clone_FieldNumber = 8;
private int clone_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Clone_ {
get { return clone_; }
set {
clone_ = value;
}
}
/// <summary>Field number for the "calculate_size" field.</summary>
public const int CalculateSize_FieldNumber = 9;
private int calculateSize_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize_ {
get { return calculateSize_; }
set {
calculateSize_ = value;
}
}
/// <summary>Field number for the "merge_from" field.</summary>
public const int MergeFrom_FieldNumber = 10;
private int mergeFrom_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int MergeFrom_ {
get { return mergeFrom_; }
set {
mergeFrom_ = value;
}
}
/// <summary>Field number for the "on_construction" field.</summary>
public const int OnConstruction_FieldNumber = 11;
private int onConstruction_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int OnConstruction_ {
get { return onConstruction_; }
set {
onConstruction_ = value;
}
}
/// <summary>Field number for the "parser" field.</summary>
public const int Parser_FieldNumber = 12;
private int parser_;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int Parser_ {
get { return parser_; }
set {
parser_ = value;
}
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override bool Equals(object other) {
return Equals(other as DisambiguateCommonMembers);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public bool Equals(DisambiguateCommonMembers other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (DisambiguateCommonMembers_ != other.DisambiguateCommonMembers_) return false;
if (Types_ != other.Types_) return false;
if (Descriptor_ != other.Descriptor_) return false;
if (Equals_ != other.Equals_) return false;
if (ToString_ != other.ToString_) return false;
if (GetHashCode_ != other.GetHashCode_) return false;
if (WriteTo_ != other.WriteTo_) return false;
if (Clone_ != other.Clone_) return false;
if (CalculateSize_ != other.CalculateSize_) return false;
if (MergeFrom_ != other.MergeFrom_) return false;
if (OnConstruction_ != other.OnConstruction_) return false;
if (Parser_ != other.Parser_) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override int GetHashCode() {
int hash = 1;
if (DisambiguateCommonMembers_ != 0) hash ^= DisambiguateCommonMembers_.GetHashCode();
if (Types_ != 0) hash ^= Types_.GetHashCode();
if (Descriptor_ != 0) hash ^= Descriptor_.GetHashCode();
if (Equals_ != 0) hash ^= Equals_.GetHashCode();
if (ToString_ != 0) hash ^= ToString_.GetHashCode();
if (GetHashCode_ != 0) hash ^= GetHashCode_.GetHashCode();
if (WriteTo_ != 0) hash ^= WriteTo_.GetHashCode();
if (Clone_ != 0) hash ^= Clone_.GetHashCode();
if (CalculateSize_ != 0) hash ^= CalculateSize_.GetHashCode();
if (MergeFrom_ != 0) hash ^= MergeFrom_.GetHashCode();
if (OnConstruction_ != 0) hash ^= OnConstruction_.GetHashCode();
if (Parser_ != 0) hash ^= Parser_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
if (DisambiguateCommonMembers_ != 0) {
output.WriteRawTag(8);
output.WriteInt32(DisambiguateCommonMembers_);
}
if (Types_ != 0) {
output.WriteRawTag(16);
output.WriteInt32(Types_);
}
if (Descriptor_ != 0) {
output.WriteRawTag(24);
output.WriteInt32(Descriptor_);
}
if (Equals_ != 0) {
output.WriteRawTag(32);
output.WriteInt32(Equals_);
}
if (ToString_ != 0) {
output.WriteRawTag(40);
output.WriteInt32(ToString_);
}
if (GetHashCode_ != 0) {
output.WriteRawTag(48);
output.WriteInt32(GetHashCode_);
}
if (WriteTo_ != 0) {
output.WriteRawTag(56);
output.WriteInt32(WriteTo_);
}
if (Clone_ != 0) {
output.WriteRawTag(64);
output.WriteInt32(Clone_);
}
if (CalculateSize_ != 0) {
output.WriteRawTag(72);
output.WriteInt32(CalculateSize_);
}
if (MergeFrom_ != 0) {
output.WriteRawTag(80);
output.WriteInt32(MergeFrom_);
}
if (OnConstruction_ != 0) {
output.WriteRawTag(88);
output.WriteInt32(OnConstruction_);
}
if (Parser_ != 0) {
output.WriteRawTag(96);
output.WriteInt32(Parser_);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
if (DisambiguateCommonMembers_ != 0) {
output.WriteRawTag(8);
output.WriteInt32(DisambiguateCommonMembers_);
}
if (Types_ != 0) {
output.WriteRawTag(16);
output.WriteInt32(Types_);
}
if (Descriptor_ != 0) {
output.WriteRawTag(24);
output.WriteInt32(Descriptor_);
}
if (Equals_ != 0) {
output.WriteRawTag(32);
output.WriteInt32(Equals_);
}
if (ToString_ != 0) {
output.WriteRawTag(40);
output.WriteInt32(ToString_);
}
if (GetHashCode_ != 0) {
output.WriteRawTag(48);
output.WriteInt32(GetHashCode_);
}
if (WriteTo_ != 0) {
output.WriteRawTag(56);
output.WriteInt32(WriteTo_);
}
if (Clone_ != 0) {
output.WriteRawTag(64);
output.WriteInt32(Clone_);
}
if (CalculateSize_ != 0) {
output.WriteRawTag(72);
output.WriteInt32(CalculateSize_);
}
if (MergeFrom_ != 0) {
output.WriteRawTag(80);
output.WriteInt32(MergeFrom_);
}
if (OnConstruction_ != 0) {
output.WriteRawTag(88);
output.WriteInt32(OnConstruction_);
}
if (Parser_ != 0) {
output.WriteRawTag(96);
output.WriteInt32(Parser_);
}
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public int CalculateSize() {
int size = 0;
if (DisambiguateCommonMembers_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(DisambiguateCommonMembers_);
}
if (Types_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Types_);
}
if (Descriptor_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Descriptor_);
}
if (Equals_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Equals_);
}
if (ToString_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(ToString_);
}
if (GetHashCode_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(GetHashCode_);
}
if (WriteTo_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(WriteTo_);
}
if (Clone_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Clone_);
}
if (CalculateSize_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(CalculateSize_);
}
if (MergeFrom_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(MergeFrom_);
}
if (OnConstruction_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(OnConstruction_);
}
if (Parser_ != 0) {
size += 1 + pb::CodedOutputStream.ComputeInt32Size(Parser_);
}
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(DisambiguateCommonMembers other) {
if (other == null) {
return;
}
if (other.DisambiguateCommonMembers_ != 0) {
DisambiguateCommonMembers_ = other.DisambiguateCommonMembers_;
}
if (other.Types_ != 0) {
Types_ = other.Types_;
}
if (other.Descriptor_ != 0) {
Descriptor_ = other.Descriptor_;
}
if (other.Equals_ != 0) {
Equals_ = other.Equals_;
}
if (other.ToString_ != 0) {
ToString_ = other.ToString_;
}
if (other.GetHashCode_ != 0) {
GetHashCode_ = other.GetHashCode_;
}
if (other.WriteTo_ != 0) {
WriteTo_ = other.WriteTo_;
}
if (other.Clone_ != 0) {
Clone_ = other.Clone_;
}
if (other.CalculateSize_ != 0) {
CalculateSize_ = other.CalculateSize_;
}
if (other.MergeFrom_ != 0) {
MergeFrom_ = other.MergeFrom_;
}
if (other.OnConstruction_ != 0) {
OnConstruction_ = other.OnConstruction_;
}
if (other.Parser_ != 0) {
Parser_ = other.Parser_;
}
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 8: {
DisambiguateCommonMembers_ = input.ReadInt32();
break;
}
case 16: {
Types_ = input.ReadInt32();
break;
}
case 24: {
Descriptor_ = input.ReadInt32();
break;
}
case 32: {
Equals_ = input.ReadInt32();
break;
}
case 40: {
ToString_ = input.ReadInt32();
break;
}
case 48: {
GetHashCode_ = input.ReadInt32();
break;
}
case 56: {
WriteTo_ = input.ReadInt32();
break;
}
case 64: {
Clone_ = input.ReadInt32();
break;
}
case 72: {
CalculateSize_ = input.ReadInt32();
break;
}
case 80: {
MergeFrom_ = input.ReadInt32();
break;
}
case 88: {
OnConstruction_ = input.ReadInt32();
break;
}
case 96: {
Parser_ = input.ReadInt32();
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
[global::System.CodeDom.Compiler.GeneratedCode("protoc", null)]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 8: {
DisambiguateCommonMembers_ = input.ReadInt32();
break;
}
case 16: {
Types_ = input.ReadInt32();
break;
}
case 24: {
Descriptor_ = input.ReadInt32();
break;
}
case 32: {
Equals_ = input.ReadInt32();
break;
}
case 40: {
ToString_ = input.ReadInt32();
break;
}
case 48: {
GetHashCode_ = input.ReadInt32();
break;
}
case 56: {
WriteTo_ = input.ReadInt32();
break;
}
case 64: {
Clone_ = input.ReadInt32();
break;
}
case 72: {
CalculateSize_ = input.ReadInt32();
break;
}
case 80: {
MergeFrom_ = input.ReadInt32();
break;
}
case 88: {
OnConstruction_ = input.ReadInt32();
break;
}
case 96: {
Parser_ = input.ReadInt32();
break;
}
}
}
}
#endif
}
#endregion
}

View File

@@ -3258,24 +3258,24 @@ namespace Google.Protobuf.TestProtos {
if (other == null) {
return;
}
anyField_.MergeFrom(other.anyField_);
apiField_.MergeFrom(other.apiField_);
durationField_.MergeFrom(other.durationField_);
emptyField_.MergeFrom(other.emptyField_);
fieldMaskField_.MergeFrom(other.fieldMaskField_);
sourceContextField_.MergeFrom(other.sourceContextField_);
structField_.MergeFrom(other.structField_);
timestampField_.MergeFrom(other.timestampField_);
typeField_.MergeFrom(other.typeField_);
doubleField_.MergeFrom(other.doubleField_);
floatField_.MergeFrom(other.floatField_);
int64Field_.MergeFrom(other.int64Field_);
uint64Field_.MergeFrom(other.uint64Field_);
int32Field_.MergeFrom(other.int32Field_);
uint32Field_.MergeFrom(other.uint32Field_);
boolField_.MergeFrom(other.boolField_);
stringField_.MergeFrom(other.stringField_);
bytesField_.MergeFrom(other.bytesField_);
anyField_.Add(other.anyField_);
apiField_.Add(other.apiField_);
durationField_.Add(other.durationField_);
emptyField_.Add(other.emptyField_);
fieldMaskField_.Add(other.fieldMaskField_);
sourceContextField_.Add(other.sourceContextField_);
structField_.Add(other.structField_);
timestampField_.Add(other.timestampField_);
typeField_.Add(other.typeField_);
doubleField_.Add(other.doubleField_);
floatField_.Add(other.floatField_);
int64Field_.Add(other.int64Field_);
uint64Field_.Add(other.uint64Field_);
int32Field_.Add(other.int32Field_);
uint32Field_.Add(other.uint32Field_);
boolField_.Add(other.boolField_);
stringField_.Add(other.stringField_);
bytesField_.Add(other.bytesField_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}

View File

@@ -41,7 +41,9 @@ using System.Buffers;
using System.Runtime.InteropServices;
using System.Threading;
using System.Runtime.CompilerServices;
#if !NET35
using System.Threading.Tasks;
#endif
namespace Google.Protobuf
{
@@ -70,7 +72,7 @@ namespace Google.Protobuf
Assert.IsFalse(b1 != b1);
Assert.IsFalse(b1 != b2);
Assert.IsTrue(ByteString.Empty == ByteString.Empty);
#pragma warning restore 1718
#pragma warning disable 1718
Assert.IsTrue(b1 != b3);
Assert.IsTrue(b1 != b4);
Assert.IsTrue(b1 != null);
@@ -276,9 +278,12 @@ namespace Google.Protobuf
Span<byte> s = stackalloc byte[data.Length];
data.CopyTo(s);
using var manager = new UnmanagedMemoryManager<byte>(s);
ByteString bs = ByteString.AttachBytes(manager.Memory);
Assert.AreEqual("Hello world", bs.ToString(Encoding.UTF8));
using (UnmanagedMemoryManager<byte> manager = new UnmanagedMemoryManager<byte>(s))
{
ByteString bs = ByteString.AttachBytes(manager.Memory);
Assert.AreEqual("Hello world", bs.ToString(Encoding.UTF8));
}
}
[Test]
@@ -312,9 +317,12 @@ namespace Google.Protobuf
Span<byte> s = stackalloc byte[data.Length];
data.CopyTo(s);
using var manager = new UnmanagedMemoryManager<byte>(s);
ByteString bs = ByteString.AttachBytes(manager.Memory);
Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64());
using (UnmanagedMemoryManager<byte> manager = new UnmanagedMemoryManager<byte>(s))
{
ByteString bs = ByteString.AttachBytes(manager.Memory);
Assert.AreEqual("SGVsbG8gd29ybGQ=", bs.ToBase64());
}
}
[Test]
@@ -341,6 +349,7 @@ namespace Google.Protobuf
Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
}
#if !NET35
[Test]
public async Task FromStreamAsync_Seekable()
{
@@ -364,6 +373,7 @@ namespace Google.Protobuf
ByteString expected = ByteString.CopyFrom(2, 3, 4);
Assert.AreEqual(expected, actual, $"{expected.ToBase64()} != {actual.ToBase64()}");
}
#endif
[Test]
public void GetHashCode_Regression()

View File

@@ -563,8 +563,8 @@ namespace Google.Protobuf
int groupFieldNumber = Proto2.TestAllTypes.OptionalGroupFieldNumber;
// write Proto2.TestAllTypes with "optional_group" set, but use wrong EndGroup closing tag
var ms = new MemoryStream();
var output = new CodedOutputStream(ms);
MemoryStream ms = new MemoryStream();
CodedOutputStream output = new CodedOutputStream(ms);
output.WriteTag(WireFormat.MakeTag(groupFieldNumber, WireFormat.WireType.StartGroup));
output.WriteGroup(new Proto2.TestAllTypes.Types.OptionalGroup { A = 12345 });
// end group with different field number
@@ -578,8 +578,8 @@ namespace Google.Protobuf
[Test]
public void ReadGroup_UnknownFields_WrongEndGroupTag()
{
var ms = new MemoryStream();
var output = new CodedOutputStream(ms);
MemoryStream ms = new MemoryStream();
CodedOutputStream output = new CodedOutputStream(ms);
output.WriteTag(WireFormat.MakeTag(14, WireFormat.WireType.StartGroup));
// end group with different field number
output.WriteTag(WireFormat.MakeTag(15, WireFormat.WireType.EndGroup));
@@ -654,7 +654,7 @@ namespace Google.Protobuf
output.Flush();
ms.Position = 0;
var input = new CodedInputStream(ms);
CodedInputStream input = new CodedInputStream(ms);
Assert.AreEqual(tag, input.ReadTag());
Assert.Throws<InvalidProtocolBufferException>(() => input.ReadBytes());
@@ -694,24 +694,26 @@ namespace Google.Protobuf
[Test]
public void TestSlowPathAvoidance()
{
using var ms = new MemoryStream();
var output = new CodedOutputStream(ms);
output.WriteTag(1, WireFormat.WireType.LengthDelimited);
output.WriteBytes(ByteString.CopyFrom(new byte[100]));
output.WriteTag(2, WireFormat.WireType.LengthDelimited);
output.WriteBytes(ByteString.CopyFrom(new byte[100]));
output.Flush();
using (var ms = new MemoryStream())
{
CodedOutputStream output = new CodedOutputStream(ms);
output.WriteTag(1, WireFormat.WireType.LengthDelimited);
output.WriteBytes(ByteString.CopyFrom(new byte[100]));
output.WriteTag(2, WireFormat.WireType.LengthDelimited);
output.WriteBytes(ByteString.CopyFrom(new byte[100]));
output.Flush();
ms.Position = 0;
CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false);
ms.Position = 0;
CodedInputStream input = new CodedInputStream(ms, new byte[ms.Length / 2], 0, 0, false);
uint tag = input.ReadTag();
Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag));
Assert.AreEqual(100, input.ReadBytes().Length);
uint tag = input.ReadTag();
Assert.AreEqual(1, WireFormat.GetTagFieldNumber(tag));
Assert.AreEqual(100, input.ReadBytes().Length);
tag = input.ReadTag();
Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag));
Assert.AreEqual(100, input.ReadBytes().Length);
tag = input.ReadTag();
Assert.AreEqual(2, WireFormat.GetTagFieldNumber(tag));
Assert.AreEqual(100, input.ReadBytes().Length);
}
}
[Test]
@@ -925,11 +927,13 @@ namespace Google.Protobuf
{
byte[] serializedMessage = GenerateBigSerializedMessage();
// How many of these big messages do we need to take us near our 2GB limit?
int count = int.MaxValue / serializedMessage.Length;
int count = Int32.MaxValue / serializedMessage.Length;
// Now make a MemoryStream that will fake a near-2GB stream of messages by returning
// our big serialized message 'count' times.
using var stream = new RepeatingMemoryStream(serializedMessage, count);
Assert.DoesNotThrow(() => TestAllTypes.Parser.ParseFrom(stream));
using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count))
{
Assert.DoesNotThrow(()=>TestAllTypes.Parser.ParseFrom(stream));
}
}
[Test]
@@ -937,15 +941,17 @@ namespace Google.Protobuf
{
byte[] serializedMessage = GenerateBigSerializedMessage();
// How many of these big messages do we need to take us near our 2GB limit?
int count = int.MaxValue / serializedMessage.Length;
int count = Int32.MaxValue / serializedMessage.Length;
// Now add one to take us over the 2GB limit
count++;
// Now make a MemoryStream that will fake a near-2GB stream of messages by returning
// our big serialized message 'count' times.
using var stream = new RepeatingMemoryStream(serializedMessage, count);
Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream),
"Protocol message was too large. May be malicious. " +
"Use CodedInputStream.SetSizeLimit() to increase the size limit.");
using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count))
{
Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream),
"Protocol message was too large. May be malicious. " +
"Use CodedInputStream.SetSizeLimit() to increase the size limit.");
}
}
/// <returns>A serialized big message</returns>

View File

@@ -94,12 +94,14 @@ namespace Google.Protobuf
if ((value >> 32) == 0)
{
MemoryStream rawOutput = new MemoryStream();
CodedOutputStream output = new CodedOutputStream(rawOutput, bufferSize);
CodedOutputStream output =
new CodedOutputStream(rawOutput, bufferSize);
output.WriteRawVarint32((uint) value);
output.Flush();
Assert.AreEqual(data, rawOutput.ToArray());
var bufferWriter = new TestArrayBufferWriter<byte> { MaxGrowBy = bufferSize };
var bufferWriter = new TestArrayBufferWriter<byte>();
bufferWriter.MaxGrowBy = bufferSize;
WriteContext.Initialize(bufferWriter, out WriteContext ctx);
ctx.WriteUInt32((uint) value);
ctx.Flush();
@@ -113,7 +115,8 @@ namespace Google.Protobuf
output.Flush();
Assert.AreEqual(data, rawOutput.ToArray());
var bufferWriter = new TestArrayBufferWriter<byte> { MaxGrowBy = bufferSize };
var bufferWriter = new TestArrayBufferWriter<byte>();
bufferWriter.MaxGrowBy = bufferSize;
WriteContext.Initialize(bufferWriter, out WriteContext ctx);
ctx.WriteUInt64(value);
ctx.Flush();
@@ -187,7 +190,8 @@ namespace Google.Protobuf
output.Flush();
Assert.AreEqual(data, rawOutput.ToArray());
var bufferWriter = new TestArrayBufferWriter<byte> { MaxGrowBy = bufferSize };
var bufferWriter = new TestArrayBufferWriter<byte>();
bufferWriter.MaxGrowBy = bufferSize;
WriteContext.Initialize(bufferWriter, out WriteContext ctx);
ctx.WriteFixed32(value);
ctx.Flush();
@@ -224,7 +228,8 @@ namespace Google.Protobuf
output.Flush();
Assert.AreEqual(data, rawOutput.ToArray());
var bufferWriter = new TestArrayBufferWriter<byte> { MaxGrowBy = blockSize };
var bufferWriter = new TestArrayBufferWriter<byte>();
bufferWriter.MaxGrowBy = blockSize;
WriteContext.Initialize(bufferWriter, out WriteContext ctx);
ctx.WriteFixed64(value);
ctx.Flush();
@@ -265,7 +270,8 @@ namespace Google.Protobuf
output.Flush();
Assert.AreEqual(rawBytes, rawOutput.ToArray());
var bufferWriter = new TestArrayBufferWriter<byte> { MaxGrowBy = blockSize };
var bufferWriter = new TestArrayBufferWriter<byte>();
bufferWriter.MaxGrowBy = blockSize;
message.WriteTo(bufferWriter);
Assert.AreEqual(rawBytes, bufferWriter.WrittenSpan.ToArray());
}
@@ -377,9 +383,7 @@ namespace Google.Protobuf
{
byte[] content = new byte[110];
for (int i = 0; i < content.Length; i++)
{
content[i] = (byte)i;
}
byte[] child = new byte[120];
{

View File

@@ -91,12 +91,10 @@ namespace Google.Protobuf.Collections
[Test]
public void AddPreservesInsertionOrder()
{
var map = new MapField<string, string>
{
{ "a", "v1" },
{ "b", "v2" },
{ "c", "v3" }
};
var map = new MapField<string, string>();
map.Add("a", "v1");
map.Add("b", "v2");
map.Add("c", "v3");
map.Remove("b");
map.Add("d", "v4");
CollectionAssert.AreEqual(new[] { "a", "c", "d" }, map.Keys);
@@ -106,17 +104,13 @@ namespace Google.Protobuf.Collections
[Test]
public void EqualityIsOrderInsensitive()
{
var map1 = new MapField<string, string>
{
{ "a", "v1" },
{ "b", "v2" }
};
var map1 = new MapField<string, string>();
map1.Add("a", "v1");
map1.Add("b", "v2");
var map2 = new MapField<string, string>
{
{ "b", "v2" },
{ "a", "v1" }
};
var map2 = new MapField<string, string>();
map2.Add("b", "v2");
map2.Add("a", "v1");
EqualityTester.AssertEquality(map1, map2);
}
@@ -124,17 +118,13 @@ namespace Google.Protobuf.Collections
[Test]
public void EqualityIsKeySensitive()
{
var map1 = new MapField<string, string>
{
{ "first key", "v1" },
{ "second key", "v2" }
};
var map1 = new MapField<string, string>();
map1.Add("first key", "v1");
map1.Add("second key", "v2");
var map2 = new MapField<string, string>
{
{ "third key", "v1" },
{ "fourth key", "v2" }
};
var map2 = new MapField<string, string>();
map2.Add("third key", "v1");
map2.Add("fourth key", "v2");
EqualityTester.AssertInequality(map1, map2);
}
@@ -153,17 +143,13 @@ namespace Google.Protobuf.Collections
{
// Note: Without some care, it's a little easier than one might
// hope to see hash collisions, but only in some environments...
var map1 = new MapField<string, string>
{
{ "a", "first value" },
{ "b", "second value" }
};
var map1 = new MapField<string, string>();
map1.Add("a", "first value");
map1.Add("b", "second value");
var map2 = new MapField<string, string>
{
{ "a", "third value" },
{ "b", "fourth value" }
};
var map2 = new MapField<string, string>();
map2.Add("a", "third value");
map2.Add("b", "fourth value");
EqualityTester.AssertInequality(map1, map2);
}
@@ -197,7 +183,8 @@ namespace Google.Protobuf.Collections
[Test]
public void Add_KeyAlreadyExists()
{
var map = new MapField<string, string> { { "foo", "bar" } };
var map = new MapField<string, string>();
map.Add("foo", "bar");
Assert.Throws<ArgumentException>(() => map.Add("foo", "baz"));
}
@@ -224,7 +211,8 @@ namespace Google.Protobuf.Collections
[Test]
public void Remove_Key()
{
var map = new MapField<string, string> { { "foo", "bar" } };
var map = new MapField<string, string>();
map.Add("foo", "bar");
Assert.AreEqual(1, map.Count);
Assert.IsFalse(map.Remove("missing"));
Assert.AreEqual(1, map.Count);
@@ -236,7 +224,8 @@ namespace Google.Protobuf.Collections
[Test]
public void Remove_Pair()
{
var map = new MapField<string, string> { { "foo", "bar" } };
var map = new MapField<string, string>();
map.Add("foo", "bar");
ICollection<KeyValuePair<string, string>> collection = map;
Assert.AreEqual(1, map.Count);
Assert.IsFalse(collection.Remove(NewKeyValuePair("wrong key", "bar")));
@@ -251,7 +240,8 @@ namespace Google.Protobuf.Collections
[Test]
public void CopyTo_Pair()
{
var map = new MapField<string, string> { { "foo", "bar" } };
var map = new MapField<string, string>();
map.Add("foo", "bar");
ICollection<KeyValuePair<string, string>> collection = map;
KeyValuePair<string, string>[] array = new KeyValuePair<string, string>[3];
collection.CopyTo(array, 1);
@@ -280,7 +270,8 @@ namespace Google.Protobuf.Collections
[Test]
public void Indexer_Set()
{
var map = new MapField<string, string> { ["x"] = "y" };
var map = new MapField<string, string>();
map["x"] = "y";
Assert.AreEqual("y", map["x"]);
map["x"] = "z"; // This won't throw, unlike Add.
Assert.AreEqual("z", map["x"]);
@@ -366,10 +357,12 @@ namespace Google.Protobuf.Collections
IDictionary dictionary = map;
var array = new DictionaryEntry[3];
dictionary.CopyTo(array, 1);
CollectionAssert.AreEqual(new[] { default, new DictionaryEntry("x", "y"), default }, array);
CollectionAssert.AreEqual(new[] { default(DictionaryEntry), new DictionaryEntry("x", "y"), default(DictionaryEntry) },
array);
var objectArray = new object[3];
dictionary.CopyTo(objectArray, 1);
CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null }, objectArray);
CollectionAssert.AreEqual(new object[] { null, new DictionaryEntry("x", "y"), null },
objectArray);
}
[Test]
@@ -587,7 +580,8 @@ namespace Google.Protobuf.Collections
};
Assert.AreEqual("x", map[SampleNaNs.Regular]);
Assert.AreEqual("y", map[SampleNaNs.SignallingFlipped]);
Assert.False(map.TryGetValue(SampleNaNs.PayloadFlipped, out _));
string ignored;
Assert.False(map.TryGetValue(SampleNaNs.PayloadFlipped, out ignored));
}
[Test]
@@ -641,6 +635,7 @@ namespace Google.Protobuf.Collections
Assert.IsTrue(input.IsAtEnd);
}
#if !NET35
[Test]
public void IDictionaryKeys_Equals_IReadOnlyDictionaryKeys()
{
@@ -654,6 +649,7 @@ namespace Google.Protobuf.Collections
var map = new MapField<string, string> { { "foo", "bar" }, { "x", "y" } };
CollectionAssert.AreEquivalent(((IDictionary<string, string>)map).Values, ((IReadOnlyDictionary<string, string>)map).Values);
}
#endif
private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
{

View File

@@ -33,6 +33,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
@@ -58,7 +59,8 @@ namespace Google.Protobuf.Collections
[Test]
public void Add_SingleItem()
{
var list = new RepeatedField<string> { "foo" };
var list = new RepeatedField<string>();
list.Add("foo");
Assert.AreEqual(1, list.Count);
Assert.AreEqual("foo", list[0]);
}
@@ -66,7 +68,8 @@ namespace Google.Protobuf.Collections
[Test]
public void Add_Sequence()
{
var list = new RepeatedField<string> { new[] { "foo", "bar" } };
var list = new RepeatedField<string>();
list.Add(new[] { "foo", "bar" });
Assert.AreEqual(2, list.Count);
Assert.AreEqual("foo", list[0]);
Assert.AreEqual("bar", list[1]);
@@ -290,13 +293,15 @@ namespace Google.Protobuf.Collections
public void Enumerator()
{
var list = new RepeatedField<string> { "first", "second" };
using var enumerator = list.GetEnumerator();
Assert.IsTrue(enumerator.MoveNext());
Assert.AreEqual("first", enumerator.Current);
Assert.IsTrue(enumerator.MoveNext());
Assert.AreEqual("second", enumerator.Current);
Assert.IsFalse(enumerator.MoveNext());
Assert.IsFalse(enumerator.MoveNext());
using (var enumerator = list.GetEnumerator())
{
Assert.IsTrue(enumerator.MoveNext());
Assert.AreEqual("first", enumerator.Current);
Assert.IsTrue(enumerator.MoveNext());
Assert.AreEqual("second", enumerator.Current);
Assert.IsFalse(enumerator.MoveNext());
Assert.IsFalse(enumerator.MoveNext());
}
}
[Test]
@@ -888,17 +893,5 @@ namespace Google.Protobuf.Collections
Assert.DoesNotThrow(() => list.Capacity = 0, "Can set Capacity to 0");
Assert.AreEqual(0, list.Capacity);
}
[Test]
public void Clear_CapacityUnaffected()
{
var list = new RepeatedField<int> { 1 };
Assert.AreEqual(1, list.Count);
Assert.AreEqual(8, list.Capacity);
list.Clear();
Assert.AreEqual(0, list.Count);
Assert.AreEqual(8, list.Capacity);
}
}
}

View File

@@ -0,0 +1,67 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2015 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
#if NET35
using System;
using System.IO;
using NUnit.Framework;
using Google.Protobuf.Compatibility;
namespace Google.Protobuf.Test.Compatibility
{
public class StreamExtensionsTest
{
[Test]
public void CopyToNullArgument()
{
var memoryStream = new MemoryStream();
Assert.Throws<ArgumentNullException>(() => memoryStream.CopyTo(null));
}
[Test]
public void CopyToTest()
{
byte[] bytesToStream = new byte[] { 0x31, 0x08, 0xFF, 0x00 };
Stream source = new MemoryStream(bytesToStream);
Stream destination = new MemoryStream((int)source.Length);
source.CopyTo(destination);
destination.Seek(0, SeekOrigin.Begin);
Assert.AreEqual(0x31, destination.ReadByte());
Assert.AreEqual(0x08, destination.ReadByte());
Assert.AreEqual(0xFF, destination.ReadByte());
Assert.AreEqual(0x00, destination.ReadByte());
Assert.AreEqual(-1, destination.ReadByte());
}
}
}
#endif

View File

@@ -29,12 +29,12 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Reflection;
#if !NET35
namespace Google.Protobuf.Compatibility
{
public class TypeExtensionsTest
@@ -114,3 +114,4 @@ namespace Google.Protobuf.Compatibility
}
}
}
#endif

View File

@@ -34,9 +34,7 @@ using System;
using System.Reflection;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
using UnitTest.Issues.TestProtos;
#pragma warning disable CS0612 // Type or member is obsolete
namespace Google.Protobuf
{
public class DeprecatedMemberTest
@@ -48,20 +46,10 @@ namespace Google.Protobuf
}
[Test]
public void TestDepreatedPrimitiveValue() =>
AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty(nameof(TestDeprecatedFields.DeprecatedInt32)));
public void TestDepreatedPrimitiveValue()
{
AssertIsDeprecated(typeof(TestDeprecatedFields).GetProperty("DeprecatedInt32"));
}
[Test]
public void TestDeprecatedMessage() =>
AssertIsDeprecated(typeof(DeprecatedChild));
[Test]
public void TestDeprecatedEnum() =>
AssertIsDeprecated(typeof(DeprecatedEnum));
[Test]
public void TestDeprecatedEnumValue() =>
AssertIsDeprecated(typeof(DeprecatedEnum).GetField(nameof(DeprecatedEnum.DeprecatedZero)));
}
}
#pragma warning restore CS0612 // Type or member is obsolete

View File

@@ -1,35 +1,3 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2015 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;
using System.Collections;
using Google.Protobuf.TestProtos.Proto2;
@@ -104,7 +72,7 @@ namespace Google.Protobuf
message.SetExtension(OptionalStringExtension, "abcd");
var input = new CodedInputStream(message.ToByteArray());
input.ExtensionRegistry = new ExtensionRegistry { OptionalStringExtension };
input.ExtensionRegistry = new ExtensionRegistry() { OptionalStringExtension };
input.ReadTag(); // TryMergeFieldFrom expects that a tag was just read and will inspect the LastTag value
ExtensionSet<TestAllExtensions> extensionSet = null;

View File

@@ -169,6 +169,7 @@ namespace Google.Protobuf
// WriteTagAndValue ignores default values
var stream = new MemoryStream();
CodedOutputStream codedOutput;
#if !NET35
codedOutput = new CodedOutputStream(stream);
codec.WriteTagAndValue(codedOutput, codec.DefaultValue);
codedOutput.Flush();
@@ -178,6 +179,7 @@ namespace Google.Protobuf
{
Assert.AreEqual(default(T), codec.DefaultValue);
}
#endif
// The plain ValueWriter/ValueReader delegates don't.
if (codec.DefaultValue != null) // This part isn't appropriate for message types.

View File

@@ -30,6 +30,7 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System.Collections.Generic;
using Google.Protobuf.Collections;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
@@ -431,89 +432,5 @@ namespace Google.Protobuf
Assert.IsNotNull(destination.Payload);
}
[Test]
public void MergeWrapperFieldsWithNonNullFieldsInSource()
{
// Instantiate a destination with wrapper-based field types.
var destination = new TestWellKnownTypes()
{
StringField = "Hello",
Int32Field = 12,
Int64Field = 24,
BoolField = true,
};
// Set up a targeted update.
var source = new TestWellKnownTypes()
{
StringField = "Hi",
Int64Field = 240
};
Merge(new FieldMaskTree().AddFieldPath("string_field").AddFieldPath("int64_field"),
source,
destination,
new FieldMask.MergeOptions(),
false);
// Make sure the targeted fields changed.
Assert.AreEqual("Hi", destination.StringField);
Assert.AreEqual(240, destination.Int64Field);
// Prove that non-targeted fields stay intact...
Assert.AreEqual(12, destination.Int32Field);
Assert.IsTrue(destination.BoolField);
// ...including default values which were not explicitly set in the destination object.
Assert.IsNull(destination.FloatField);
}
[Test]
[TestCase(false, "Hello", 24)]
[TestCase(true, null, null)]
public void MergeWrapperFieldsWithNullFieldsInSource(
bool replaceMessageFields,
string expectedStringValue,
long? expectedInt64Value)
{
// Instantiate a destination with wrapper-based field types.
var destination = new TestWellKnownTypes()
{
StringField = "Hello",
Int32Field = 12,
Int64Field = 24,
BoolField = true,
};
// Set up a targeted update with null valued fields.
var source = new TestWellKnownTypes()
{
StringField = null,
Int64Field = null
};
Merge(new FieldMaskTree().AddFieldPath("string_field").AddFieldPath("int64_field"),
source,
destination,
new FieldMask.MergeOptions()
{
ReplaceMessageFields = replaceMessageFields
},
false);
// Make sure the targeted fields changed according to our expectations, depending on the value of ReplaceMessageFields.
// When ReplaceMessageFields is false, the null values are not applied to the destination, because, although wrapped types
// are semantically primitives, FieldMaskTree.Merge still treats them as message types in order to maintain consistency with other Protobuf
// libraries such as Java and C++.
Assert.AreEqual(expectedStringValue, destination.StringField);
Assert.AreEqual(expectedInt64Value, destination.Int64Field);
// Prove that non-targeted fields stay intact...
Assert.AreEqual(12, destination.Int32Field);
Assert.IsTrue(destination.BoolField);
// ...including default values which were not explicitly set in the destination object.
Assert.IsNull(destination.FloatField);
}
}
}

View File

@@ -1,35 +1,3 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2015 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 Google.Protobuf.TestProtos.Proto2;
using Proto2 = Google.Protobuf.TestProtos.Proto2;
using NUnit.Framework;
@@ -419,9 +387,11 @@ namespace Google.Protobuf
var message = new TestAllExtensions();
message.SetExtension(UnittestExtensions.OptionalBoolExtension, true);
byte[] bytes = message.ToByteArray();
using CodedInputStream input = new CodedInputStream(bytes);
var parsed = TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalBoolExtension }).ParseFrom(input);
Assert.AreEqual(message, parsed);
using (CodedInputStream input = new CodedInputStream(bytes))
{
var parsed = TestAllExtensions.Parser.WithExtensionRegistry(new ExtensionRegistry() { UnittestExtensions.OptionalBoolExtension }).ParseFrom(input);
Assert.AreEqual(message, parsed);
}
}
}
}

View File

@@ -33,10 +33,12 @@
using System;
using System.IO;
using Google.Protobuf.TestProtos;
using Proto2 = Google.Protobuf.TestProtos.Proto2;
using NUnit.Framework;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Google.Protobuf.WellKnownTypes;
using Google.Protobuf.Collections;
namespace Google.Protobuf
{
@@ -656,11 +658,9 @@ namespace Google.Protobuf
[Test]
public void OneofSerialization_NonDefaultValue()
{
var message = new TestAllTypes
{
OneofString = "this would take a bit of space",
OneofUint32 = 10
};
var message = new TestAllTypes();
message.OneofString = "this would take a bit of space";
message.OneofUint32 = 10;
var bytes = message.ToByteArray();
Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - no string!
@@ -675,11 +675,9 @@ namespace Google.Protobuf
[Test]
public void OneofSerialization_DefaultValue()
{
var message = new TestAllTypes
{
OneofString = "this would take a bit of space",
OneofUint32 = 0 // This is the default value for UInt32; normally wouldn't be serialized
};
var message = new TestAllTypes();
message.OneofString = "this would take a bit of space";
message.OneofUint32 = 0; // This is the default value for UInt32; normally wouldn't be serialized
var bytes = message.ToByteArray();
Assert.AreEqual(3, bytes.Length); // 2 bytes for the tag + 1 for the value - it's still serialized
@@ -748,6 +746,7 @@ namespace Google.Protobuf
[Test]
public void ExtraEndGroupThrows()
{
var message = SampleMessages.CreateFullTestAllTypes();
var stream = new MemoryStream();
var output = new CodedOutputStream(stream);
@@ -796,44 +795,5 @@ namespace Google.Protobuf
EqualityTester.AssertInequality(message1, message2);
EqualityTester.AssertEquality(message1, message3);
}
[Test]
[TestCase(false)]
[TestCase(true)]
public void MapFieldMerging(bool direct)
{
var message1 = new TestMap
{
MapStringString =
{
{ "x1", "y1" },
{ "common", "message1" }
}
};
var message2 = new TestMap
{
MapStringString =
{
{ "x2", "y2" },
{ "common", "message2" }
}
};
if (direct)
{
message1.MergeFrom(message2);
}
else
{
message1.MergeFrom(message2.ToByteArray());
}
var expected = new MapField<string, string>
{
{ "x1", "y1" },
{ "x2", "y2" },
{ "common", "message2" }
};
Assert.AreEqual(expected, message1.MapStringString);
}
}
}

View File

@@ -1,111 +0,0 @@
#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 Google.Protobuf.Reflection;
using NUnit.Framework;
// For WrapInQuotes
namespace Google.Protobuf
{
public class JsonFormatterSettingsTest
{
[Test]
public void WithIndentation()
{
var settings = JsonFormatter.Settings.Default.WithIndentation("\t");
Assert.AreEqual("\t", settings.Indentation);
}
[Test]
public void WithTypeRegistry()
{
var typeRegistry = TypeRegistry.Empty;
var settings = JsonFormatter.Settings.Default.WithTypeRegistry(typeRegistry);
Assert.AreEqual(typeRegistry, settings.TypeRegistry);
}
[Test]
public void WithFormatDefaultValues()
{
var settingsWith = JsonFormatter.Settings.Default.WithFormatDefaultValues(true);
Assert.AreEqual(true, settingsWith.FormatDefaultValues);
var settingsWithout = JsonFormatter.Settings.Default.WithFormatDefaultValues(false);
Assert.AreEqual(false, settingsWithout.FormatDefaultValues);
}
[Test]
public void WithFormatEnumsAsIntegers()
{
var settingsWith = JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(true);
Assert.AreEqual(true, settingsWith.FormatEnumsAsIntegers);
var settingsWithout = JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(false);
Assert.AreEqual(false, settingsWithout.FormatEnumsAsIntegers);
}
[Test]
public void WithMethodsPreserveExistingSettings()
{
var typeRegistry = TypeRegistry.Empty;
var baseSettings = JsonFormatter.Settings.Default
.WithIndentation("\t")
.WithFormatDefaultValues(true)
.WithFormatEnumsAsIntegers(true)
.WithTypeRegistry(typeRegistry)
.WithPreserveProtoFieldNames(true);
var settings1 = baseSettings.WithIndentation("\t");
var settings2 = baseSettings.WithFormatDefaultValues(true);
var settings3 = baseSettings.WithFormatEnumsAsIntegers(true);
var settings4 = baseSettings.WithTypeRegistry(typeRegistry);
var settings5 = baseSettings.WithPreserveProtoFieldNames(true);
AssertAreEqual(baseSettings, settings1);
AssertAreEqual(baseSettings, settings2);
AssertAreEqual(baseSettings, settings3);
AssertAreEqual(baseSettings, settings4);
AssertAreEqual(baseSettings, settings5);
}
private static void AssertAreEqual(JsonFormatter.Settings settings, JsonFormatter.Settings other)
{
Assert.AreEqual(settings.Indentation, other.Indentation);
Assert.AreEqual(settings.FormatDefaultValues, other.FormatDefaultValues);
Assert.AreEqual(settings.FormatEnumsAsIntegers, other.FormatEnumsAsIntegers);
Assert.AreEqual(settings.TypeRegistry, other.TypeRegistry);
}
}
}

View File

@@ -168,7 +168,8 @@ namespace Google.Protobuf
[Test]
public void WithFormatDefaultValues_DoesNotAffectProto3OptionalFields()
{
var message = new TestProto3Optional { OptionalInt32 = 0 };
var message = new TestProto3Optional();
message.OptionalInt32 = 0;
var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true));
var json = formatter.Format(message);
// The non-optional proto3 fields are formatted, as is the optional-but-specified field.
@@ -178,7 +179,8 @@ namespace Google.Protobuf
[Test]
public void WithFormatDefaultValues_DoesNotAffectProto2Fields()
{
var message = new TestProtos.Proto2.ForeignMessage { C = 0 };
var message = new TestProtos.Proto2.ForeignMessage();
message.C = 0;
var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true));
var json = formatter.Format(message);
// The specified field is formatted, but the non-specified field (d) is not.
@@ -674,200 +676,6 @@ namespace Google.Protobuf
AssertWriteValue(value, "[ 1, 2, 3 ]");
}
[Test]
public void WriteValueWithIndentation_EmptyMessage()
{
var value = new TestEmptyMessage();
AssertWriteValue(value, "{}", JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void WriteValueWithIndentation_NestedTestAllTypes()
{
var value = new NestedTestAllTypes
{
Payload = new TestAllTypes
{
SingleBool = true,
SingleInt32 = 100,
SingleString = "multiple fields",
RepeatedString = { "string1", "string2" },
},
Child = new NestedTestAllTypes
{
Payload = new TestAllTypes
{
SingleString = "single field",
},
},
RepeatedChild =
{
new NestedTestAllTypes { Payload = new TestAllTypes { SingleString = "child 1", RepeatedString = { "string" } } },
new NestedTestAllTypes { Payload = new TestAllTypes { SingleString = "child 2" } },
},
};
const string expectedJson = @"
{
'child': {
'payload': {
'singleString': 'single field'
}
},
'payload': {
'singleInt32': 100,
'singleBool': true,
'singleString': 'multiple fields',
'repeatedString': [
'string1',
'string2'
]
},
'repeatedChild': [
{
'payload': {
'singleString': 'child 1',
'repeatedString': [
'string'
]
}
},
{
'payload': {
'singleString': 'child 2'
}
}
]
}";
AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void WriteValueWithIndentation_WellKnownTypes()
{
var value = new TestWellKnownTypes
{
StructField = new Struct
{
Fields =
{
{ "string", Value.ForString("foo") },
{ "numbers", Value.ForList(Value.ForNumber(1), Value.ForNumber(2), Value.ForNumber(3)) },
{ "emptyList", Value.ForList() },
{ "emptyStruct", Value.ForStruct(new Struct()) },
},
},
};
const string expectedJson = @"
{
'structField': {
'string': 'foo',
'numbers': [
1,
2,
3
],
'emptyList': [],
'emptyStruct': {}
}
}";
AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void WriteValueWithIndentation_StructSingleField()
{
var value = new Struct { Fields = { { "structField1", Value.ForString("structFieldValue1") } } };
const string expectedJson = @"
{
'structField1': 'structFieldValue1'
}";
AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void WriteValueWithIndentation_StructMultipleFields()
{
var value = new Struct
{
Fields =
{
{ "structField1", Value.ForString("structFieldValue1") },
{ "structField2", Value.ForString("structFieldValue2") },
{ "structField3", Value.ForString("structFieldValue3") },
},
};
const string expectedJson = @"
{
'structField1': 'structFieldValue1',
'structField2': 'structFieldValue2',
'structField3': 'structFieldValue3'
}";
AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void FormatWithIndentation_EmbeddedMessage()
{
var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L };
var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithIndentation());
var valueJson = formatter.Format(value, indentationLevel: 1);
var actualJson = $@"
{{
""data"": {valueJson}
}}";
const string expectedJson = @"
{
'data': {
'singleInt32': 100,
'singleInt64': '3210987654321'
}
}";
AssertJson(expectedJson, actualJson.Trim());
}
[Test]
public void WriteValueWithIndentation_Map()
{
var value = new TestMap
{
MapStringString =
{
{ "key1", "value1" },
{ "key2", "value2" },
},
};
const string expectedJson = @"
{
'mapStringString': {
'key1': 'value1',
'key2': 'value2'
}
}";
AssertWriteValue(value, expectedJson, JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void WriteValueWithIndentation_List()
{
var value = new RepeatedField<int> { 1, 2, 3 };
AssertWriteValue(value, "[\n 1,\n 2,\n 3\n]", JsonFormatter.Settings.Default.WithIndentation());
}
[Test]
public void WriteValueWithIndentation_CustomIndentation()
{
var value = new RepeatedField<int> { 1, 2, 3 };
AssertWriteValue(value, "[\n\t1,\n\t2,\n\t3\n]", JsonFormatter.Settings.Default.WithIndentation("\t"));
}
[Test]
public void Proto2_DefaultValuesWritten()
{
@@ -877,7 +685,7 @@ namespace Google.Protobuf
private static void AssertWriteValue(object value, string expectedJson, JsonFormatter.Settings settings = null)
{
var writer = new StringWriter { NewLine = "\n" };
var writer = new StringWriter();
new JsonFormatter(settings ?? JsonFormatter.Settings.Default).WriteValue(writer, value);
string actual = writer.ToString();
AssertJson(expectedJson, actual);
@@ -885,17 +693,13 @@ namespace Google.Protobuf
/// <summary>
/// Checks that the actual JSON is the same as the expected JSON - but after replacing
/// all apostrophes in the expected JSON with double quotes, trimming leading whitespace and normalizing new lines.
/// This basically makes the tests easier to read.
/// all apostrophes in the expected JSON with double quotes. This basically makes the tests easier
/// to read.
/// </summary>
/// <remarks>
/// Line endings are normalized because indented JSON strings are generated with system-specific line endings,
/// while line endings in the test cases are hard-coded, but may be converted during source checkout, depending
/// on git settings, causing unpredictability in the test results otherwise.</remarks>
private static void AssertJson(string expectedJsonWithApostrophes, string actualJson)
{
var expectedJson = expectedJsonWithApostrophes.Replace("'", "\"").Replace("\r\n", "\n").TrimStart();
Assert.AreEqual(expectedJson, actualJson.Replace("\r\n", "\n"));
var expectedJson = expectedJsonWithApostrophes.Replace("'", "\"");
Assert.AreEqual(expectedJson, actualJson);
}
}
}

View File

@@ -576,10 +576,6 @@ namespace Google.Protobuf
[TestCase("-3.402823e38", -3.402823e38f)]
[TestCase("1.5e1", 15f)]
[TestCase("15e-1", 1.5f)]
[TestCase("3.4028235e38", float.MaxValue)]
[TestCase("-3.4028235e38", float.MinValue)]
[TestCase("3.4028235e+38", float.MaxValue)]
[TestCase("-3.4028235e+38", float.MinValue)]
public void NumberToFloat_Valid(string jsonValue, float expectedParsedValue)
{
string json = "{ \"singleFloat\": " + jsonValue + "}";
@@ -588,10 +584,8 @@ namespace Google.Protobuf
}
[Test]
[TestCase("3.4028236e38", typeof(InvalidProtocolBufferException))]
[TestCase("-3.4028236e38", typeof(InvalidProtocolBufferException))]
[TestCase("3.4028236e+38", typeof(InvalidProtocolBufferException))]
[TestCase("-3.4028236e+38", typeof(InvalidProtocolBufferException))]
[TestCase("3.402824e38", typeof(InvalidProtocolBufferException))]
[TestCase("-3.402824e38", typeof(InvalidProtocolBufferException))]
[TestCase("1,0", typeof(InvalidJsonException))]
[TestCase("1.0.0", typeof(InvalidJsonException))]
[TestCase("+1", typeof(InvalidJsonException))]
@@ -647,7 +641,7 @@ namespace Google.Protobuf
[TestCase("9999-12-31T23:59:59.999999999Z", null)]
public void Timestamp_Valid(string jsonValue, string expectedFormatted)
{
expectedFormatted ??= jsonValue;
expectedFormatted = expectedFormatted ?? jsonValue;
string json = WrapInQuotes(jsonValue);
var parsed = Timestamp.Parser.ParseJson(json);
Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
@@ -764,7 +758,7 @@ namespace Google.Protobuf
[TestCase("-315576000000s", null)]
public void Duration_Valid(string jsonValue, string expectedFormatted)
{
expectedFormatted ??= jsonValue;
expectedFormatted = expectedFormatted ?? jsonValue;
string json = WrapInQuotes(jsonValue);
var parsed = Duration.Parser.ParseJson(json);
Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
@@ -1072,26 +1066,25 @@ namespace Google.Protobuf
""mapStringNestedMessage"": null
}";
var message = new TestAllTypesProto3
{
OptionalInt32 = 1,
OptionalInt64 = 1,
OptionalUint32 = 1,
OptionalUint64 = 1,
OptionalSint32 = 1,
OptionalSint64 = 1,
OptionalFixed32 = 1,
OptionalFixed64 = 1,
OptionalSfixed32 = 1,
OptionalSfixed64 = 1,
OptionalFloat = 1,
OptionalDouble = 1,
OptionalBool = true,
OptionalString = "1",
OptionalBytes = ByteString.CopyFrom(new byte[] { 1 }),
OptionalNestedEnum = TestAllTypesProto3.Types.NestedEnum.Bar,
OptionalNestedMessage = new TestAllTypesProto3.Types.NestedMessage()
};
TestAllTypesProto3 message = new TestAllTypesProto3();
message.OptionalInt32 = 1;
message.OptionalInt64 = 1;
message.OptionalUint32 = 1;
message.OptionalUint64 = 1;
message.OptionalSint32 = 1;
message.OptionalSint64 = 1;
message.OptionalFixed32 = 1;
message.OptionalFixed64 = 1;
message.OptionalSfixed32 = 1;
message.OptionalSfixed64 = 1;
message.OptionalFloat = 1;
message.OptionalDouble = 1;
message.OptionalBool = true;
message.OptionalString = "1";
message.OptionalBytes = ByteString.CopyFrom(new byte[] { 1 });
message.OptionalNestedEnum = TestAllTypesProto3.Types.NestedEnum.Bar;
message.OptionalNestedMessage = new TestAllTypesProto3.Types.NestedMessage();
message.RepeatedInt32.Add(1);
message.RepeatedInt64.Add(1);
message.RepeatedUint32.Add(1);

View File

@@ -29,7 +29,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
using System;
using System.IO;
@@ -127,7 +126,7 @@ namespace Google.Protobuf
tokenizer.PushBack(token);
Assert.AreEqual(0, tokenizer.ObjectDepth);
// Read the same token again, and get back to depth 1
_ = tokenizer.Next();
token = tokenizer.Next();
Assert.AreEqual(1, tokenizer.ObjectDepth);
// Now the same in reverse, with EndObject

View File

@@ -29,12 +29,14 @@
// (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 Google.Protobuf;
using Google.Protobuf.Reflection;
using System.Buffers;
using pb = Google.Protobuf;
using pbr = Google.Protobuf.Reflection;
using pb = global::Google.Protobuf;
using pbr = global::Google.Protobuf.Reflection;
using NUnit.Framework;
using System.IO;
using System;
using Google.Protobuf.Buffers;
namespace Google.Protobuf

View File

@@ -136,7 +136,8 @@ namespace Google.Protobuf
// test for different IBufferWriter.GetSpan() segment sizes
for (int blockSize = 1; blockSize < 256; blockSize *= 2)
{
var segmentedBufferWriter = new TestArrayBufferWriter<byte> { MaxGrowBy = blockSize };
var segmentedBufferWriter = new TestArrayBufferWriter<byte>();
segmentedBufferWriter.MaxGrowBy = blockSize;
message.WriteTo(segmentedBufferWriter);
Assert.AreEqual(bytes, segmentedBufferWriter.WrittenSpan.ToArray());
}

View File

@@ -38,7 +38,7 @@ using UnitTest.Issues.TestProtos;
namespace Google.Protobuf.Test
{
public class Proto3OptionalTest
class Proto3OptionalTest
{
[Test]
public void OptionalInt32FieldLifecycle()

View File

@@ -33,6 +33,9 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Google.Protobuf
{
@@ -47,7 +50,7 @@ namespace Google.Protobuf
if (addEmptySegmentDelimiters)
{
segments.Add(Array.Empty<byte>());
segments.Add(new byte[0]);
}
var currentIndex = 0;
@@ -62,7 +65,7 @@ namespace Google.Protobuf
if (addEmptySegmentDelimiters)
{
segments.Add(Array.Empty<byte>());
segments.Add(new byte[0]);
}
}

View File

@@ -77,42 +77,43 @@ namespace Google.Protobuf
/// <param name="args"></param>
/// <param name="workingDirectory"></param>
private void RunOldCsharpCompilerAndCheckSuccess(string args, string workingDirectory)
{
using var process = new Process();
// Get the path to the old C# 5 compiler from .NET framework. This approach is not 100% reliable, but works on most machines.
// Alternative way of getting the framework path is System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
// but it only works with the net45 target.
var oldCsharpCompilerPath = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v4.0.30319", "csc.exe");
process.StartInfo.FileName = oldCsharpCompilerPath;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.Arguments = args;
process.StartInfo.WorkingDirectory = workingDirectory;
process.OutputDataReceived += (sender, e) =>
{
using (var process = new Process())
{
if (e.Data != null)
// Get the path to the old C# 5 compiler from .NET framework. This approach is not 100% reliable, but works on most machines.
// Alternative way of getting the framework path is System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
// but it only works with the net45 target.
var oldCsharpCompilerPath = Path.Combine(Environment.GetEnvironmentVariable("WINDIR"), "Microsoft.NET", "Framework", "v4.0.30319", "csc.exe");
process.StartInfo.FileName = oldCsharpCompilerPath;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.Arguments = args;
process.StartInfo.WorkingDirectory = workingDirectory;
process.OutputDataReceived += (sender, e) =>
{
Console.WriteLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
if (e.Data != null)
if (e.Data != null)
{
Console.WriteLine(e.Data);
}
};
process.ErrorDataReceived += (sender, e) =>
{
Console.WriteLine(e.Data);
}
};
if (e.Data != null)
{
Console.WriteLine(e.Data);
}
};
process.Start();
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
process.WaitForExit();
Assert.AreEqual(0, process.ExitCode);
process.WaitForExit();
Assert.AreEqual(0, process.ExitCode);
}
}
}
}

View File

@@ -31,10 +31,13 @@
#endregion
using Google.Protobuf.Reflection;
using Google.Protobuf.WellKnownTypes;
using NUnit.Framework;
using System;
using System.IO;
using System.Linq;
using UnitTest.Issues.TestProtos;
using static Google.Protobuf.WireFormat;
using static UnitTest.Issues.TestProtos.ComplexOptionType2.Types;
using static UnitTest.Issues.TestProtos.UnittestCustomOptionsProto3Extensions;
using static UnitTest.Issues.TestProtos.DummyMessageContainingEnum.Types;
@@ -62,7 +65,7 @@ namespace Google.Protobuf.Test.Reflection
}
else
{
v = default;
v = default(E);
return false;
}
};

View File

@@ -35,6 +35,7 @@ using NUnit.Framework;
using ProtobufUnittest;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnitTest.Issues.TestProtos;

View File

@@ -30,8 +30,10 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.IO;
using Google.Protobuf.TestProtos;
using Proto2 = Google.Protobuf.TestProtos.Proto2;
using NUnit.Framework;
namespace Google.Protobuf
@@ -125,7 +127,8 @@ namespace Google.Protobuf
public void TestClone(IMessage message)
{
var emptyMessage = new TestEmptyMessage();
TestEmptyMessage otherEmptyMessage = emptyMessage.Clone();
var otherEmptyMessage = new TestEmptyMessage();
otherEmptyMessage = emptyMessage.Clone();
Assert.AreEqual(emptyMessage.CalculateSize(), otherEmptyMessage.CalculateSize());
Assert.AreEqual(emptyMessage.ToByteArray(), otherEmptyMessage.ToByteArray());
@@ -166,13 +169,13 @@ namespace Google.Protobuf
byte[] data = message.ToByteArray();
int fullSize = message.CalculateSize();
void AssertEmpty(IMessage msg)
Action<IMessage> assertEmpty = msg =>
{
Assert.AreEqual(0, msg.CalculateSize());
Assert.AreEqual(goldenEmptyMessage, msg);
}
};
void AssertFull(IMessage msg) => Assert.AreEqual(fullSize, msg.CalculateSize());
Action<IMessage> assertFull = msg => Assert.AreEqual(fullSize, msg.CalculateSize());
// Test the behavior of the parsers with and without discarding, both generic and non-generic.
MessageParser<TestEmptyMessage> retainingParser1 = TestEmptyMessage.Parser;
@@ -181,28 +184,28 @@ namespace Google.Protobuf
MessageParser discardingParser2 = retainingParser2.WithDiscardUnknownFields(true);
// Test parse from byte[]
MessageParsingHelpers.AssertReadingMessage(retainingParser1, data, m => AssertFull(m));
MessageParsingHelpers.AssertReadingMessage(retainingParser2, data, m => AssertFull(m));
MessageParsingHelpers.AssertReadingMessage(discardingParser1, data, m => AssertEmpty(m));
MessageParsingHelpers.AssertReadingMessage(discardingParser2, data, m => AssertEmpty(m));
MessageParsingHelpers.AssertReadingMessage(retainingParser1, data, m => assertFull(m));
MessageParsingHelpers.AssertReadingMessage(retainingParser2, data, m => assertFull(m));
MessageParsingHelpers.AssertReadingMessage(discardingParser1, data, m => assertEmpty(m));
MessageParsingHelpers.AssertReadingMessage(discardingParser2, data, m => assertEmpty(m));
// Test parse from byte[] with offset
AssertFull(retainingParser1.ParseFrom(data, 0, data.Length));
AssertFull(retainingParser2.ParseFrom(data, 0, data.Length));
AssertEmpty(discardingParser1.ParseFrom(data, 0, data.Length));
AssertEmpty(discardingParser2.ParseFrom(data, 0, data.Length));
assertFull(retainingParser1.ParseFrom(data, 0, data.Length));
assertFull(retainingParser2.ParseFrom(data, 0, data.Length));
assertEmpty(discardingParser1.ParseFrom(data, 0, data.Length));
assertEmpty(discardingParser2.ParseFrom(data, 0, data.Length));
// Test parse from CodedInputStream
AssertFull(retainingParser1.ParseFrom(new CodedInputStream(data)));
AssertFull(retainingParser2.ParseFrom(new CodedInputStream(data)));
AssertEmpty(discardingParser1.ParseFrom(new CodedInputStream(data)));
AssertEmpty(discardingParser2.ParseFrom(new CodedInputStream(data)));
assertFull(retainingParser1.ParseFrom(new CodedInputStream(data)));
assertFull(retainingParser2.ParseFrom(new CodedInputStream(data)));
assertEmpty(discardingParser1.ParseFrom(new CodedInputStream(data)));
assertEmpty(discardingParser2.ParseFrom(new CodedInputStream(data)));
// Test parse from Stream
AssertFull(retainingParser1.ParseFrom(new MemoryStream(data)));
AssertFull(retainingParser2.ParseFrom(new MemoryStream(data)));
AssertEmpty(discardingParser1.ParseFrom(new MemoryStream(data)));
AssertEmpty(discardingParser2.ParseFrom(new MemoryStream(data)));
assertFull(retainingParser1.ParseFrom(new MemoryStream(data)));
assertFull(retainingParser2.ParseFrom(new MemoryStream(data)));
assertEmpty(discardingParser1.ParseFrom(new MemoryStream(data)));
assertEmpty(discardingParser2.ParseFrom(new MemoryStream(data)));
}
[Test]

View File

@@ -30,11 +30,8 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using Google.Protobuf.Reflection;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
using System.Linq;
using UnitTest.Issues.TestProtos;
namespace Google.Protobuf.WellKnownTypes
{
@@ -126,6 +123,7 @@ namespace Google.Protobuf.WellKnownTypes
[TestCase("foobar", "")]
public void GetTypeName(string typeUrl, string expectedTypeName)
{
var any = new Any { TypeUrl = typeUrl };
Assert.AreEqual(expectedTypeName, Any.GetTypeName(typeUrl));
}
@@ -150,34 +148,10 @@ namespace Google.Protobuf.WellKnownTypes
Assert.False(any.Is(TestOneof.Descriptor));
}
[Test]
public void IsRightType()
{
var any = Any.Pack(SampleMessages.CreateFullTestAllTypes());
Assert.True(any.Is(TestAllTypes.Descriptor));
}
[Test]
public void Unpack_TypeRegistry()
{
var messages = new IMessage[]
{
SampleMessages.CreateFullTestAllTypes(),
new TestWellKnownTypes { BoolField = true },
new MoreString { Data = { "x" } },
new MoreBytes { Data = ByteString.CopyFromUtf8("xyz") },
new ReservedNames { Descriptor_ = 10 }
};
var anyMessages = messages.Select(Any.Pack);
// The type registry handles the first four of the packed messages, but not the final one.
var registry = TypeRegistry.FromFiles(
UnittestWellKnownTypesReflection.Descriptor,
UnittestProto3Reflection.Descriptor);
var unpacked = anyMessages.Select(any => any.Unpack(registry)).ToList();
var expected = (IMessage[]) messages.Clone();
expected[4] = null;
Assert.AreEqual(expected, unpacked);
}
}
}

View File

@@ -128,38 +128,5 @@ namespace Google.Protobuf.WellKnownTypes
var duration = new Duration { Seconds = 1, Nanos = -1 };
Assert.AreEqual("{ \"@warning\": \"Invalid Duration\", \"seconds\": \"1\", \"nanos\": -1 }", duration.ToString());
}
[Test]
public void Comparability()
{
Duration[] durationsInExpectedSortOrder =
{
null,
new Duration { Seconds = -10, Nanos = -10 },
new Duration { Seconds = -10, Nanos = -1 },
new Duration { Seconds = -1, Nanos = -10 },
new Duration { Seconds = -1, Nanos = -1 },
new Duration(),
new Duration { Seconds = 1, Nanos = 1 },
new Duration { Seconds = 1, Nanos = 10 },
new Duration { Seconds = 10, Nanos = 1 },
new Duration { Seconds = 10, Nanos = 10 }
};
for (int i = 0; i < durationsInExpectedSortOrder.Length; i++)
{
var target = durationsInExpectedSortOrder[i];
if (target is null)
{
continue;
}
for (int j = 0; j < durationsInExpectedSortOrder.Length; j++)
{
var expectedResult = Math.Sign(i - j);
var actualResult = target.CompareTo(durationsInExpectedSortOrder[j]);
Assert.AreEqual(expectedResult, actualResult);
}
}
}
}
}

View File

@@ -12,6 +12,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf.Conformance
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Google.Protobuf.JsonDump", "Google.Protobuf.JsonDump\Google.Protobuf.JsonDump.csproj", "{9695E08F-9829-497D-B95C-B38F28D48690}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.Benchmarks", "Google.Protobuf.Benchmarks\Google.Protobuf.Benchmarks.csproj", "{D25E4804-4DEA-45AB-9F8C-BA4DBD8E5A07}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Google.Protobuf.Test.TestProtos", "Google.Protobuf.Test.TestProtos\Google.Protobuf.Test.TestProtos.csproj", "{ADF24BEB-A318-4530-8448-356B72B820EA}"
EndProject
Global
@@ -40,6 +42,10 @@ Global
{9695E08F-9829-497D-B95C-B38F28D48690}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9695E08F-9829-497D-B95C-B38F28D48690}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9695E08F-9829-497D-B95C-B38F28D48690}.Release|Any CPU.Build.0 = Release|Any CPU
{D25E4804-4DEA-45AB-9F8C-BA4DBD8E5A07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D25E4804-4DEA-45AB-9F8C-BA4DBD8E5A07}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D25E4804-4DEA-45AB-9F8C-BA4DBD8E5A07}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D25E4804-4DEA-45AB-9F8C-BA4DBD8E5A07}.Release|Any CPU.Build.0 = Release|Any CPU
{ADF24BEB-A318-4530-8448-356B72B820EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ADF24BEB-A318-4530-8448-356B72B820EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ADF24BEB-A318-4530-8448-356B72B820EA}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@@ -37,8 +37,13 @@ using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
#if !NET35
using System.Threading;
using System.Threading.Tasks;
#endif
#if NET35
using Google.Protobuf.Compatibility;
#endif
namespace Google.Protobuf
{
@@ -181,6 +186,7 @@ namespace Google.Protobuf
return AttachBytes(bytes);
}
#if !NET35
/// <summary>
/// Constructs a <see cref="ByteString"/> from data in the given stream, asynchronously.
/// </summary>
@@ -189,11 +195,12 @@ namespace Google.Protobuf
/// <param name="stream">The stream to copy into a ByteString.</param>
/// <param name="cancellationToken">The cancellation token to use when reading from the stream, if any.</param>
/// <returns>A ByteString with content read from the given stream.</returns>
public static Task<ByteString> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default)
public static Task<ByteString> FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken))
{
ProtoPreconditions.CheckNotNull(stream, nameof(stream));
return ByteStringAsync.FromStreamAsyncCore(stream, cancellationToken);
}
#endif
/// <summary>
/// Constructs a <see cref="ByteString" /> from the given array. The contents
@@ -340,7 +347,7 @@ namespace Google.Protobuf
{
return true;
}
if (lhs is null || rhs is null)
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
{
return false;
}

View File

@@ -43,6 +43,7 @@ namespace Google.Protobuf
/// </summary>
internal static class ByteStringAsync
{
#if !NET35
internal static async Task<ByteString> FromStreamAsyncCore(Stream stream, CancellationToken cancellationToken)
{
int capacity = stream.CanSeek ? checked((int)(stream.Length - stream.Position)) : 0;
@@ -58,5 +59,6 @@ namespace Google.Protobuf
#endif
return ByteString.AttachBytes(bytes);
}
#endif
}
}

View File

@@ -32,7 +32,10 @@
using Google.Protobuf.Collections;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
namespace Google.Protobuf
@@ -646,6 +649,21 @@ namespace Google.Protobuf
}
}
/// <summary>
/// Called when buffer is empty to read more bytes from the
/// input. If <paramref name="mustSucceed"/> is true, RefillBuffer() guarantees that
/// either there will be at least one byte in the buffer when it returns
/// or it will throw an exception. If <paramref name="mustSucceed"/> is false,
/// RefillBuffer() returns false if no more bytes were available.
/// </summary>
/// <param name="mustSucceed"></param>
/// <returns></returns>
private bool RefillBuffer(bool mustSucceed)
{
var span = new ReadOnlySpan<byte>(buffer);
return state.segmentedBufferHelper.RefillBuffer(ref span, ref state, mustSucceed);
}
/// <summary>
/// Reads a fixed size of bytes from the input.
/// </summary>

View File

@@ -30,9 +30,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using Google.Protobuf.Collections;
using System;
using System.IO;
using System.Security;
using System.Text;
namespace Google.Protobuf
{

View File

@@ -31,6 +31,7 @@
#endregion
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Google.Protobuf.Collections
{

View File

@@ -31,7 +31,9 @@
#endregion
using Google.Protobuf.Compatibility;
using Google.Protobuf.Reflection;
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.IO;
@@ -66,14 +68,18 @@ namespace Google.Protobuf.Collections
/// in future versions.
/// </para>
/// </remarks>
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary, IReadOnlyDictionary<TKey, TValue>
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
#if !NET35
, IReadOnlyDictionary<TKey, TValue>
#endif
{
private static readonly EqualityComparer<TValue> ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TValue>();
private static readonly EqualityComparer<TKey> KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TKey>();
// TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map = new(KeyEqualityComparer);
private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new();
private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(KeyEqualityComparer);
private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
/// <summary>
/// Creates a deep clone of this object.
@@ -141,7 +147,8 @@ namespace Google.Protobuf.Collections
public bool Remove(TKey key)
{
ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
if (map.TryGetValue(key, out LinkedListNode<KeyValuePair<TKey, TValue>> node))
LinkedListNode<KeyValuePair<TKey, TValue>> node;
if (map.TryGetValue(key, out node))
{
map.Remove(key);
node.List.Remove(node);
@@ -163,14 +170,15 @@ namespace Google.Protobuf.Collections
/// <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>
public bool TryGetValue(TKey key, out TValue value)
{
if (map.TryGetValue(key, out LinkedListNode<KeyValuePair<TKey, TValue>> node))
LinkedListNode<KeyValuePair<TKey, TValue>> node;
if (map.TryGetValue(key, out node))
{
value = node.Value.Value;
return true;
}
else
{
value = default;
value = default(TValue);
return false;
}
}
@@ -187,7 +195,8 @@ namespace Google.Protobuf.Collections
get
{
ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
if (TryGetValue(key, out TValue value))
TValue value;
if (TryGetValue(key, out value))
{
return value;
}
@@ -201,8 +210,9 @@ namespace Google.Protobuf.Collections
{
ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
}
LinkedListNode<KeyValuePair<TKey, TValue>> node;
var pair = new KeyValuePair<TKey, TValue>(key, value);
if (map.TryGetValue(key, out LinkedListNode<KeyValuePair<TKey, TValue>> node))
if (map.TryGetValue(key, out node))
{
node.Value = pair;
}
@@ -217,12 +227,12 @@ namespace Google.Protobuf.Collections
/// <summary>
/// Gets a collection containing the keys in the map.
/// </summary>
public ICollection<TKey> Keys => new MapView<TKey>(this, pair => pair.Key, ContainsKey);
public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } }
/// <summary>
/// Gets a collection containing the values in the map.
/// </summary>
public ICollection<TValue> Values => new MapView<TValue>(this, pair => pair.Value, ContainsValue);
public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
/// <summary>
/// Adds the specified entries to the map. The keys and values are not automatically cloned.
@@ -237,28 +247,16 @@ namespace Google.Protobuf.Collections
}
}
/// <summary>
/// Adds the specified entries to the map, replacing any existing entries with the same keys.
/// The keys and values are not automatically cloned.
/// </summary>
/// <remarks>This method primarily exists to be called from MergeFrom methods in generated classes for messages.</remarks>
/// <param name="entries">The entries to add to the map.</param>
public void MergeFrom(IDictionary<TKey, TValue> entries)
{
ProtoPreconditions.CheckNotNull(entries, nameof(entries));
foreach (var pair in entries)
{
this[pair.Key] = pair.Value;
}
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// An enumerator that can be used to iterate through the collection.
/// </returns>
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => list.GetEnumerator();
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return list.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
@@ -266,13 +264,19 @@ namespace Google.Protobuf.Collections
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Adds the specified item to the map.
/// </summary>
/// <param name="item">The item to add to the map.</param>
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) => Add(item.Key, item.Value);
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
/// <summary>
/// Removes all items from the map.
@@ -288,16 +292,21 @@ namespace Google.Protobuf.Collections
/// </summary>
/// <param name="item">The key/value pair to find.</param>
/// <returns></returns>
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item) =>
TryGetValue(item.Key, out TValue value) && ValueEqualityComparer.Equals(item.Value, value);
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
TValue value;
return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value);
}
/// <summary>
/// Copies the key/value pairs in this map to an array.
/// </summary>
/// <param name="array">The array to copy the entries into.</param>
/// <param name="arrayIndex">The index of the array at which to start copying values.</param>
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) =>
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
list.CopyTo(array, arrayIndex);
}
/// <summary>
/// Removes the specified key/value pair from the map.
@@ -311,7 +320,8 @@ namespace Google.Protobuf.Collections
{
throw new ArgumentException("Key is null", nameof(item));
}
if (map.TryGetValue(item.Key, out LinkedListNode<KeyValuePair<TKey, TValue>> node) &&
LinkedListNode<KeyValuePair<TKey, TValue>> node;
if (map.TryGetValue(item.Key, out node) &&
EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.Value))
{
map.Remove(item.Key);
@@ -327,12 +337,12 @@ namespace Google.Protobuf.Collections
/// <summary>
/// Gets the number of elements contained in the map.
/// </summary>
public int Count => list.Count;
public int Count { get { return list.Count; } }
/// <summary>
/// Gets a value indicating whether the map is read-only.
/// </summary>
public bool IsReadOnly => false;
public bool IsReadOnly { get { return false; } }
/// <summary>
/// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
@@ -341,7 +351,10 @@ namespace Google.Protobuf.Collections
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object other) => Equals(other as MapField<TKey, TValue>);
public override bool Equals(object other)
{
return Equals(other as MapField<TKey, TValue>);
}
/// <summary>
/// Returns a hash code for this instance.
@@ -386,7 +399,8 @@ namespace Google.Protobuf.Collections
var valueComparer = ValueEqualityComparer;
foreach (var pair in this)
{
if (!other.TryGetValue(pair.Key, out TValue value))
TValue value;
if (!other.TryGetValue(pair.Key, out value))
{
return false;
}
@@ -518,20 +532,33 @@ namespace Google.Protobuf.Collections
}
#region IDictionary explicit interface implementation
void IDictionary.Add(object key, object value)
{
Add((TKey)key, (TValue)value);
}
void IDictionary.Add(object key, object value) => Add((TKey)key, (TValue)value);
bool IDictionary.Contains(object key)
{
if (!(key is TKey))
{
return false;
}
return ContainsKey((TKey)key);
}
bool IDictionary.Contains(object key) => key is TKey k && ContainsKey(k);
IDictionaryEnumerator IDictionary.GetEnumerator() => new DictionaryEnumerator(GetEnumerator());
IDictionaryEnumerator IDictionary.GetEnumerator()
{
return new DictionaryEnumerator(GetEnumerator());
}
void IDictionary.Remove(object key)
{
ProtoPreconditions.CheckNotNull(key, nameof(key));
if (key is TKey k)
if (!(key is TKey))
{
Remove(k);
return;
}
Remove((TKey)key);
}
void ICollection.CopyTo(Array array, int index)
@@ -541,27 +568,28 @@ namespace Google.Protobuf.Collections
temp.CopyTo(array, index);
}
bool IDictionary.IsFixedSize => false;
bool IDictionary.IsFixedSize { get { return false; } }
ICollection IDictionary.Keys => (ICollection)Keys;
ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
ICollection IDictionary.Values => (ICollection)Values;
ICollection IDictionary.Values { get { return (ICollection)Values; } }
bool ICollection.IsSynchronized => false;
bool ICollection.IsSynchronized { get { return false; } }
object ICollection.SyncRoot => this;
object ICollection.SyncRoot { get { return this; } }
object IDictionary.this[object key]
{
get
{
ProtoPreconditions.CheckNotNull(key, nameof(key));
if (key is TKey k)
if (!(key is TKey))
{
TryGetValue(k, out TValue value);
return value;
return null;
}
return null;
TValue value;
TryGetValue((TKey)key, out value);
return value;
}
set
@@ -572,8 +600,11 @@ namespace Google.Protobuf.Collections
#endregion
#region IReadOnlyDictionary explicit interface implementation
#if !NET35
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
#endif
#endregion
private class DictionaryEnumerator : IDictionaryEnumerator
@@ -585,14 +616,20 @@ namespace Google.Protobuf.Collections
this.enumerator = enumerator;
}
public bool MoveNext() => enumerator.MoveNext();
public bool MoveNext()
{
return enumerator.MoveNext();
}
public void Reset() => enumerator.Reset();
public void Reset()
{
enumerator.Reset();
}
public object Current => Entry;
public DictionaryEntry Entry => new DictionaryEntry(Key, Value);
public object Key => enumerator.Current.Key;
public object Value => enumerator.Current.Value;
public object Current { get { return Entry; } }
public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
public object Key { get { return enumerator.Current.Key; } }
public object Value { get { return enumerator.Current.Value; } }
}
/// <summary>
@@ -651,19 +688,28 @@ namespace Google.Protobuf.Collections
this.containsCheck = containsCheck;
}
public int Count => parent.Count;
public int Count { get { return parent.Count; } }
public bool IsReadOnly => true;
public bool IsReadOnly { get { return true; } }
public bool IsSynchronized => false;
public bool IsSynchronized { get { return false; } }
public object SyncRoot => parent;
public object SyncRoot { get { return parent; } }
public void Add(T item) => throw new NotSupportedException();
public void Add(T item)
{
throw new NotSupportedException();
}
public void Clear() => throw new NotSupportedException();
public void Clear()
{
throw new NotSupportedException();
}
public bool Contains(T item) => containsCheck(item);
public bool Contains(T item)
{
return containsCheck(item);
}
public void CopyTo(T[] array, int arrayIndex)
{
@@ -686,9 +732,15 @@ namespace Google.Protobuf.Collections
return parent.list.Select(projection).GetEnumerator();
}
public bool Remove(T item) => throw new NotSupportedException();
public bool Remove(T item)
{
throw new NotSupportedException();
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void CopyTo(Array array, int index)
{

View File

@@ -0,0 +1,147 @@
#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;
using System.Collections;
using System.Collections.Generic;
namespace Google.Protobuf.Collections
{
/// <summary>
/// Read-only wrapper around another dictionary.
/// </summary>
internal sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
private readonly IDictionary<TKey, TValue> wrapped;
public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped)
{
this.wrapped = wrapped;
}
public void Add(TKey key, TValue value)
{
throw new InvalidOperationException();
}
public bool ContainsKey(TKey key)
{
return wrapped.ContainsKey(key);
}
public ICollection<TKey> Keys
{
get { return wrapped.Keys; }
}
public bool Remove(TKey key)
{
throw new InvalidOperationException();
}
public bool TryGetValue(TKey key, out TValue value)
{
return wrapped.TryGetValue(key, out value);
}
public ICollection<TValue> Values
{
get { return wrapped.Values; }
}
public TValue this[TKey key]
{
get { return wrapped[key]; }
set { throw new InvalidOperationException(); }
}
public void Add(KeyValuePair<TKey, TValue> item)
{
throw new InvalidOperationException();
}
public void Clear()
{
throw new InvalidOperationException();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return wrapped.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
wrapped.CopyTo(array, arrayIndex);
}
public int Count
{
get { return wrapped.Count; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
throw new InvalidOperationException();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return wrapped.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable) wrapped).GetEnumerator();
}
public override bool Equals(object obj)
{
return wrapped.Equals(obj);
}
public override int GetHashCode()
{
return wrapped.GetHashCode();
}
public override string ToString()
{
return wrapped.ToString();
}
}
}

View File

@@ -35,6 +35,7 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Security;
using System.Threading;
namespace Google.Protobuf.Collections
{
@@ -47,7 +48,10 @@ namespace Google.Protobuf.Collections
/// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
/// </remarks>
/// <typeparam name="T">The element type of the repeated field.</typeparam>
public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>, IReadOnlyList<T>
public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>
#if !NET35
, IReadOnlyList<T>
#endif
{
private static readonly EqualityComparer<T> EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<T>();
private static readonly T[] EmptyArray = new T[0];
@@ -73,7 +77,8 @@ namespace Google.Protobuf.Collections
if (array != EmptyArray)
{
clone.array = (T[])array.Clone();
if (clone.array is IDeepCloneable<T>[] cloneableArray)
IDeepCloneable<T>[] cloneableArray = clone.array as IDeepCloneable<T>[];
if (cloneableArray != null)
{
for (int i = 0; i < count; i++)
{
@@ -279,9 +284,8 @@ namespace Google.Protobuf.Collections
}
/// <summary>
/// Gets and sets the capacity of the RepeatedField's internal array.
/// When set, the internal array is reallocated to the given capacity.
/// <exception cref="ArgumentOutOfRangeException">The new value is less than <see cref="Count"/>.</exception>
/// Gets and sets the capacity of the RepeatedField's internal array. WHen set, the internal array is reallocated to the given capacity.
/// <exception cref="ArgumentOutOfRangeException">The new value is less than Count -or- when Count is less than 0.</exception>
/// </summary>
public int Capacity
{
@@ -339,10 +343,7 @@ namespace Google.Protobuf.Collections
/// </summary>
public void Clear()
{
// Clear the content of the array (so that any objects it referred to can be garbage collected)
// but keep the capacity the same. This allows large repeated fields to be reused without
// array reallocation.
Array.Clear(array, 0, count);
array = EmptyArray;
count = 0;
}
@@ -351,7 +352,10 @@ namespace Google.Protobuf.Collections
/// </summary>
/// <param name="item">The item to find.</param>
/// <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
public bool Contains(T item) => IndexOf(item) != -1;
public bool Contains(T item)
{
return IndexOf(item) != -1;
}
/// <summary>
/// Copies this collection to the given array.
@@ -377,7 +381,7 @@ namespace Google.Protobuf.Collections
}
Array.Copy(array, index + 1, array, index, count - index - 1);
count--;
array[count] = default;
array[count] = default(T);
return true;
}
@@ -401,7 +405,8 @@ namespace Google.Protobuf.Collections
// Optimization 1: If the collection we're adding is already a RepeatedField<T>,
// we know the values are valid.
if (values is RepeatedField<T> otherRepeatedField)
var otherRepeatedField = values as RepeatedField<T>;
if (otherRepeatedField != null)
{
EnsureSize(count + otherRepeatedField.count);
Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count);
@@ -411,7 +416,8 @@ namespace Google.Protobuf.Collections
// Optimization 2: The collection is an ICollection, so we can expand
// just once and ask the collection to copy itself into the array.
if (values is ICollection collection)
var collection = values as ICollection;
if (collection != null)
{
var extraCount = collection.Count;
// For reference types and nullable value types, we need to check that there are no nulls
@@ -481,15 +487,21 @@ namespace Google.Protobuf.Collections
/// <returns>
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
/// </returns>
public override bool Equals(object obj) => Equals(obj as RepeatedField<T>);
public override bool Equals(object obj)
{
return Equals(obj as RepeatedField<T>);
}
/// <summary>
/// Returns an enumerator that iterates through a collection.
/// </summary>
/// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns>
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Returns a hash code for this instance.
@@ -514,7 +526,7 @@ namespace Google.Protobuf.Collections
/// <returns><c>true</c> if <paramref name="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
public bool Equals(RepeatedField<T> other)
{
if (other is null)
if (ReferenceEquals(other, null))
{
return false;
}
@@ -587,7 +599,7 @@ namespace Google.Protobuf.Collections
}
Array.Copy(array, index + 1, array, index, count - index - 1);
count--;
array[count] = default;
array[count] = default(T);
}
/// <summary>
@@ -633,7 +645,10 @@ namespace Google.Protobuf.Collections
#region Explicit interface implementation for IList and ICollection.
bool IList.IsFixedSize => false;
void ICollection.CopyTo(Array array, int index) => Array.Copy(this.array, 0, array, index, count);
void ICollection.CopyTo(Array array, int index)
{
Array.Copy(this.array, 0, array, index, count);
}
bool ICollection.IsSynchronized => false;
@@ -641,8 +656,8 @@ namespace Google.Protobuf.Collections
object IList.this[int index]
{
get => this[index];
set => this[index] = (T)value;
get { return this[index]; }
set { this[index] = (T)value; }
}
int IList.Add(object value)
@@ -651,18 +666,32 @@ namespace Google.Protobuf.Collections
return count - 1;
}
bool IList.Contains(object value) => (value is T t && Contains(t));
bool IList.Contains(object value)
{
return (value is T && Contains((T)value));
}
int IList.IndexOf(object value) => (value is T t) ? IndexOf(t) : -1;
int IList.IndexOf(object value)
{
if (!(value is T))
{
return -1;
}
return IndexOf((T)value);
}
void IList.Insert(int index, object value) => Insert(index, (T) value);
void IList.Insert(int index, object value)
{
Insert(index, (T) value);
}
void IList.Remove(object value)
{
if (value is T t)
if (!(value is T))
{
Remove(t);
return;
}
Remove((T)value);
}
#endregion
}

View File

@@ -1,6 +1,6 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2022 Google Inc. All rights reserved.
// Copyright 2017 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
@@ -30,34 +30,18 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
#if NET35
using System;
using System.Linq;
using System.Reflection;
namespace Google.Protobuf.Test;
internal class ParsingPrimitivesTest
namespace Google.Protobuf.Compatibility
{
// Note: test cases use integers rather than bytes as they're easier
// to specify in attributes.
[Test]
[TestCase("\ufffd", 255)]
[TestCase("A\ufffd", 65, 255)]
[TestCase("A\ufffd\ufffdB", 65, 255, 255, 66)]
// Overlong form of "space"
[TestCase("\ufffd\ufffd", 0xc0, 0xa0)]
public void ReadRawString_NonUtf8(string expectedText, params int[] bytes)
// .NET Core (at least netstandard1.0) doesn't have Delegate.CreateDelegate, and .NET 3.5 doesn't have
// MethodInfo.CreateDelegate. Proxy from one to the other on .NET 3.5...
internal static class MethodInfoExtensions
{
var context = CreateContext(bytes);
string text = ParsingPrimitives.ReadRawString(ref context.buffer, ref context.state, bytes.Length);
Assert.AreEqual(expectedText, text);
}
private static ParseContext CreateContext(int[] bytes)
{
byte[] actualBytes = bytes.Select(b => (byte) b).ToArray();
ParseContext.Initialize(actualBytes.AsSpan(), out var context);
return context;
internal static Delegate CreateDelegate(this MethodInfo method, Type type) =>
Delegate.CreateDelegate(type, method);
}
}
#endif

View File

@@ -47,7 +47,11 @@ namespace Google.Protobuf.Compatibility
/// </summary>
internal static MethodInfo GetGetMethod(this PropertyInfo target)
{
#if NET35
var method = target.GetGetMethod();
#else
var method = target.GetMethod;
#endif
return method != null && method.IsPublic ? method : null;
}
@@ -57,7 +61,11 @@ namespace Google.Protobuf.Compatibility
/// </summary>
internal static MethodInfo GetSetMethod(this PropertyInfo target)
{
#if NET35
var method = target.GetSetMethod();
#else
var method = target.SetMethod;
#endif
return method != null && method.IsPublic ? method : null;
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright notice and license
// Protocol Buffers - Google's data interchange format
// Copyright 2022 Google Inc. All rights reserved.
// Copyright 2015 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
@@ -30,32 +30,37 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using NUnit.Framework;
#if NET35
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
namespace Google.Protobuf.Test;
internal class WritingPrimitivesTest
namespace Google.Protobuf.Compatibility
{
[Test]
public void WriteRawString_IllFormedUnicodeString()
/// <summary>
/// Extension methods for <see cref="Stream"/> in order to provide
/// backwards compatibility with .NET 3.5
/// </summary>
public static class StreamExtensions
{
// See https://codeblog.jonskeet.uk/2014/11/07/when-is-a-string-not-a-string/
char c1 = '\u0058';
char c2 = '\ud800';
char c3 = '\u0059';
string text = new string(new[] { c1, c2, c3 });
Span<byte> buffer = new byte[10];
WriteContext.Initialize(ref buffer, out var context);
WritingPrimitives.WriteString(ref context.buffer, ref context.state, text);
// 81920 seems to be the default buffer size used in .NET 4.5.1
private const int BUFFER_SIZE = 81920;
// The high surrogate is written out in a "raw" form, surrounded by the ASCII
// characters.
byte[] expectedBytes = { 0x5, 0x58, 0xef, 0xbf, 0xbd, 0x59 };
Assert.AreEqual(expectedBytes, buffer.Slice(0, context.state.position).ToArray());
/// <summary>
/// Write the contents of the current stream to the destination stream
/// </summary>
public static void CopyTo(this Stream source, Stream destination)
{
if (destination == null)
{
throw new ArgumentNullException(nameof(destination));
}
byte[] buffer = new byte[BUFFER_SIZE];
int numBytesRead;
while ((numBytesRead = source.Read(buffer, 0, buffer.Length)) > 0) {
destination.Write(buffer, 0, numBytesRead);
}
}
}
}
#endif

View File

@@ -34,6 +34,7 @@ using System;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
#if !NET35
namespace Google.Protobuf.Compatibility
{
/// <summary>
@@ -111,3 +112,4 @@ namespace Google.Protobuf.Compatibility
}
}
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -77,7 +77,7 @@ namespace Google.Protobuf
this.codec = codec;
}
internal TValue DefaultValue => codec != null ? codec.DefaultValue : default;
internal TValue DefaultValue => codec != null ? codec.DefaultValue : default(TValue);
internal override Type TargetType => typeof(TTarget);

View File

@@ -55,7 +55,7 @@ namespace Google.Protobuf
internal static ExtensionComparer Instance = new ExtensionComparer();
}
private readonly IDictionary<ObjectIntPair<Type>, Extension> extensions;
private IDictionary<ObjectIntPair<Type>, Extension> extensions;
/// <summary>
/// Creates a new empty extension registry

View File

@@ -61,7 +61,8 @@ namespace Google.Protobuf
/// </summary>
public static TValue Get<TTarget, TValue>(ref ExtensionSet<TTarget> set, Extension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
{
if (TryGetValue(ref set, extension, out IExtensionValue value))
IExtensionValue value;
if (TryGetValue(ref set, extension, out value))
{
// The stored ExtensionValue can be a different type to what is being requested.
// This happens when the same extension proto is compiled in different assemblies.
@@ -97,7 +98,7 @@ namespace Google.Protobuf
}
}
}
else
else
{
return extension.DefaultValue;
}
@@ -108,7 +109,8 @@ namespace Google.Protobuf
/// </summary>
public static RepeatedField<TValue> Get<TTarget, TValue>(ref ExtensionSet<TTarget> set, RepeatedExtension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
{
if (TryGetValue(ref set, extension, out IExtensionValue value))
IExtensionValue value;
if (TryGetValue(ref set, extension, out value))
{
if (value is RepeatedExtensionValue<TValue> extensionValue)
{
@@ -130,7 +132,7 @@ namespace Google.Protobuf
}
}
}
else
else
{
return null;
}
@@ -191,7 +193,8 @@ namespace Google.Protobuf
/// </summary>
public static bool Has<TTarget, TValue>(ref ExtensionSet<TTarget> set, Extension<TTarget, TValue> extension) where TTarget : IExtendableMessage<TTarget>
{
return TryGetValue(ref set, extension, out IExtensionValue _);
IExtensionValue value;
return TryGetValue(ref set, extension, out value);
}
/// <summary>
@@ -249,18 +252,20 @@ namespace Google.Protobuf
/// </summary>
public static bool TryMergeFieldFrom<TTarget>(ref ExtensionSet<TTarget> set, ref ParseContext ctx) where TTarget : IExtendableMessage<TTarget>
{
Extension extension;
int lastFieldNumber = WireFormat.GetTagFieldNumber(ctx.LastTag);
if (set != null && set.ValuesByNumber.TryGetValue(lastFieldNumber, out IExtensionValue extensionValue))
IExtensionValue extensionValue;
if (set != null && set.ValuesByNumber.TryGetValue(lastFieldNumber, out extensionValue))
{
extensionValue.MergeFrom(ref ctx);
return true;
}
else if (ctx.ExtensionRegistry != null && ctx.ExtensionRegistry.ContainsInputField(ctx.LastTag, typeof(TTarget), out Extension extension))
else if (ctx.ExtensionRegistry != null && ctx.ExtensionRegistry.ContainsInputField(ctx.LastTag, typeof(TTarget), out extension))
{
IExtensionValue value = extension.CreateValue();
value.MergeFrom(ref ctx);
set ??= new ExtensionSet<TTarget>();
set = (set ?? new ExtensionSet<TTarget>());
set.ValuesByNumber.Add(extension.FieldNumber, value);
return true;
}
@@ -285,7 +290,8 @@ namespace Google.Protobuf
}
foreach (var pair in second.ValuesByNumber)
{
if (first.ValuesByNumber.TryGetValue(pair.Key, out IExtensionValue value))
IExtensionValue value;
if (first.ValuesByNumber.TryGetValue(pair.Key, out value))
{
value.MergeFrom(pair.Value);
}
@@ -359,7 +365,8 @@ namespace Google.Protobuf
}
foreach (var pair in ValuesByNumber)
{
if (!otherSet.ValuesByNumber.TryGetValue(pair.Key, out IExtensionValue secondValue))
IExtensionValue secondValue;
if (!otherSet.ValuesByNumber.TryGetValue(pair.Key, out secondValue))
{
return false;
}

View File

@@ -32,6 +32,7 @@
using Google.Protobuf.Collections;
using System;
using System.Linq;
namespace Google.Protobuf
{
@@ -49,7 +50,7 @@ namespace Google.Protobuf
internal sealed class ExtensionValue<T> : IExtensionValue
{
private T field;
private readonly FieldCodec<T> codec;
private FieldCodec<T> codec;
internal ExtensionValue(FieldCodec<T> codec)
{

View File

@@ -31,6 +31,7 @@
#endregion
using Google.Protobuf.Collections;
using Google.Protobuf.Compatibility;
using Google.Protobuf.WellKnownTypes;
using System;
using System.Collections.Generic;
@@ -50,105 +51,150 @@ namespace Google.Protobuf
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<string> ForString(uint tag) => ForString(tag, "");
public static FieldCodec<string> ForString(uint tag)
{
return FieldCodec.ForString(tag, "");
}
/// <summary>
/// Retrieves a codec suitable for a bytes field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<ByteString> ForBytes(uint tag) => ForBytes(tag, ByteString.Empty);
public static FieldCodec<ByteString> ForBytes(uint tag)
{
return FieldCodec.ForBytes(tag, ByteString.Empty);
}
/// <summary>
/// Retrieves a codec suitable for a bool field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<bool> ForBool(uint tag) => ForBool(tag, false);
public static FieldCodec<bool> ForBool(uint tag)
{
return FieldCodec.ForBool(tag, false);
}
/// <summary>
/// Retrieves a codec suitable for an int32 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<int> ForInt32(uint tag) => ForInt32(tag, 0);
public static FieldCodec<int> ForInt32(uint tag)
{
return FieldCodec.ForInt32(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for an sint32 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<int> ForSInt32(uint tag) => ForSInt32(tag, 0);
public static FieldCodec<int> ForSInt32(uint tag)
{
return FieldCodec.ForSInt32(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for a fixed32 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<uint> ForFixed32(uint tag) => ForFixed32(tag, 0);
public static FieldCodec<uint> ForFixed32(uint tag)
{
return FieldCodec.ForFixed32(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for an sfixed32 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<int> ForSFixed32(uint tag) => ForSFixed32(tag, 0);
public static FieldCodec<int> ForSFixed32(uint tag)
{
return FieldCodec.ForSFixed32(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for a uint32 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<uint> ForUInt32(uint tag) => ForUInt32(tag, 0);
public static FieldCodec<uint> ForUInt32(uint tag)
{
return FieldCodec.ForUInt32(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for an int64 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<long> ForInt64(uint tag) => ForInt64(tag, 0);
public static FieldCodec<long> ForInt64(uint tag)
{
return FieldCodec.ForInt64(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for an sint64 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<long> ForSInt64(uint tag) => ForSInt64(tag, 0);
public static FieldCodec<long> ForSInt64(uint tag)
{
return FieldCodec.ForSInt64(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for a fixed64 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<ulong> ForFixed64(uint tag) => ForFixed64(tag, 0);
public static FieldCodec<ulong> ForFixed64(uint tag)
{
return FieldCodec.ForFixed64(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for an sfixed64 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<long> ForSFixed64(uint tag) => ForSFixed64(tag, 0);
public static FieldCodec<long> ForSFixed64(uint tag)
{
return FieldCodec.ForSFixed64(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for a uint64 field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<ulong> ForUInt64(uint tag) => ForUInt64(tag, 0);
public static FieldCodec<ulong> ForUInt64(uint tag)
{
return FieldCodec.ForUInt64(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for a float field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<float> ForFloat(uint tag) => ForFloat(tag, 0);
public static FieldCodec<float> ForFloat(uint tag)
{
return FieldCodec.ForFloat(tag, 0);
}
/// <summary>
/// Retrieves a codec suitable for a double field with the given tag.
/// </summary>
/// <param name="tag">The tag.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<double> ForDouble(uint tag) => ForDouble(tag, 0);
public static FieldCodec<double> ForDouble(uint tag)
{
return FieldCodec.ForDouble(tag, 0);
}
// Enums are tricky. We can probably use expression trees to build these delegates automatically,
// but it's easy to generate the code for it.
@@ -160,8 +206,10 @@ namespace Google.Protobuf
/// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
/// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
/// <returns>A codec for the given tag.</returns>
public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32) =>
ForEnum(tag, toInt32, fromInt32, default);
public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
{
return FieldCodec.ForEnum(tag, toInt32, fromInt32, default(T));
}
/// <summary>
/// Retrieves a codec suitable for a string field with the given tag.
@@ -517,7 +565,8 @@ namespace Google.Protobuf
/// </summary>
internal static FieldCodec<T> GetCodec<T>()
{
if (!Codecs.TryGetValue(typeof(T), out object value))
object value;
if (!Codecs.TryGetValue(typeof(T), out value))
{
throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T));
}
@@ -526,7 +575,8 @@ namespace Google.Protobuf
internal static ValueReader<T?> GetReader<T>() where T : struct
{
if (!Readers.TryGetValue(typeof(T), out object value))
object value;
if (!Readers.TryGetValue(typeof(T), out value))
{
throw new InvalidOperationException("Invalid type argument requested for wrapper reader: " + typeof(T));
}

View File

@@ -120,7 +120,8 @@ namespace Google.Protobuf
return this;
}
if (!node.Children.TryGetValue(part, out Node childNode))
Node childNode;
if (!node.Children.TryGetValue(part, out childNode))
{
createNewBranch = true;
childNode = new Node();
@@ -332,24 +333,15 @@ namespace Google.Protobuf
{
if (sourceField != null)
{
// Well-known wrapper types are represented as nullable primitive types, so we do not "merge" them.
// Instead, any non-null value just overwrites the previous value directly.
if (field.MessageType.IsWrapperType)
var sourceByteString = ((IMessage)sourceField).ToByteString();
var destinationValue = (IMessage)field.Accessor.GetValue(destination);
if (destinationValue != null)
{
field.Accessor.SetValue(destination, sourceField);
destinationValue.MergeFrom(sourceByteString);
}
else
{
var sourceByteString = ((IMessage)sourceField).ToByteString();
var destinationValue = (IMessage)field.Accessor.GetValue(destination);
if (destinationValue != null)
{
destinationValue.MergeFrom(sourceByteString);
}
else
{
field.Accessor.SetValue(destination, field.MessageType.Parser.ParseFrom(sourceByteString));
}
field.Accessor.SetValue(destination, field.MessageType.Parser.ParseFrom(sourceByteString));
}
}
}

View File

@@ -1,12 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<!-- If you update this, update the .csproj in the Docker file as well -->
<PropertyGroup>
<Description>C# runtime library for Protocol Buffers - Google's data interchange format.</Description>
<Copyright>Copyright 2015, Google Inc.</Copyright>
<AssemblyTitle>Google Protocol Buffers</AssemblyTitle>
<VersionPrefix>3.21.8</VersionPrefix>
<LangVersion>10.0</LangVersion>
<VersionPrefix>3.21.12</VersionPrefix>
<!-- C# 7.2 is required for Span/BufferWriter/ReadOnlySequence -->
<LangVersion>7.2</LangVersion>
<Authors>Google Inc.</Authors>
<TargetFrameworks>netstandard1.1;netstandard2.0;net45;net50</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@@ -136,5 +136,5 @@ namespace Google.Protobuf
{
return new InvalidProtocolBufferException("Message was missing required fields");
}
}
}
}

View File

@@ -62,13 +62,9 @@ namespace Google.Protobuf
internal const string AnyTypeUrlField = "@type";
internal const string AnyDiagnosticValueField = "@value";
internal const string AnyWellKnownTypeValueField = "value";
private const string TypeUrlPrefix = "type.googleapis.com";
private const string NameValueSeparator = ": ";
private const string ValueSeparator = ", ";
private const string MultilineValueSeparator = ",";
private const char ObjectOpenBracket = '{';
private const char ObjectCloseBracket = '}';
private const char ListBracketOpen = '[';
private const char ListBracketClose = ']';
private const string PropertySeparator = ", ";
/// <summary>
/// Returns a formatter using the default settings.
@@ -145,26 +141,11 @@ namespace Google.Protobuf
/// Formats the specified message as JSON.
/// </summary>
/// <param name="message">The message to format.</param>
/// <remarks>This method delegates to <c>Format(IMessage, int)</c> with <c>indentationLevel = 0</c>.</remarks>
/// <returns>The formatted message.</returns>
public string Format(IMessage message) => Format(message, indentationLevel: 0);
/// <summary>
/// Formats the specified message as JSON.
/// </summary>
/// <param name="message">The message to format.</param>
/// <param name="indentationLevel">Indentation level to start at.</param>
/// <remarks>To keep consistent indentation when embedding a message inside another JSON string, set <paramref name="indentationLevel"/>. E.g:
/// <code>
/// var response = $@"{{
/// ""data"": { Format(message, indentationLevel: 1) }
/// }}"</code>
/// </remarks>
/// <returns>The formatted message.</returns>
public string Format(IMessage message, int indentationLevel)
public string Format(IMessage message)
{
var writer = new StringWriter();
Format(message, writer, indentationLevel);
Format(message, writer);
return writer.ToString();
}
@@ -173,29 +154,19 @@ namespace Google.Protobuf
/// </summary>
/// <param name="message">The message to format.</param>
/// <param name="writer">The TextWriter to write the formatted message to.</param>
/// <remarks>This method delegates to <c>Format(IMessage, TextWriter, int)</c> with <c>indentationLevel = 0</c>.</remarks>
/// <returns>The formatted message.</returns>
public void Format(IMessage message, TextWriter writer) => Format(message, writer, indentationLevel: 0);
/// <summary>
/// Formats the specified message as JSON. When <see cref="Settings.Indentation"/> is not null, start indenting at the specified <paramref name="indentationLevel"/>.
/// </summary>
/// <param name="message">The message to format.</param>
/// <param name="writer">The TextWriter to write the formatted message to.</param>
/// <param name="indentationLevel">Indentation level to start at.</param>
/// <remarks>To keep consistent indentation when embedding a message inside another JSON string, set <paramref name="indentationLevel"/>.</remarks>
public void Format(IMessage message, TextWriter writer, int indentationLevel)
public void Format(IMessage message, TextWriter writer)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(writer, nameof(writer));
if (message.Descriptor.IsWellKnownType)
{
WriteWellKnownTypeValue(writer, message.Descriptor, message, indentationLevel);
WriteWellKnownTypeValue(writer, message.Descriptor, message);
}
else
{
WriteMessage(writer, message, indentationLevel);
WriteMessage(writer, message);
}
}
@@ -222,7 +193,7 @@ namespace Google.Protobuf
return diagnosticFormatter.Format(message);
}
private void WriteMessage(TextWriter writer, IMessage message, int indentationLevel)
private void WriteMessage(TextWriter writer, IMessage message)
{
if (message == null)
{
@@ -231,19 +202,19 @@ namespace Google.Protobuf
}
if (DiagnosticOnly)
{
if (message is ICustomDiagnosticMessage customDiagnosticMessage)
ICustomDiagnosticMessage customDiagnosticMessage = message as ICustomDiagnosticMessage;
if (customDiagnosticMessage != null)
{
writer.Write(customDiagnosticMessage.ToDiagnosticString());
return;
}
}
WriteBracketOpen(writer, ObjectOpenBracket);
bool writtenFields = WriteMessageFields(writer, message, false, indentationLevel + 1);
WriteBracketClose(writer, ObjectCloseBracket, writtenFields, indentationLevel);
writer.Write("{ ");
bool writtenFields = WriteMessageFields(writer, message, false);
writer.Write(writtenFields ? " }" : "}");
}
private bool WriteMessageFields(TextWriter writer, IMessage message, bool assumeFirstFieldWritten, int indentationLevel)
private bool WriteMessageFields(TextWriter writer, IMessage message, bool assumeFirstFieldWritten)
{
var fields = message.Descriptor.Fields;
bool first = !assumeFirstFieldWritten;
@@ -257,8 +228,10 @@ namespace Google.Protobuf
continue;
}
MaybeWriteValueSeparator(writer, first);
MaybeWriteValueWhitespace(writer, indentationLevel);
if (!first)
{
writer.Write(PropertySeparator);
}
if (settings.PreserveProtoFieldNames)
{
@@ -269,23 +242,13 @@ namespace Google.Protobuf
WriteString(writer, accessor.Descriptor.JsonName);
}
writer.Write(NameValueSeparator);
WriteValue(writer, value, indentationLevel);
WriteValue(writer, value);
first = false;
}
return !first;
}
private void MaybeWriteValueSeparator(TextWriter writer, bool first)
{
if (first)
{
return;
}
writer.Write(settings.Indentation == null ? ValueSeparator : MultilineValueSeparator);
}
/// <summary>
/// Determines whether or not a field value should be serialized according to the field,
/// its value in the message, and the settings of this formatter.
@@ -357,20 +320,39 @@ namespace Google.Protobuf
IList list = (IList) value;
return list.Count == 0;
}
return descriptor.FieldType switch
switch (descriptor.FieldType)
{
FieldType.Bool => (bool) value == false,
FieldType.Bytes => (ByteString) value == ByteString.Empty,
FieldType.String => (string) value == "",
FieldType.Double => (double) value == 0.0,
FieldType.SInt32 or FieldType.Int32 or FieldType.SFixed32 or FieldType.Enum => (int) value == 0,
FieldType.Fixed32 or FieldType.UInt32 => (uint) value == 0,
FieldType.Fixed64 or FieldType.UInt64 => (ulong) value == 0,
FieldType.SFixed64 or FieldType.Int64 or FieldType.SInt64 => (long) value == 0,
FieldType.Float => (float) value == 0f,
FieldType.Message or FieldType.Group => value == null,
_ => throw new ArgumentException("Invalid field type"),
};
case FieldType.Bool:
return (bool) value == false;
case FieldType.Bytes:
return (ByteString) value == ByteString.Empty;
case FieldType.String:
return (string) value == "";
case FieldType.Double:
return (double) value == 0.0;
case FieldType.SInt32:
case FieldType.Int32:
case FieldType.SFixed32:
case FieldType.Enum:
return (int) value == 0;
case FieldType.Fixed32:
case FieldType.UInt32:
return (uint) value == 0;
case FieldType.Fixed64:
case FieldType.UInt64:
return (ulong) value == 0;
case FieldType.SFixed64:
case FieldType.Int64:
case FieldType.SInt64:
return (long) value == 0;
case FieldType.Float:
return (float) value == 0f;
case FieldType.Message:
case FieldType.Group: // Never expect to get this, but...
return value == null;
default:
throw new ArgumentException("Invalid field type");
}
}
/// <summary>
@@ -381,46 +363,34 @@ namespace Google.Protobuf
/// </summary>
/// <param name="writer">The writer to write the value to. Must not be null.</param>
/// <param name="value">The value to write. May be null.</param>
/// <remarks>Delegates to <c>WriteValue(TextWriter, object, int)</c> with <c>indentationLevel = 0</c>.</remarks>
public void WriteValue(TextWriter writer, object value) => WriteValue(writer, value, 0);
/// <summary>
/// Writes a single value to the given writer as JSON. Only types understood by
/// Protocol Buffers can be written in this way. This method is only exposed for
/// advanced use cases; most users should be using <see cref="Format(IMessage)"/>
/// or <see cref="Format(IMessage, TextWriter)"/>.
/// </summary>
/// <param name="writer">The writer to write the value to. Must not be null.</param>
/// <param name="value">The value to write. May be null.</param>
/// <param name="indentationLevel">The current indentationLevel. Not used when <see cref="Settings.Indentation"/> is null.</param>
public void WriteValue(TextWriter writer, object value, int indentationLevel)
public void WriteValue(TextWriter writer, object value)
{
if (value == null || value is NullValue)
{
WriteNull(writer);
}
else if (value is bool b)
else if (value is bool)
{
writer.Write(b ? "true" : "false");
writer.Write((bool)value ? "true" : "false");
}
else if (value is ByteString byteString)
else if (value is ByteString)
{
// Nothing in Base64 needs escaping
writer.Write('"');
writer.Write(byteString.ToBase64());
writer.Write(((ByteString)value).ToBase64());
writer.Write('"');
}
else if (value is string str)
else if (value is string)
{
WriteString(writer, str);
WriteString(writer, (string)value);
}
else if (value is IDictionary dictionary)
else if (value is IDictionary)
{
WriteDictionary(writer, dictionary, indentationLevel);
WriteDictionary(writer, (IDictionary)value);
}
else if (value is IList list)
else if (value is IList)
{
WriteList(writer, list, indentationLevel);
WriteList(writer, (IList)value);
}
else if (value is int || value is uint)
{
@@ -467,9 +437,9 @@ namespace Google.Protobuf
writer.Write(text);
}
}
else if (value is IMessage message)
else if (value is IMessage)
{
Format(message, writer, indentationLevel);
Format((IMessage)value, writer);
}
else
{
@@ -483,7 +453,7 @@ namespace Google.Protobuf
/// values are using the embedded well-known types, in order to allow for dynamic messages
/// in the future.
/// </summary>
private void WriteWellKnownTypeValue(TextWriter writer, MessageDescriptor descriptor, object value, int indentationLevel)
private void WriteWellKnownTypeValue(TextWriter writer, MessageDescriptor descriptor, object value)
{
// Currently, we can never actually get here, because null values are always handled by the caller. But if we *could*,
// this would do the right thing.
@@ -499,8 +469,9 @@ namespace Google.Protobuf
// WriteValue will do the right thing.)
if (descriptor.IsWrapperType)
{
if (value is IMessage message)
if (value is IMessage)
{
var message = (IMessage) value;
value = message.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.GetValue(message);
}
WriteValue(writer, value);
@@ -523,26 +494,26 @@ namespace Google.Protobuf
}
if (descriptor.FullName == Struct.Descriptor.FullName)
{
WriteStruct(writer, (IMessage)value, indentationLevel);
WriteStruct(writer, (IMessage)value);
return;
}
if (descriptor.FullName == ListValue.Descriptor.FullName)
{
var fieldAccessor = descriptor.Fields[ListValue.ValuesFieldNumber].Accessor;
WriteList(writer, (IList)fieldAccessor.GetValue((IMessage)value), indentationLevel);
WriteList(writer, (IList)fieldAccessor.GetValue((IMessage)value));
return;
}
if (descriptor.FullName == Value.Descriptor.FullName)
{
WriteStructFieldValue(writer, (IMessage)value, indentationLevel);
WriteStructFieldValue(writer, (IMessage)value);
return;
}
if (descriptor.FullName == Any.Descriptor.FullName)
{
WriteAny(writer, (IMessage)value, indentationLevel);
WriteAny(writer, (IMessage)value);
return;
}
WriteMessage(writer, (IMessage)value, indentationLevel);
WriteMessage(writer, (IMessage)value);
}
private void WriteTimestamp(TextWriter writer, IMessage value)
@@ -570,7 +541,7 @@ namespace Google.Protobuf
writer.Write(FieldMask.ToJson(paths, DiagnosticOnly));
}
private void WriteAny(TextWriter writer, IMessage value, int indentationLevel)
private void WriteAny(TextWriter writer, IMessage value)
{
if (DiagnosticOnly)
{
@@ -587,23 +558,23 @@ namespace Google.Protobuf
throw new InvalidOperationException($"Type registry has no descriptor for type name '{typeName}'");
}
IMessage message = descriptor.Parser.ParseFrom(data);
WriteBracketOpen(writer, ObjectOpenBracket);
writer.Write("{ ");
WriteString(writer, AnyTypeUrlField);
writer.Write(NameValueSeparator);
WriteString(writer, typeUrl);
if (descriptor.IsWellKnownType)
{
writer.Write(ValueSeparator);
writer.Write(PropertySeparator);
WriteString(writer, AnyWellKnownTypeValueField);
writer.Write(NameValueSeparator);
WriteWellKnownTypeValue(writer, descriptor, message, indentationLevel);
WriteWellKnownTypeValue(writer, descriptor, message);
}
else
{
WriteMessageFields(writer, message, true, indentationLevel);
WriteMessageFields(writer, message, true);
}
WriteBracketClose(writer, ObjectCloseBracket, true, indentationLevel);
writer.Write(" }");
}
private void WriteDiagnosticOnlyAny(TextWriter writer, IMessage value)
@@ -614,7 +585,7 @@ namespace Google.Protobuf
WriteString(writer, AnyTypeUrlField);
writer.Write(NameValueSeparator);
WriteString(writer, typeUrl);
writer.Write(ValueSeparator);
writer.Write(PropertySeparator);
WriteString(writer, AnyDiagnosticValueField);
writer.Write(NameValueSeparator);
writer.Write('"');
@@ -623,9 +594,9 @@ namespace Google.Protobuf
writer.Write(" }");
}
private void WriteStruct(TextWriter writer, IMessage message, int indentationLevel)
private void WriteStruct(TextWriter writer, IMessage message)
{
WriteBracketOpen(writer, ObjectOpenBracket);
writer.Write("{ ");
IDictionary fields = (IDictionary) message.Descriptor.Fields[Struct.FieldsFieldNumber].Accessor.GetValue(message);
bool first = true;
foreach (DictionaryEntry entry in fields)
@@ -637,17 +608,19 @@ namespace Google.Protobuf
throw new InvalidOperationException("Struct fields cannot have an empty key or a null value.");
}
MaybeWriteValueSeparator(writer, first);
MaybeWriteValueWhitespace(writer, indentationLevel + 1);
if (!first)
{
writer.Write(PropertySeparator);
}
WriteString(writer, key);
writer.Write(NameValueSeparator);
WriteStructFieldValue(writer, value, indentationLevel + 1);
WriteStructFieldValue(writer, value);
first = false;
}
WriteBracketClose(writer, ObjectCloseBracket, !first, indentationLevel);
writer.Write(first ? "}" : " }");
}
private void WriteStructFieldValue(TextWriter writer, IMessage message, int indentationLevel)
private void WriteStructFieldValue(TextWriter writer, IMessage message)
{
var specifiedField = message.Descriptor.Oneofs[0].Accessor.GetCaseFieldDescriptor(message);
if (specifiedField == null)
@@ -668,7 +641,7 @@ namespace Google.Protobuf
case Value.ListValueFieldNumber:
// Structs and ListValues are nested messages, and already well-known types.
var nestedMessage = (IMessage) specifiedField.Accessor.GetValue(message);
WriteWellKnownTypeValue(writer, nestedMessage.Descriptor, nestedMessage, indentationLevel);
WriteWellKnownTypeValue(writer, nestedMessage.Descriptor, nestedMessage);
return;
case Value.NullValueFieldNumber:
WriteNull(writer);
@@ -678,40 +651,43 @@ namespace Google.Protobuf
}
}
internal void WriteList(TextWriter writer, IList list, int indentationLevel = 0)
internal void WriteList(TextWriter writer, IList list)
{
WriteBracketOpen(writer, ListBracketOpen);
writer.Write("[ ");
bool first = true;
foreach (var value in list)
{
MaybeWriteValueSeparator(writer, first);
MaybeWriteValueWhitespace(writer, indentationLevel + 1);
WriteValue(writer, value, indentationLevel + 1);
if (!first)
{
writer.Write(PropertySeparator);
}
WriteValue(writer, value);
first = false;
}
WriteBracketClose(writer, ListBracketClose, !first, indentationLevel);
writer.Write(first ? "]" : " ]");
}
internal void WriteDictionary(TextWriter writer, IDictionary dictionary, int indentationLevel = 0)
internal void WriteDictionary(TextWriter writer, IDictionary dictionary)
{
WriteBracketOpen(writer, ObjectOpenBracket);
writer.Write("{ ");
bool first = true;
// This will box each pair. Could use IDictionaryEnumerator, but that's ugly in terms of disposal.
foreach (DictionaryEntry pair in dictionary)
{
if (!first)
{
writer.Write(PropertySeparator);
}
string keyText;
if (pair.Key is string s)
if (pair.Key is string)
{
keyText = s;
keyText = (string) pair.Key;
}
else if (pair.Key is bool b)
else if (pair.Key is bool)
{
keyText = b ? "true" : "false";
keyText = (bool) pair.Key ? "true" : "false";
}
else if (pair.Key is int || pair.Key is uint || pair.Key is long || pair.Key is ulong)
else if (pair.Key is int || pair.Key is uint | pair.Key is long || pair.Key is ulong)
{
keyText = ((IFormattable) pair.Key).ToString("d", CultureInfo.InvariantCulture);
}
@@ -723,16 +699,12 @@ namespace Google.Protobuf
}
throw new ArgumentException("Unhandled dictionary key type: " + pair.Key.GetType());
}
MaybeWriteValueSeparator(writer, first);
MaybeWriteValueWhitespace(writer, indentationLevel + 1);
WriteString(writer, keyText);
writer.Write(NameValueSeparator);
WriteValue(writer, pair.Value);
first = false;
}
WriteBracketClose(writer, ObjectCloseBracket, !first, indentationLevel);
writer.Write(first ? "}" : " }");
}
/// <summary>
@@ -816,49 +788,6 @@ namespace Google.Protobuf
writer.Write(Hex[(c >> 0) & 0xf]);
}
private void WriteBracketOpen(TextWriter writer, char openChar)
{
writer.Write(openChar);
if (settings.Indentation == null)
{
writer.Write(' ');
}
}
private void WriteBracketClose(TextWriter writer, char closeChar, bool hasFields, int indentationLevel)
{
if (hasFields)
{
if (settings.Indentation != null)
{
writer.WriteLine();
WriteIndentation(writer, indentationLevel);
}
else
{
writer.Write(" ");
}
}
writer.Write(closeChar);
}
private void MaybeWriteValueWhitespace(TextWriter writer, int indentationLevel)
{
if (settings.Indentation != null) {
writer.WriteLine();
WriteIndentation(writer, indentationLevel);
}
}
private void WriteIndentation(TextWriter writer, int indentationLevel)
{
for (int i = 0; i < indentationLevel; i++)
{
writer.Write(settings.Indentation);
}
}
/// <summary>
/// Settings controlling JSON formatting.
/// </summary>
@@ -899,10 +828,6 @@ namespace Google.Protobuf
/// </summary>
public bool PreserveProtoFieldNames { get; }
/// <summary>
/// Indentation string, used for formatting. Setting null disables indentation.
/// </summary>
public string Indentation { get; }
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified formatting of default values
@@ -930,54 +855,40 @@ namespace Google.Protobuf
/// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages. TypeRegistry.Empty will be used if it is null.</param>
/// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param>
/// <param name="preserveProtoFieldNames"><c>true</c> to preserve proto field names; <c>false</c> to convert them to lowerCamelCase.</param>
/// <param name="indentation">The indentation string to use for multi-line formatting. <c>null</c> to disable multi-line format.</param>
private Settings(bool formatDefaultValues,
TypeRegistry typeRegistry,
bool formatEnumsAsIntegers,
bool preserveProtoFieldNames,
string indentation = null)
bool preserveProtoFieldNames)
{
FormatDefaultValues = formatDefaultValues;
TypeRegistry = typeRegistry ?? TypeRegistry.Empty;
FormatEnumsAsIntegers = formatEnumsAsIntegers;
PreserveProtoFieldNames = preserveProtoFieldNames;
Indentation = indentation;
}
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified formatting of default values and the current settings.
/// </summary>
/// <param name="formatDefaultValues"><c>true</c> if default values (0, empty strings etc) should be formatted; <c>false</c> otherwise.</param>
public Settings WithFormatDefaultValues(bool formatDefaultValues) => new Settings(formatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
public Settings WithFormatDefaultValues(bool formatDefaultValues) => new Settings(formatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames);
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified type registry and the current settings.
/// </summary>
/// <param name="typeRegistry">The <see cref="TypeRegistry"/> to use when formatting <see cref="Any"/> messages.</param>
public Settings WithTypeRegistry(TypeRegistry typeRegistry) => new Settings(FormatDefaultValues, typeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
public Settings WithTypeRegistry(TypeRegistry typeRegistry) => new Settings(FormatDefaultValues, typeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames);
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified enums formatting option and the current settings.
/// </summary>
/// <param name="formatEnumsAsIntegers"><c>true</c> to format the enums as integers; <c>false</c> to format enums as enum names.</param>
public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers) => new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers, PreserveProtoFieldNames, Indentation);
public Settings WithFormatEnumsAsIntegers(bool formatEnumsAsIntegers) => new Settings(FormatDefaultValues, TypeRegistry, formatEnumsAsIntegers, PreserveProtoFieldNames);
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified field name formatting option and the current settings.
/// </summary>
/// <param name="preserveProtoFieldNames"><c>true</c> to preserve proto field names; <c>false</c> to convert them to lowerCamelCase.</param>
public Settings WithPreserveProtoFieldNames(bool preserveProtoFieldNames) => new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, preserveProtoFieldNames, Indentation);
/// <summary>
/// Creates a new <see cref="Settings"/> object with the specified indentation and the current settings.
/// </summary>
/// <param name="indentation">The string to output for each level of indentation (nesting). The default is two spaces per level. Use null to disable indentation entirely.</param>
/// <remarks>A non-null value for <see cref="Indentation"/> will insert additional line-breaks to the JSON output.
/// Each line will contain either a single value, or braces. The default line-break is determined by <see cref="Environment.NewLine"/>,
/// which is <c>"\n"</c> on Unix platforms, and <c>"\r\n"</c> on Windows. If <see cref="JsonFormatter"/> seems to produce empty lines,
/// you need to pass a <see cref="TextWriter"/> that uses a <c>"\n"</c> newline. See <see cref="JsonFormatter.Format(Google.Protobuf.IMessage, TextWriter)"/>.
/// </remarks>
public Settings WithIndentation(string indentation = " ") => new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, PreserveProtoFieldNames, indentation);
public Settings WithPreserveProtoFieldNames(bool preserveProtoFieldNames) => new Settings(FormatDefaultValues, TypeRegistry, FormatEnumsAsIntegers, preserveProtoFieldNames);
}
// Effectively a cache of mapping from enum values to the original name as specified in the proto file,
@@ -1005,8 +916,9 @@ namespace Google.Protobuf
}
}
string originalName;
// If this returns false, originalName will be null, which is what we want.
nameMapping.TryGetValue(value, out string originalName);
nameMapping.TryGetValue(value, out originalName);
return originalName;
}

View File

@@ -70,7 +70,8 @@ namespace Google.Protobuf
// TODO: Consider introducing a class containing parse state of the parser, tokenizer and depth. That would simplify these handlers
// and the signatures of various methods.
private static readonly Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>> WellKnownTypeHandlers = new()
private static readonly Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
WellKnownTypeHandlers = new Dictionary<string, Action<JsonParser, IMessage, JsonTokenizer>>
{
{ Timestamp.Descriptor.FullName, (parser, message, tokenizer) => MergeTimestamp(message, tokenizer.Next()) },
{ Duration.Descriptor.FullName, (parser, message, tokenizer) => MergeDuration(message, tokenizer.Next()) },
@@ -155,7 +156,8 @@ namespace Google.Protobuf
}
if (message.Descriptor.IsWellKnownType)
{
if (WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, out Action<JsonParser, IMessage, JsonTokenizer> handler))
Action<JsonParser, IMessage, JsonTokenizer> handler;
if (WellKnownTypeHandlers.TryGetValue(message.Descriptor.FullName, out handler))
{
handler(this, message, tokenizer);
return;
@@ -185,7 +187,8 @@ namespace Google.Protobuf
throw new InvalidOperationException("Unexpected token type " + token.Type);
}
string name = token.StringValue;
if (jsonFieldMap.TryGetValue(name, out FieldDescriptor field))
FieldDescriptor field;
if (jsonFieldMap.TryGetValue(name, out field))
{
if (field.ContainingOneof != null)
{
@@ -300,7 +303,11 @@ namespace Google.Protobuf
}
object key = ParseMapKey(keyField, token.StringValue);
object value = ParseSingleValue(valueField, tokenizer);
dictionary[key] = value ?? throw new InvalidProtocolBufferException("Map values must not be null");
if (value == null)
{
throw new InvalidProtocolBufferException("Map values must not be null");
}
dictionary[key] = value;
}
}
@@ -642,15 +649,19 @@ namespace Google.Protobuf
{
return float.NaN;
}
float converted = (float) value;
// If the value is out of range of float, the cast representation will be infinite.
// If the original value was infinite as well, that's fine - we'll return the 32-bit
// version (with the correct sign).
if (float.IsInfinity(converted) && !double.IsInfinity(value))
if (value > float.MaxValue || value < float.MinValue)
{
if (double.IsPositiveInfinity(value))
{
return float.PositiveInfinity;
}
if (double.IsNegativeInfinity(value))
{
return float.NegativeInfinity;
}
throw new InvalidProtocolBufferException($"Value out of range: {value}");
}
return converted;
return (float) value;
case FieldType.Enum:
CheckInteger(value);
// Just return it as an int, and let the CLR convert it.
@@ -842,7 +853,7 @@ namespace Google.Protobuf
if (secondsToAdd < 0 && nanosToAdd > 0)
{
secondsToAdd++;
nanosToAdd -= Duration.NanosecondsPerSecond;
nanosToAdd = nanosToAdd - Duration.NanosecondsPerSecond;
}
if (secondsToAdd != 0 || nanosToAdd != 0)
{
@@ -1038,20 +1049,23 @@ namespace Google.Protobuf
/// when unknown fields are encountered.
/// </summary>
/// <param name="ignoreUnknownFields"><c>true</c> if unknown fields should be ignored when parsing; <c>false</c> to throw an exception.</param>
public Settings WithIgnoreUnknownFields(bool ignoreUnknownFields) => new(RecursionLimit, TypeRegistry, ignoreUnknownFields);
public Settings WithIgnoreUnknownFields(bool ignoreUnknownFields) =>
new Settings(RecursionLimit, TypeRegistry, ignoreUnknownFields);
/// <summary>
/// Creates a new <see cref="Settings"/> object based on this one, but with the specified recursion limit.
/// </summary>
/// <param name="recursionLimit">The new recursion limit.</param>
public Settings WithRecursionLimit(int recursionLimit) => new(recursionLimit, TypeRegistry, IgnoreUnknownFields);
public Settings WithRecursionLimit(int recursionLimit) =>
new Settings(recursionLimit, TypeRegistry, IgnoreUnknownFields);
/// <summary>
/// Creates a new <see cref="Settings"/> object based on this one, but with the specified type registry.
/// </summary>
/// <param name="typeRegistry">The new type registry. Must not be null.</param>
public Settings WithTypeRegistry(TypeRegistry typeRegistry) =>
new(RecursionLimit,
new Settings(
RecursionLimit,
ProtoPreconditions.CheckNotNull(typeRegistry, nameof(typeRegistry)),
IgnoreUnknownFields);
}

View File

@@ -36,14 +36,24 @@ namespace Google.Protobuf
{
internal sealed class JsonToken : IEquatable<JsonToken>
{
internal static JsonToken Null { get; } = new JsonToken(TokenType.Null);
internal static JsonToken False { get; } = new JsonToken(TokenType.False);
internal static JsonToken True { get; } = new JsonToken(TokenType.True);
internal static JsonToken StartObject { get; } = new JsonToken(TokenType.StartObject);
internal static JsonToken EndObject { get; } = new JsonToken(TokenType.EndObject);
internal static JsonToken StartArray { get; } = new JsonToken(TokenType.StartArray);
internal static JsonToken EndArray { get; } = new JsonToken(TokenType.EndArray);
internal static JsonToken EndDocument { get; } = new JsonToken(TokenType.EndDocument);
// Tokens with no value can be reused.
private static readonly JsonToken _true = new JsonToken(TokenType.True);
private static readonly JsonToken _false = new JsonToken(TokenType.False);
private static readonly JsonToken _null = new JsonToken(TokenType.Null);
private static readonly JsonToken startObject = new JsonToken(TokenType.StartObject);
private static readonly JsonToken endObject = new JsonToken(TokenType.EndObject);
private static readonly JsonToken startArray = new JsonToken(TokenType.StartArray);
private static readonly JsonToken endArray = new JsonToken(TokenType.EndArray);
private static readonly JsonToken endDocument = new JsonToken(TokenType.EndDocument);
internal static JsonToken Null { get { return _null; } }
internal static JsonToken False { get { return _false; } }
internal static JsonToken True { get { return _true; } }
internal static JsonToken StartObject{ get { return startObject; } }
internal static JsonToken EndObject { get { return endObject; } }
internal static JsonToken StartArray { get { return startArray; } }
internal static JsonToken EndArray { get { return endArray; } }
internal static JsonToken EndDocument { get { return endDocument; } }
internal static JsonToken Name(string name)
{
@@ -84,9 +94,9 @@ namespace Google.Protobuf
private readonly string stringValue;
private readonly double numberValue;
internal TokenType Type => type;
internal string StringValue => stringValue;
internal double NumberValue => numberValue;
internal TokenType Type { get { return type; } }
internal string StringValue { get { return stringValue; } }
internal double NumberValue { get { return numberValue; } }
private JsonToken(TokenType type, string stringValue = null, double numberValue = 0)
{
@@ -95,7 +105,10 @@ namespace Google.Protobuf
this.numberValue = numberValue;
}
public override bool Equals(object obj) => Equals(obj as JsonToken);
public override bool Equals(object obj)
{
return Equals(obj as JsonToken);
}
public override int GetHashCode()
{
@@ -111,26 +124,38 @@ namespace Google.Protobuf
public override string ToString()
{
return type switch
switch (type)
{
TokenType.Null => "null",
TokenType.True => "true",
TokenType.False => "false",
TokenType.Name => $"name ({stringValue})",
TokenType.StringValue => $"value ({stringValue})",
TokenType.Number => $"number ({numberValue})",
TokenType.StartObject => "start-object",
TokenType.EndObject => "end-object",
TokenType.StartArray => "start-array",
TokenType.EndArray => "end-array",
TokenType.EndDocument => "end-document",
_ => throw new InvalidOperationException($"Token is of unknown type {type}"),
};
case TokenType.Null:
return "null";
case TokenType.True:
return "true";
case TokenType.False:
return "false";
case TokenType.Name:
return "name (" + stringValue + ")";
case TokenType.StringValue:
return "value (" + stringValue + ")";
case TokenType.Number:
return "number (" + numberValue + ")";
case TokenType.StartObject:
return "start-object";
case TokenType.EndObject:
return "end-object";
case TokenType.StartArray:
return "start-array";
case TokenType.EndArray:
return "end-array";
case TokenType.EndDocument:
return "end-document";
default:
throw new InvalidOperationException("Token is of unknown type " + type);
}
}
public bool Equals(JsonToken other)
{
if (other is null)
if (ReferenceEquals(other, null))
{
return false;
}

View File

@@ -29,7 +29,6 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -363,19 +362,29 @@ namespace Google.Protobuf
private char ReadEscapedCharacter()
{
char c = reader.ReadOrFail("Unexpected end of text while reading character escape sequence");
return c switch
switch (c)
{
'n' => '\n',
'\\' => '\\',
'b' => '\b',
'f' => '\f',
'r' => '\r',
't' => '\t',
'"' => '"',
'/' => '/',
'u' => ReadUnicodeEscape(),
_ => throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int)c)),
};
case 'n':
return '\n';
case '\\':
return '\\';
case 'b':
return '\b';
case 'f':
return '\f';
case 'r':
return '\r';
case 't':
return '\t';
case '"':
return '"';
case '/':
return '/';
case 'u':
return ReadUnicodeEscape();
default:
throw reader.CreateException(string.Format(CultureInfo.InvariantCulture, "Invalid character in character escape sequence: U+{0:x4}", (int) c));
}
}
/// <summary>
@@ -489,7 +498,8 @@ namespace Google.Protobuf
throw reader.CreateException("Invalid numeric literal");
}
builder.Append(first);
char? next = ConsumeDigits(builder, out int digitCount);
int digitCount;
char? next = ConsumeDigits(builder, out digitCount);
if (first == '0' && digitCount != 0)
{
throw reader.CreateException("Invalid numeric literal: leading 0 for non-zero value.");
@@ -500,7 +510,8 @@ namespace Google.Protobuf
private char? ReadFrac(StringBuilder builder)
{
builder.Append('.'); // Already consumed this
char? next = ConsumeDigits(builder, out int digitCount);
int digitCount;
char? next = ConsumeDigits(builder, out digitCount);
if (digitCount == 0)
{
throw reader.CreateException("Invalid numeric literal: fraction with no trailing digits");
@@ -524,7 +535,8 @@ namespace Google.Protobuf
{
reader.PushBack(next.Value);
}
next = ConsumeDigits(builder, out int digitCount);
int digitCount;
next = ConsumeDigits(builder, out digitCount);
if (digitCount == 0)
{
throw reader.CreateException("Invalid numeric literal: exponent without value");
@@ -579,13 +591,20 @@ namespace Google.Protobuf
{
containerStack.Pop();
var parent = containerStack.Peek();
state = parent switch
switch (parent)
{
ContainerType.Object => State.ObjectAfterProperty,
ContainerType.Array => State.ArrayAfterValue,
ContainerType.Document => State.ExpectedEndOfDocument,
_ => throw new InvalidOperationException("Unexpected container type: " + parent),
};
case ContainerType.Object:
state = State.ObjectAfterProperty;
break;
case ContainerType.Array:
state = State.ArrayAfterValue;
break;
case ContainerType.Document:
state = State.ExpectedEndOfDocument;
break;
default:
throw new InvalidOperationException("Unexpected container type: " + parent);
}
}
private enum ContainerType

View File

@@ -51,20 +51,34 @@ namespace Google.Protobuf
bytesLeft = size;
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return false; }
}
public override void Flush()
{
}
public override long Length => throw new NotSupportedException();
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get => throw new NotSupportedException();
set => throw new NotSupportedException();
get { throw new NotSupportedException(); }
set { throw new NotSupportedException(); }
}
public override int Read(byte[] buffer, int offset, int count)
@@ -78,10 +92,19 @@ namespace Google.Protobuf
return 0;
}
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value) => throw new NotSupportedException();
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
public override void Write(byte[] buffer, int offset, int count)
{
throw new NotSupportedException();
}
}
}

View File

@@ -107,7 +107,7 @@ namespace Google.Protobuf
/// <returns>The message data as a byte array.</returns>
public static byte[] ToByteArray(this IMessage message)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(message, "message");
byte[] result = new byte[message.CalculateSize()];
CodedOutputStream output = new CodedOutputStream(result);
message.WriteTo(output);
@@ -122,8 +122,8 @@ namespace Google.Protobuf
/// <param name="output">The stream to write to.</param>
public static void WriteTo(this IMessage message, Stream output)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(output, nameof(output));
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(output, "output");
CodedOutputStream codedOutput = new CodedOutputStream(output);
message.WriteTo(codedOutput);
codedOutput.Flush();
@@ -136,8 +136,8 @@ namespace Google.Protobuf
/// <param name="output">The output stream to write to.</param>
public static void WriteDelimitedTo(this IMessage message, Stream output)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(output, nameof(output));
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(output, "output");
CodedOutputStream codedOutput = new CodedOutputStream(output);
codedOutput.WriteLength(message.CalculateSize());
message.WriteTo(codedOutput);
@@ -151,7 +151,7 @@ namespace Google.Protobuf
/// <returns>The message data as a byte string.</returns>
public static ByteString ToByteString(this IMessage message)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(message, "message");
return ByteString.AttachBytes(message.ToByteArray());
}
@@ -251,34 +251,30 @@ namespace Google.Protobuf
// Implementations allowing unknown fields to be discarded.
internal static void MergeFrom(this IMessage message, byte[] data, bool discardUnknownFields, ExtensionRegistry registry)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(data, nameof(data));
CodedInputStream input = new CodedInputStream(data)
{
DiscardUnknownFields = discardUnknownFields,
ExtensionRegistry = registry
};
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(data, "data");
CodedInputStream input = new CodedInputStream(data);
input.DiscardUnknownFields = discardUnknownFields;
input.ExtensionRegistry = registry;
message.MergeFrom(input);
input.CheckReadEndOfStreamTag();
}
internal static void MergeFrom(this IMessage message, byte[] data, int offset, int length, bool discardUnknownFields, ExtensionRegistry registry)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(data, nameof(data));
CodedInputStream input = new CodedInputStream(data, offset, length)
{
DiscardUnknownFields = discardUnknownFields,
ExtensionRegistry = registry
};
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(data, "data");
CodedInputStream input = new CodedInputStream(data, offset, length);
input.DiscardUnknownFields = discardUnknownFields;
input.ExtensionRegistry = registry;
message.MergeFrom(input);
input.CheckReadEndOfStreamTag();
}
internal static void MergeFrom(this IMessage message, ByteString data, bool discardUnknownFields, ExtensionRegistry registry)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(data, nameof(data));
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(data, "data");
CodedInputStream input = data.CreateCodedInput();
input.DiscardUnknownFields = discardUnknownFields;
input.ExtensionRegistry = registry;
@@ -288,13 +284,11 @@ namespace Google.Protobuf
internal static void MergeFrom(this IMessage message, Stream input, bool discardUnknownFields, ExtensionRegistry registry)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(input, nameof(input));
CodedInputStream codedInput = new CodedInputStream(input)
{
DiscardUnknownFields = discardUnknownFields,
ExtensionRegistry = registry
};
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(input, "input");
CodedInputStream codedInput = new CodedInputStream(input);
codedInput.DiscardUnknownFields = discardUnknownFields;
codedInput.ExtensionRegistry = registry;
message.MergeFrom(codedInput);
codedInput.CheckReadEndOfStreamTag();
}
@@ -321,8 +315,8 @@ namespace Google.Protobuf
internal static void MergeDelimitedFrom(this IMessage message, Stream input, bool discardUnknownFields, ExtensionRegistry registry)
{
ProtoPreconditions.CheckNotNull(message, nameof(message));
ProtoPreconditions.CheckNotNull(input, nameof(input));
ProtoPreconditions.CheckNotNull(message, "message");
ProtoPreconditions.CheckNotNull(input, "input");
int size = (int) CodedInputStream.ReadRawVarint32(input);
Stream limitedStream = new LimitedInputStream(input, size);
MergeFrom(message, limitedStream, discardUnknownFields, registry);

View File

@@ -43,8 +43,9 @@ namespace Google.Protobuf
/// </summary>
public class MessageParser
{
private readonly Func<IMessage> factory;
private protected bool DiscardUnknownFields { get; }
private Func<IMessage> factory;
// TODO: When we use a C# 7.1 compiler, make this private protected.
internal bool DiscardUnknownFields { get; }
internal ExtensionRegistry Extensions { get; }
@@ -171,10 +172,6 @@ namespace Google.Protobuf
/// <summary>
/// Parses a message from the given JSON.
/// </summary>
/// <remarks>This method always uses the default JSON parser; it is not affected by <see cref="WithDiscardUnknownFields(bool)"/>.
/// To ignore unknown fields when parsing JSON, create a <see cref="JsonParser"/> using a <see cref="JsonParser.Settings"/>
/// with <see cref="JsonParser.Settings.IgnoreUnknownFields"/> set to true and call <see cref="JsonParser.Parse{T}(string)"/> directly.
/// </remarks>
/// <param name="json">The JSON to parse.</param>
/// <returns>The parsed message.</returns>
/// <exception cref="InvalidJsonException">The JSON does not comply with RFC 7159</exception>
@@ -207,9 +204,6 @@ namespace Google.Protobuf
/// <summary>
/// Creates a new message parser which optionally discards unknown fields when parsing.
/// </summary>
/// <remarks>Note that this does not affect the behavior of <see cref="ParseJson(string)"/>
/// at all. To ignore unknown fields when parsing JSON, create a <see cref="JsonParser"/> using a <see cref="JsonParser.Settings"/>
/// with <see cref="JsonParser.Settings.IgnoreUnknownFields"/> set to true and call <see cref="JsonParser.Parse{T}(string)"/> directly.</remarks>
/// <param name="discardUnknownFields">Whether or not to discard unknown fields when parsing.</param>
/// <returns>A newly configured message parser.</returns>
public MessageParser WithDiscardUnknownFields(bool discardUnknownFields) =>

View File

@@ -23,7 +23,14 @@ namespace Google.Protobuf
&& number == other.number;
}
public override bool Equals(object obj) => obj is ObjectIntPair<T> pair && Equals(pair);
public override bool Equals(object obj)
{
if (obj is ObjectIntPair<T>)
{
return Equals((ObjectIntPair<T>)obj);
}
return false;
}
public override int GetHashCode()
{

View File

@@ -32,8 +32,14 @@
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Google.Protobuf.Collections;
namespace Google.Protobuf
{
@@ -47,7 +53,7 @@ namespace Google.Protobuf
public ref struct ParseContext
{
internal const int DefaultRecursionLimit = 100;
internal const int DefaultSizeLimit = int.MaxValue;
internal const int DefaultSizeLimit = Int32.MaxValue;
internal ReadOnlySpan<byte> buffer;
internal ParserInternalState state;
@@ -121,15 +127,14 @@ namespace Google.Protobuf
/// Returns the last tag read, or 0 if no tags have been read or we've read beyond
/// the end of the input.
/// </summary>
internal uint LastTag => state.lastTag;
internal uint LastTag { get { return state.lastTag; } }
/// <summary>
/// Internal-only property; when set to true, unknown fields will be discarded while parsing.
/// </summary>
internal bool DiscardUnknownFields
{
get => state.DiscardUnknownFields;
set => state.DiscardUnknownFields = value;
internal bool DiscardUnknownFields {
get { return state.DiscardUnknownFields; }
set { state.DiscardUnknownFields = value; }
}
/// <summary>
@@ -137,8 +142,8 @@ namespace Google.Protobuf
/// </summary>
internal ExtensionRegistry ExtensionRegistry
{
get => state.ExtensionRegistry;
set => state.ExtensionRegistry = value;
get { return state.ExtensionRegistry; }
set { state.ExtensionRegistry = value; }
}
/// <summary>
@@ -151,85 +156,125 @@ namespace Google.Protobuf
/// </remarks>
/// <returns>The next field tag, or 0 for end of input. (0 is never a valid tag.)</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint ReadTag() => ParsingPrimitives.ParseTag(ref buffer, ref state);
public uint ReadTag()
{
return ParsingPrimitives.ParseTag(ref buffer, ref state);
}
/// <summary>
/// Reads a double field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public double ReadDouble() => ParsingPrimitives.ParseDouble(ref buffer, ref state);
public double ReadDouble()
{
return ParsingPrimitives.ParseDouble(ref buffer, ref state);
}
/// <summary>
/// Reads a float field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float ReadFloat() => ParsingPrimitives.ParseFloat(ref buffer, ref state);
public float ReadFloat()
{
return ParsingPrimitives.ParseFloat(ref buffer, ref state);
}
/// <summary>
/// Reads a uint64 field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong ReadUInt64() => ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
public ulong ReadUInt64()
{
return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
}
/// <summary>
/// Reads an int64 field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public long ReadInt64() => (long)ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
public long ReadInt64()
{
return (long)ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
}
/// <summary>
/// Reads an int32 field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadInt32() => (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
public int ReadInt32()
{
return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
}
/// <summary>
/// Reads a fixed64 field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ulong ReadFixed64() => ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state);
public ulong ReadFixed64()
{
return ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state);
}
/// <summary>
/// Reads a fixed32 field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint ReadFixed32() => ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state);
public uint ReadFixed32()
{
return ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state);
}
/// <summary>
/// Reads a bool field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool ReadBool() => ParsingPrimitives.ParseRawVarint64(ref buffer, ref state) != 0;
public bool ReadBool()
{
return ParsingPrimitives.ParseRawVarint64(ref buffer, ref state) != 0;
}
/// <summary>
/// Reads a string field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ReadString() => ParsingPrimitives.ReadString(ref buffer, ref state);
public string ReadString()
{
return ParsingPrimitives.ReadString(ref buffer, ref state);
}
/// <summary>
/// Reads an embedded message field value from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadMessage(IMessage message) => ParsingPrimitivesMessages.ReadMessage(ref this, message);
public void ReadMessage(IMessage message)
{
ParsingPrimitivesMessages.ReadMessage(ref this, message);
}
/// <summary>
/// Reads an embedded group field from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadGroup(IMessage message) => ParsingPrimitivesMessages.ReadGroup(ref this, message);
public void ReadGroup(IMessage message)
{
ParsingPrimitivesMessages.ReadGroup(ref this, message);
}
/// <summary>
/// Reads a bytes field value from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ByteString ReadBytes() => ParsingPrimitives.ReadBytes(ref buffer, ref state);
public ByteString ReadBytes()
{
return ParsingPrimitives.ReadBytes(ref buffer, ref state);
}
/// <summary>
/// Reads a uint32 field value from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint ReadUInt32() => ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
public uint ReadUInt32()
{
return ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
}
/// <summary>
/// Reads an enum field value from the input.
@@ -245,25 +290,37 @@ namespace Google.Protobuf
/// Reads an sfixed32 field value from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadSFixed32() => (int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state);
public int ReadSFixed32()
{
return (int)ParsingPrimitives.ParseRawLittleEndian32(ref buffer, ref state);
}
/// <summary>
/// Reads an sfixed64 field value from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public long ReadSFixed64() => (long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state);
public long ReadSFixed64()
{
return (long)ParsingPrimitives.ParseRawLittleEndian64(ref buffer, ref state);
}
/// <summary>
/// Reads an sint32 field value from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadSInt32() => ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state));
public int ReadSInt32()
{
return ParsingPrimitives.DecodeZigZag32(ParsingPrimitives.ParseRawVarint32(ref buffer, ref state));
}
/// <summary>
/// Reads an sint64 field value from the input.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public long ReadSInt64() => ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state));
public long ReadSInt64()
{
return ParsingPrimitives.DecodeZigZag64(ParsingPrimitives.ParseRawVarint64(ref buffer, ref state));
}
/// <summary>
/// Reads a length for length-delimited data.
@@ -273,7 +330,10 @@ namespace Google.Protobuf
/// to make the calling code clearer.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int ReadLength() => (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
public int ReadLength()
{
return (int)ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
}
internal void CopyStateTo(CodedInputStream input)
{

View File

@@ -30,8 +30,20 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Google.Protobuf.Collections;
namespace Google.Protobuf
{
// warning: this is a mutable struct, so it needs to be only passed as a ref!
internal struct ParserInternalState
{

View File

@@ -34,10 +34,13 @@ using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Google.Protobuf.Collections;
namespace Google.Protobuf
{

View File

@@ -33,6 +33,8 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security;
using Google.Protobuf.Collections;

View File

@@ -31,7 +31,15 @@
#endregion
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using Google.Protobuf.Collections;
namespace Google.Protobuf
{

View File

@@ -47,3 +47,10 @@ using System.Security;
"981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" +
"b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" +
"c5ae9cb6")]
[assembly: InternalsVisibleTo("Google.Protobuf.Benchmarks, PublicKey=" +
"002400000480000094000000060200000024000052534131000400000100010025800fbcfc63a1" +
"7c66b303aae80b03a6beaa176bb6bef883be436f2a1579edd80ce23edf151a1f4ced97af83abcd" +
"981207041fd5b2da3b498346fcfcd94910d52f25537c4a43ce3fbe17dc7d43e6cbdb4d8f1242dc" +
"b6bd9b5906be74da8daa7d7280f97130f318a16c07baf118839b156299a48522f9fae2371c9665" +
"c5ae9cb6")]

View File

@@ -31,6 +31,7 @@
#endregion
using Google.Protobuf.Collections;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
@@ -225,21 +226,24 @@ namespace Google.Protobuf.Reflection
{
if (values == null)
{
value = default;
value = default(T);
return false;
}
if (values.TryGetValue(field, out IExtensionValue extensionValue))
IExtensionValue extensionValue;
if (values.TryGetValue(field, out extensionValue))
{
if (extensionValue is ExtensionValue<T> single)
if (extensionValue is ExtensionValue<T>)
{
ExtensionValue<T> single = extensionValue as ExtensionValue<T>;
ByteString bytes = single.GetValue().ToByteString();
value = new T();
value.MergeFrom(bytes);
return true;
}
else if (extensionValue is RepeatedExtensionValue<T> repeated)
else if (extensionValue is RepeatedExtensionValue<T>)
{
RepeatedExtensionValue<T> repeated = extensionValue as RepeatedExtensionValue<T>;
value = repeated.GetValue()
.Select(v => v.ToByteString())
.Aggregate(new T(), (t, b) =>
@@ -260,19 +264,22 @@ namespace Google.Protobuf.Reflection
{
if (values == null)
{
value = default;
value = default(T);
return false;
}
if (values.TryGetValue(field, out IExtensionValue extensionValue))
IExtensionValue extensionValue;
if (values.TryGetValue(field, out extensionValue))
{
if (extensionValue is ExtensionValue<T> single)
if (extensionValue is ExtensionValue<T>)
{
ExtensionValue<T> single = extensionValue as ExtensionValue<T>;
value = single.GetValue();
return true;
}
else if (extensionValue is RepeatedExtensionValue<T> repeated)
else if (extensionValue is RepeatedExtensionValue<T>)
{
RepeatedExtensionValue<T> repeated = extensionValue as RepeatedExtensionValue<T>;
if (repeated.GetValue().Count != 0)
{
RepeatedField<T> repeatedField = repeated.GetValue();
@@ -310,7 +317,7 @@ namespace Google.Protobuf.Reflection
}
}
value = default;
value = default(T);
return false;
}
}

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