commit
0f442a7533
24 changed files with 3521 additions and 134 deletions
4
BUILD
4
BUILD
|
@ -162,10 +162,10 @@ cc_library(
|
|||
"src/google/protobuf/compiler/cpp/cpp_string_field.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_enum.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_enum_field.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_extension.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_field_base.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_generator.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_helpers.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_map_field.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_message.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_message_field.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_primitive_field.cc",
|
||||
|
@ -174,7 +174,7 @@ cc_library(
|
|||
"src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_writer.cc",
|
||||
"src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc",
|
||||
"src/google/protobuf/compiler/java/java_context.cc",
|
||||
"src/google/protobuf/compiler/java/java_doc_comment.cc",
|
||||
"src/google/protobuf/compiler/java/java_enum.cc",
|
||||
|
|
|
@ -28,6 +28,7 @@ set(libprotoc_files
|
|||
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_umbrella_class.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_context.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_doc_comment.cc
|
||||
${protobuf_source_dir}/src/google/protobuf/compiler/java/java_enum.cc
|
||||
|
|
|
@ -58,7 +58,8 @@ $PROTOC -Isrc --csharp_out=csharp/src/ProtocolBuffers.Test/TestProtos \
|
|||
src/google/protobuf/map_unittest_proto3.proto \
|
||||
src/google/protobuf/unittest_proto3.proto \
|
||||
src/google/protobuf/unittest_import_proto3.proto \
|
||||
src/google/protobuf/unittest_import_public_proto3.proto
|
||||
src/google/protobuf/unittest_import_public_proto3.proto \
|
||||
src/google/protobuf/unittest_well_known_types.proto
|
||||
|
||||
|
||||
$PROTOC -Icsharp/protos/extest --csharp_out=csharp/src/ProtocolBuffers.Test/TestProtos \
|
||||
|
|
|
@ -38,6 +38,34 @@ namespace Google.Protobuf
|
|||
{
|
||||
public class ByteStringTest
|
||||
{
|
||||
[Test]
|
||||
public void Equality()
|
||||
{
|
||||
ByteString b1 = ByteString.CopyFrom(1, 2, 3);
|
||||
ByteString b2 = ByteString.CopyFrom(1, 2, 3);
|
||||
ByteString b3 = ByteString.CopyFrom(1, 2, 4);
|
||||
ByteString b4 = ByteString.CopyFrom(1, 2, 3, 4);
|
||||
EqualityTester.AssertEquality(b1, b1);
|
||||
EqualityTester.AssertEquality(b1, b2);
|
||||
EqualityTester.AssertInequality(b1, b3);
|
||||
EqualityTester.AssertInequality(b1, b4);
|
||||
EqualityTester.AssertInequality(b1, null);
|
||||
#pragma warning disable 1718 // Deliberately calling ==(b1, b1) and !=(b1, b1)
|
||||
Assert.IsTrue(b1 == b1);
|
||||
Assert.IsTrue(b1 == b2);
|
||||
Assert.IsFalse(b1 == b3);
|
||||
Assert.IsFalse(b1 == b4);
|
||||
Assert.IsFalse(b1 == null);
|
||||
Assert.IsTrue((ByteString) null == null);
|
||||
Assert.IsFalse(b1 != b1);
|
||||
Assert.IsFalse(b1 != b2);
|
||||
#pragma warning disable 1718
|
||||
Assert.IsTrue(b1 != b3);
|
||||
Assert.IsTrue(b1 != b4);
|
||||
Assert.IsTrue(b1 != null);
|
||||
Assert.IsFalse((ByteString) null != null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EmptyByteStringHasZeroSize()
|
||||
{
|
||||
|
|
|
@ -102,6 +102,31 @@ namespace Google.Protobuf.Collections
|
|||
Assert.AreEqual(20, clone["x"].C);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NullValues()
|
||||
{
|
||||
TestNullValues<int?>(0);
|
||||
TestNullValues("");
|
||||
TestNullValues(new TestAllTypes());
|
||||
}
|
||||
|
||||
private void TestNullValues<T>(T nonNullValue)
|
||||
{
|
||||
var map = new MapField<int, T>(false);
|
||||
var nullValue = (T) (object) null;
|
||||
Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));
|
||||
Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);
|
||||
map.Add(1, nonNullValue);
|
||||
map[1] = nonNullValue;
|
||||
|
||||
// Doesn't throw...
|
||||
map = new MapField<int, T>(true);
|
||||
map.Add(0, nullValue);
|
||||
map[0] = nullValue;
|
||||
map.Add(1, nonNullValue);
|
||||
map[1] = nonNullValue;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_ForbidsNullKeys()
|
||||
{
|
||||
|
@ -109,57 +134,13 @@ namespace Google.Protobuf.Collections
|
|||
Assert.Throws<ArgumentNullException>(() => map.Add(null, new ForeignMessage()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_AcceptsNullMessageValues()
|
||||
{
|
||||
var map = new MapField<string, ForeignMessage>();
|
||||
map.Add("missing", null);
|
||||
Assert.IsNull(map["missing"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_ForbidsNullStringValues()
|
||||
{
|
||||
var map = new MapField<string, string>();
|
||||
Assert.Throws<ArgumentNullException>(() => map.Add("missing", null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Add_ForbidsNullByteStringValues()
|
||||
{
|
||||
var map = new MapField<string, ByteString>();
|
||||
Assert.Throws<ArgumentNullException>(() => map.Add("missing", null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_ForbidsNullKeys()
|
||||
{
|
||||
var map = new MapField<string, ForeignMessage>();
|
||||
Assert.Throws<ArgumentNullException>(() => map[null] = new ForeignMessage());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_AcceptsNullMessageValues()
|
||||
{
|
||||
var map = new MapField<string, ForeignMessage>();
|
||||
map["missing"] = null;
|
||||
Assert.IsNull(map["missing"]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_ForbidsNullStringValues()
|
||||
{
|
||||
var map = new MapField<string, string>();
|
||||
Assert.Throws<ArgumentNullException>(() => map["missing"] = null);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Indexer_ForbidsNullByteStringValues()
|
||||
{
|
||||
var map = new MapField<string, ByteString>();
|
||||
Assert.Throws<ArgumentNullException>(() => map["missing"] = null);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void AddPreservesInsertionOrder()
|
||||
{
|
||||
|
@ -528,6 +509,30 @@ namespace Google.Protobuf.Collections
|
|||
Assert.Throws<NotSupportedException>(() => dictionary["a"] = "c");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void AllowNullValues_Property()
|
||||
{
|
||||
// Non-message reference type values are non-nullable by default, but can be overridden
|
||||
Assert.IsFalse(new MapField<int, string>().AllowsNullValues);
|
||||
Assert.IsFalse(new MapField<int, string>(false).AllowsNullValues);
|
||||
Assert.IsTrue(new MapField<int, string>(true).AllowsNullValues);
|
||||
|
||||
// Non-nullable value type values are never nullable
|
||||
Assert.IsFalse(new MapField<int, int>().AllowsNullValues);
|
||||
Assert.IsFalse(new MapField<int, int>(false).AllowsNullValues);
|
||||
Assert.Throws<ArgumentException>(() => new MapField<int, int>(true));
|
||||
|
||||
// Message type values are nullable by default, but can be overridden
|
||||
Assert.IsTrue(new MapField<int, TestAllTypes>().AllowsNullValues);
|
||||
Assert.IsFalse(new MapField<int, TestAllTypes>(false).AllowsNullValues);
|
||||
Assert.IsTrue(new MapField<int, TestAllTypes>(true).AllowsNullValues);
|
||||
|
||||
// Nullable value type values are nullable by default, but can be overridden
|
||||
Assert.IsTrue(new MapField<int, int?>().AllowsNullValues);
|
||||
Assert.IsFalse(new MapField<int, int?>(false).AllowsNullValues);
|
||||
Assert.IsTrue(new MapField<int, int?>(true).AllowsNullValues);
|
||||
}
|
||||
|
||||
private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
|
||||
{
|
||||
return new KeyValuePair<TKey, TValue>(key, value);
|
||||
|
|
|
@ -93,6 +93,8 @@
|
|||
<Compile Include="IssuesTest.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="TestCornerCases.cs" />
|
||||
<Compile Include="TestProtos\UnittestWellKnownTypes.cs" />
|
||||
<Compile Include="WellKnownTypes\WrappersTest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ProtocolBuffers\ProtocolBuffers.csproj">
|
||||
|
|
2453
csharp/src/ProtocolBuffers.Test/TestProtos/UnittestWellKnownTypes.cs
Normal file
2453
csharp/src/ProtocolBuffers.Test/TestProtos/UnittestWellKnownTypes.cs
Normal file
File diff suppressed because it is too large
Load diff
326
csharp/src/ProtocolBuffers.Test/WellKnownTypes/WrappersTest.cs
Normal file
326
csharp/src/ProtocolBuffers.Test/WellKnownTypes/WrappersTest.cs
Normal file
|
@ -0,0 +1,326 @@
|
|||
#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 Google.Protobuf.TestProtos;
|
||||
using NUnit.Framework;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
|
||||
namespace Google.Protobuf.WellKnownTypes
|
||||
{
|
||||
public class WrappersTest
|
||||
{
|
||||
[Test]
|
||||
public void NullIsDefault()
|
||||
{
|
||||
var message = new TestWellKnownTypes();
|
||||
Assert.IsNull(message.StringField);
|
||||
Assert.IsNull(message.BytesField);
|
||||
Assert.IsNull(message.BoolField);
|
||||
Assert.IsNull(message.FloatField);
|
||||
Assert.IsNull(message.DoubleField);
|
||||
Assert.IsNull(message.Int32Field);
|
||||
Assert.IsNull(message.Int64Field);
|
||||
Assert.IsNull(message.Uint32Field);
|
||||
Assert.IsNull(message.Uint64Field);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NonDefaultSingleValues()
|
||||
{
|
||||
var message = new TestWellKnownTypes
|
||||
{
|
||||
StringField = "x",
|
||||
BytesField = ByteString.CopyFrom(1, 2, 3),
|
||||
BoolField = true,
|
||||
FloatField = 12.5f,
|
||||
DoubleField = 12.25d,
|
||||
Int32Field = 1,
|
||||
Int64Field = 2,
|
||||
Uint32Field = 3,
|
||||
Uint64Field = 4
|
||||
};
|
||||
|
||||
var bytes = message.ToByteArray();
|
||||
var parsed = TestWellKnownTypes.Parser.ParseFrom(bytes);
|
||||
|
||||
Assert.AreEqual("x", parsed.StringField);
|
||||
Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), parsed.BytesField);
|
||||
Assert.AreEqual(true, parsed.BoolField);
|
||||
Assert.AreEqual(12.5f, parsed.FloatField);
|
||||
Assert.AreEqual(12.25d, parsed.DoubleField);
|
||||
Assert.AreEqual(1, parsed.Int32Field);
|
||||
Assert.AreEqual(2L, parsed.Int64Field);
|
||||
Assert.AreEqual(3U, parsed.Uint32Field);
|
||||
Assert.AreEqual(4UL, parsed.Uint64Field);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void NonNullDefaultIsPreservedThroughSerialization()
|
||||
{
|
||||
var message = new TestWellKnownTypes
|
||||
{
|
||||
StringField = "",
|
||||
BytesField = ByteString.Empty,
|
||||
BoolField = false,
|
||||
FloatField = 0f,
|
||||
DoubleField = 0d,
|
||||
Int32Field = 0,
|
||||
Int64Field = 0,
|
||||
Uint32Field = 0,
|
||||
Uint64Field = 0
|
||||
};
|
||||
|
||||
var bytes = message.ToByteArray();
|
||||
var parsed = TestWellKnownTypes.Parser.ParseFrom(bytes);
|
||||
|
||||
Assert.AreEqual("", parsed.StringField);
|
||||
Assert.AreEqual(ByteString.Empty, parsed.BytesField);
|
||||
Assert.AreEqual(false, parsed.BoolField);
|
||||
Assert.AreEqual(0f, parsed.FloatField);
|
||||
Assert.AreEqual(0d, parsed.DoubleField);
|
||||
Assert.AreEqual(0, parsed.Int32Field);
|
||||
Assert.AreEqual(0L, parsed.Int64Field);
|
||||
Assert.AreEqual(0U, parsed.Uint32Field);
|
||||
Assert.AreEqual(0UL, parsed.Uint64Field);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RepeatedWrappersProhibitNullItems()
|
||||
{
|
||||
var message = new RepeatedWellKnownTypes();
|
||||
Assert.Throws<ArgumentNullException>(() => message.BoolField.Add((bool?) null));
|
||||
Assert.Throws<ArgumentNullException>(() => message.Int32Field.Add((int?) null));
|
||||
Assert.Throws<ArgumentNullException>(() => message.StringField.Add((string) null));
|
||||
Assert.Throws<ArgumentNullException>(() => message.BytesField.Add((ByteString) null));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RepeatedWrappersSerializeDeserialize()
|
||||
{
|
||||
var message = new RepeatedWellKnownTypes
|
||||
{
|
||||
BoolField = { true, false },
|
||||
BytesField = { ByteString.CopyFrom(1, 2, 3), ByteString.CopyFrom(4, 5, 6), ByteString.Empty },
|
||||
DoubleField = { 12.5, -1.5, 0d },
|
||||
FloatField = { 123.25f, -20f, 0f },
|
||||
Int32Field = { int.MaxValue, int.MinValue, 0 },
|
||||
Int64Field = { long.MaxValue, long.MinValue, 0L },
|
||||
StringField = { "First", "Second", "" },
|
||||
Uint32Field = { uint.MaxValue, uint.MinValue, 0U },
|
||||
Uint64Field = { ulong.MaxValue, ulong.MinValue, 0UL },
|
||||
};
|
||||
var bytes = message.ToByteArray();
|
||||
var parsed = RepeatedWellKnownTypes.Parser.ParseFrom(bytes);
|
||||
|
||||
Assert.AreEqual(message, parsed);
|
||||
// Just to test a single value for sanity...
|
||||
Assert.AreEqual("Second", message.StringField[1]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void MapWrappersSerializeDeserialize()
|
||||
{
|
||||
var message = new MapWellKnownTypes
|
||||
{
|
||||
BoolField = { { 10, false }, { 20, true } },
|
||||
BytesField = {
|
||||
{ -1, ByteString.CopyFrom(1, 2, 3) },
|
||||
{ 10, ByteString.CopyFrom(4, 5, 6) },
|
||||
{ 1000, ByteString.Empty },
|
||||
{ 10000, null }
|
||||
},
|
||||
DoubleField = { { 1, 12.5 }, { 10, -1.5 }, { 20, 0d } },
|
||||
FloatField = { { 2, 123.25f }, { 3, -20f }, { 4, 0f } },
|
||||
Int32Field = { { 5, int.MaxValue }, { 6, int.MinValue }, { 7, 0 } },
|
||||
Int64Field = { { 8, long.MaxValue }, { 9, long.MinValue }, { 10, 0L } },
|
||||
StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" }, { 14, null } },
|
||||
Uint32Field = { { 15, uint.MaxValue }, { 16, uint.MinValue }, { 17, 0U } },
|
||||
Uint64Field = { { 18, ulong.MaxValue }, { 19, ulong.MinValue }, { 20, 0UL } },
|
||||
};
|
||||
|
||||
var bytes = message.ToByteArray();
|
||||
var parsed = MapWellKnownTypes.Parser.ParseFrom(bytes);
|
||||
|
||||
Assert.AreEqual(message, parsed);
|
||||
// Just to test a single value for sanity...
|
||||
Assert.AreEqual("Second", message.StringField[12]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_SingleValues()
|
||||
{
|
||||
var message = new TestWellKnownTypes
|
||||
{
|
||||
StringField = "x",
|
||||
BytesField = ByteString.CopyFrom(1, 2, 3),
|
||||
BoolField = true,
|
||||
FloatField = 12.5f,
|
||||
DoubleField = 12.25d,
|
||||
Int32Field = 1,
|
||||
Int64Field = 2,
|
||||
Uint32Field = 3,
|
||||
Uint64Field = 4
|
||||
};
|
||||
var fields = ((IReflectedMessage) message).Fields;
|
||||
|
||||
Assert.AreEqual("x", fields[TestWellKnownTypes.StringFieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(ByteString.CopyFrom(1, 2, 3), fields[TestWellKnownTypes.BytesFieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(true, fields[TestWellKnownTypes.BoolFieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(12.5f, fields[TestWellKnownTypes.FloatFieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(12.25d, fields[TestWellKnownTypes.DoubleFieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(1, fields[TestWellKnownTypes.Int32FieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(2L, fields[TestWellKnownTypes.Int64FieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(3U, fields[TestWellKnownTypes.Uint32FieldFieldNumber].GetValue(message));
|
||||
Assert.AreEqual(4UL, fields[TestWellKnownTypes.Uint64FieldFieldNumber].GetValue(message));
|
||||
|
||||
// And a couple of null fields...
|
||||
message.StringField = null;
|
||||
message.FloatField = null;
|
||||
Assert.IsNull(fields[TestWellKnownTypes.StringFieldFieldNumber].GetValue(message));
|
||||
Assert.IsNull(fields[TestWellKnownTypes.FloatFieldFieldNumber].GetValue(message));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_RepeatedFields()
|
||||
{
|
||||
// Just a single example... note that we can't have a null value here
|
||||
var message = new RepeatedWellKnownTypes { Int32Field = { 1, 2 } };
|
||||
var fields = ((IReflectedMessage) message).Fields;
|
||||
var list = (IList) fields[RepeatedWellKnownTypes.Int32FieldFieldNumber].GetValue(message);
|
||||
CollectionAssert.AreEqual(new[] { 1, 2 }, list);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Reflection_MapFields()
|
||||
{
|
||||
// Just a single example... note that we can't have a null value here
|
||||
var message = new MapWellKnownTypes { Int32Field = { { 1, 2 }, { 3, null } } };
|
||||
var fields = ((IReflectedMessage) message).Fields;
|
||||
var dictionary = (IDictionary) fields[MapWellKnownTypes.Int32FieldFieldNumber].GetValue(message);
|
||||
Assert.AreEqual(2, dictionary[1]);
|
||||
Assert.IsNull(dictionary[3]);
|
||||
Assert.IsTrue(dictionary.Contains(3));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Oneof()
|
||||
{
|
||||
var message = new OneofWellKnownTypes { EmptyField = new Empty() };
|
||||
// Start off with a non-wrapper
|
||||
Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.EmptyField, message.OneofFieldCase);
|
||||
AssertOneofRoundTrip(message);
|
||||
|
||||
message.StringField = "foo";
|
||||
Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase);
|
||||
AssertOneofRoundTrip(message);
|
||||
|
||||
message.StringField = "foo";
|
||||
Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.StringField, message.OneofFieldCase);
|
||||
AssertOneofRoundTrip(message);
|
||||
|
||||
message.DoubleField = 0.0f;
|
||||
Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase);
|
||||
AssertOneofRoundTrip(message);
|
||||
|
||||
message.DoubleField = 1.0f;
|
||||
Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.DoubleField, message.OneofFieldCase);
|
||||
AssertOneofRoundTrip(message);
|
||||
|
||||
message.ClearOneofField();
|
||||
Assert.AreEqual(OneofWellKnownTypes.OneofFieldOneofCase.None, message.OneofFieldCase);
|
||||
AssertOneofRoundTrip(message);
|
||||
}
|
||||
|
||||
private void AssertOneofRoundTrip(OneofWellKnownTypes message)
|
||||
{
|
||||
// Normal roundtrip, but explicitly checking the case...
|
||||
var bytes = message.ToByteArray();
|
||||
var parsed = OneofWellKnownTypes.Parser.ParseFrom(bytes);
|
||||
Assert.AreEqual(message, parsed);
|
||||
Assert.AreEqual(message.OneofFieldCase, parsed.OneofFieldCase);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase("x", "y", "y")]
|
||||
[TestCase("x", "", "x")]
|
||||
[TestCase("x", null, "x")]
|
||||
[TestCase("", "y", "y")]
|
||||
[TestCase("", "", "")]
|
||||
[TestCase("", null, "")]
|
||||
[TestCase(null, "y", "y")]
|
||||
[TestCase(null, "", "")]
|
||||
[TestCase(null, null, null)]
|
||||
public void Merging(string original, string merged, string expected)
|
||||
{
|
||||
var originalMessage = new TestWellKnownTypes { StringField = original };
|
||||
var mergingMessage = new TestWellKnownTypes { StringField = merged };
|
||||
originalMessage.MergeFrom(mergingMessage);
|
||||
Assert.AreEqual(expected, originalMessage.StringField);
|
||||
|
||||
// Try it using MergeFrom(CodedInputStream) too...
|
||||
originalMessage = new TestWellKnownTypes { StringField = original };
|
||||
originalMessage.MergeFrom(mergingMessage.ToByteArray());
|
||||
Assert.AreEqual(expected, originalMessage.StringField);
|
||||
}
|
||||
|
||||
// Merging is odd with wrapper types, due to the way that default values aren't emitted in
|
||||
// the binary stream. In fact we cheat a little bit - a message with an explicitly present default
|
||||
// value will have that default value ignored.
|
||||
[Test]
|
||||
public void MergingCornerCase()
|
||||
{
|
||||
var message = new TestWellKnownTypes { Int32Field = 5 };
|
||||
|
||||
// Create a byte array which has the data of an Int32Value explicitly containing a value of 0.
|
||||
// This wouldn't normally happen.
|
||||
byte[] bytes;
|
||||
var wrapperTag = WireFormat.MakeTag(TestWellKnownTypes.Int32FieldFieldNumber, WireFormat.WireType.LengthDelimited);
|
||||
var valueTag = WireFormat.MakeTag(Int32Value.ValueFieldNumber, WireFormat.WireType.Varint);
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
var coded = CodedOutputStream.CreateInstance(stream);
|
||||
coded.WriteTag(wrapperTag);
|
||||
coded.WriteLength(2); // valueTag + a value 0, each one byte
|
||||
coded.WriteTag(valueTag);
|
||||
coded.WriteInt32(0);
|
||||
coded.Flush();
|
||||
bytes = stream.ToArray();
|
||||
}
|
||||
|
||||
message.MergeFrom(bytes);
|
||||
// A normal implementation would have 0 now, as the explicit default would have been overwritten the 5.
|
||||
Assert.AreEqual(5, message.Int32Field);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -212,11 +212,22 @@ namespace Google.Protobuf
|
|||
{
|
||||
return true;
|
||||
}
|
||||
if (ReferenceEquals(lhs, null))
|
||||
if (ReferenceEquals(lhs, null) || ReferenceEquals(rhs, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return lhs.Equals(rhs);
|
||||
if (lhs.bytes.Length != rhs.bytes.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < lhs.Length; i++)
|
||||
{
|
||||
if (rhs.bytes[i] != lhs.bytes[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool operator !=(ByteString lhs, ByteString rhs)
|
||||
|
@ -228,12 +239,7 @@ namespace Google.Protobuf
|
|||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
ByteString other = obj as ByteString;
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Equals(other);
|
||||
return this == (obj as ByteString);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
@ -248,18 +254,7 @@ namespace Google.Protobuf
|
|||
|
||||
public bool Equals(ByteString other)
|
||||
{
|
||||
if (other.bytes.Length != bytes.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < bytes.Length; i++)
|
||||
{
|
||||
if (other.bytes[i] != bytes[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return this == other;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -129,8 +129,7 @@ namespace Google.Protobuf
|
|||
public static int ComputeStringSize(String value)
|
||||
{
|
||||
int byteArraySize = Utf8Encoding.GetByteCount(value);
|
||||
return ComputeRawVarint32Size((uint) byteArraySize) +
|
||||
byteArraySize;
|
||||
return ComputeLengthSize(byteArraySize) + byteArraySize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -149,7 +148,7 @@ namespace Google.Protobuf
|
|||
public static int ComputeMessageSize(IMessage value)
|
||||
{
|
||||
int size = value.CalculateSize();
|
||||
return ComputeRawVarint32Size((uint) size) + size;
|
||||
return ComputeLengthSize(size) + size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -158,8 +157,7 @@ namespace Google.Protobuf
|
|||
/// </summary>
|
||||
public static int ComputeBytesSize(ByteString value)
|
||||
{
|
||||
return ComputeRawVarint32Size((uint) value.Length) +
|
||||
value.Length;
|
||||
return ComputeLengthSize(value.Length) + value.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -274,7 +274,7 @@ namespace Google.Protobuf
|
|||
/// <param name="value">The value to write</param>
|
||||
public void WriteMessage(IMessage value)
|
||||
{
|
||||
WriteRawVarint32((uint) value.CalculateSize());
|
||||
WriteLength(value.CalculateSize());
|
||||
value.WriteTo(this);
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ namespace Google.Protobuf
|
|||
/// <param name="value">The value to write</param>
|
||||
public void WriteBytes(ByteString value)
|
||||
{
|
||||
WriteRawVarint32((uint) value.Length);
|
||||
WriteLength(value.Length);
|
||||
value.WriteRawBytesTo(this);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,14 +51,38 @@ namespace Google.Protobuf.Collections
|
|||
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IFreezable, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
|
||||
{
|
||||
// TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
|
||||
private readonly bool allowNullValues;
|
||||
private bool frozen;
|
||||
private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
|
||||
new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
|
||||
private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new map field, defaulting the value nullability to only allow null values for message types
|
||||
/// and non-nullable value types.
|
||||
/// </summary>
|
||||
public MapField() : this(typeof(IMessage).IsAssignableFrom(typeof(TValue)) || Nullable.GetUnderlyingType(typeof(TValue)) != null)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a new map field, overriding the choice of whether null values are permitted in the map.
|
||||
/// This is used by wrapper types, where maps with string and bytes wrappers as the value types
|
||||
/// support null values.
|
||||
/// </summary>
|
||||
/// <param name="allowNullValues">Whether null values are permitted in the map or not.</param>
|
||||
public MapField(bool allowNullValues)
|
||||
{
|
||||
if (allowNullValues && typeof(TValue).IsValueType && Nullable.GetUnderlyingType(typeof(TValue)) == null)
|
||||
{
|
||||
throw new ArgumentException("allowNullValues", "Non-nullable value types do not support null values");
|
||||
}
|
||||
this.allowNullValues = allowNullValues;
|
||||
}
|
||||
|
||||
public MapField<TKey, TValue> Clone()
|
||||
{
|
||||
var clone = new MapField<TKey, TValue>();
|
||||
var clone = new MapField<TKey, TValue>(allowNullValues);
|
||||
// Keys are never cloneable. Values might be.
|
||||
if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
|
||||
{
|
||||
|
@ -138,7 +162,8 @@ namespace Google.Protobuf.Collections
|
|||
set
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(key, "key");
|
||||
if (value == null && (typeof(TValue) == typeof(ByteString) || typeof(TValue) == typeof(string)))
|
||||
// value == null check here is redundant, but avoids boxing.
|
||||
if (value == null && !allowNullValues)
|
||||
{
|
||||
ThrowHelper.ThrowIfNull(value, "value");
|
||||
}
|
||||
|
@ -225,6 +250,11 @@ namespace Google.Protobuf.Collections
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not this map allows values to be null.
|
||||
/// </summary>
|
||||
public bool AllowsNullValues { get { return allowNullValues; } }
|
||||
|
||||
public int Count { get { return list.Count; } }
|
||||
public bool IsReadOnly { get { return frozen; } }
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ namespace Google.Protobuf.Collections
|
|||
{
|
||||
int dataSize = CalculatePackedDataSize(codec);
|
||||
return CodedOutputStream.ComputeRawVarint32Size(tag) +
|
||||
CodedOutputStream.ComputeRawVarint32Size((uint)dataSize) +
|
||||
CodedOutputStream.ComputeLengthSize(dataSize) +
|
||||
dataSize;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#endregion
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -43,7 +43,7 @@ namespace Google.Protobuf
|
|||
// TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...)
|
||||
public static FieldCodec<string> ForString(uint tag)
|
||||
{
|
||||
return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
|
||||
return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
|
||||
}
|
||||
|
||||
public static FieldCodec<ByteString> ForBytes(uint tag)
|
||||
|
@ -131,6 +131,116 @@ namespace Google.Protobuf
|
|||
return new FieldCodec<T>(input => { T message = parser.CreateTemplate(); input.ReadMessage(message); return message; },
|
||||
(output, value) => output.WriteMessage(value), message => CodedOutputStream.ComputeMessageSize(message), tag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a codec for a wrapper type of a class - which must be string or ByteString.
|
||||
/// </summary>
|
||||
public static FieldCodec<T> ForClassWrapper<T>(uint tag) where T : class
|
||||
{
|
||||
var nestedCodec = WrapperCodecs.GetCodec<T>();
|
||||
return new FieldCodec<T>(
|
||||
input => WrapperCodecs.Read<T>(input, nestedCodec),
|
||||
(output, value) => WrapperCodecs.Write<T>(output, value, nestedCodec),
|
||||
value => WrapperCodecs.CalculateSize<T>(value, nestedCodec),
|
||||
tag,
|
||||
null); // Default value for the wrapper
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a codec for a wrapper type of a struct - which must be Int32, Int64, UInt32, UInt64,
|
||||
/// Bool, Single or Double.
|
||||
/// </summary>
|
||||
public static FieldCodec<T?> ForStructWrapper<T>(uint tag) where T : struct
|
||||
{
|
||||
var nestedCodec = WrapperCodecs.GetCodec<T>();
|
||||
return new FieldCodec<T?>(
|
||||
input => WrapperCodecs.Read<T>(input, nestedCodec),
|
||||
(output, value) => WrapperCodecs.Write<T>(output, value.Value, nestedCodec),
|
||||
value => value == null ? 0 : WrapperCodecs.CalculateSize<T>(value.Value, nestedCodec),
|
||||
tag,
|
||||
null); // Default value for the wrapper
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper code to create codecs for wrapper types.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Somewhat ugly with all the static methods, but the conversions involved to/from nullable types make it
|
||||
/// slightly tricky to improve. So long as we keep the public API (ForClassWrapper, ForStructWrapper) in place,
|
||||
/// we can refactor later if we come up with something cleaner.
|
||||
/// </remarks>
|
||||
private static class WrapperCodecs
|
||||
{
|
||||
// All the field numbers are the same (1).
|
||||
private const int WrapperValueFieldNumber = Google.Protobuf.WellKnownTypes.Int32Value.ValueFieldNumber;
|
||||
|
||||
private static readonly Dictionary<Type, object> Codecs = new Dictionary<Type, object>
|
||||
{
|
||||
{ typeof(bool), ForBool(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||
{ typeof(int), ForInt32(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||
{ typeof(long), ForInt64(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||
{ typeof(uint), ForUInt32(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||
{ typeof(ulong), ForUInt64(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
|
||||
{ typeof(float), ForFloat(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) },
|
||||
{ typeof(double), ForDouble(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) },
|
||||
{ typeof(string), ForString(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) },
|
||||
{ typeof(ByteString), ForBytes(WireFormat.MakeTag(WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Returns a field codec which effectively wraps a value of type T in a message.
|
||||
///
|
||||
/// </summary>
|
||||
internal static FieldCodec<T> GetCodec<T>()
|
||||
{
|
||||
object value;
|
||||
if (!Codecs.TryGetValue(typeof(T), out value))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T));
|
||||
}
|
||||
return (FieldCodec<T>) value;
|
||||
}
|
||||
|
||||
internal static T Read<T>(CodedInputStream input, FieldCodec<T> codec)
|
||||
{
|
||||
int length = input.ReadLength();
|
||||
int oldLimit = input.PushLimit(length);
|
||||
|
||||
uint tag;
|
||||
T value = codec.DefaultValue;
|
||||
while (input.ReadTag(out tag))
|
||||
{
|
||||
if (tag == 0)
|
||||
{
|
||||
throw InvalidProtocolBufferException.InvalidTag();
|
||||
}
|
||||
if (tag == codec.Tag)
|
||||
{
|
||||
value = codec.Read(input);
|
||||
}
|
||||
if (WireFormat.IsEndGroupTag(tag))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
input.CheckLastTagWas(0);
|
||||
input.PopLimit(oldLimit);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
internal static void Write<T>(CodedOutputStream output, T value, FieldCodec<T> codec)
|
||||
{
|
||||
output.WriteLength(codec.CalculateSizeWithTag(value));
|
||||
codec.WriteTagAndValue(output, value);
|
||||
}
|
||||
|
||||
internal static int CalculateSize<T>(T value, FieldCodec<T> codec)
|
||||
{
|
||||
int fieldLength = codec.CalculateSizeWithTag(value);
|
||||
return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -144,31 +254,19 @@ namespace Google.Protobuf
|
|||
/// </remarks>
|
||||
public sealed class FieldCodec<T>
|
||||
{
|
||||
private static readonly Func<T, bool> IsDefault;
|
||||
private static readonly T Default;
|
||||
private static readonly T DefaultDefault;
|
||||
|
||||
static FieldCodec()
|
||||
{
|
||||
if (typeof(T) == typeof(string))
|
||||
{
|
||||
Default = (T)(object)"";
|
||||
IsDefault = CreateDefaultValueCheck<string>(x => x.Length == 0);
|
||||
DefaultDefault = (T)(object)"";
|
||||
}
|
||||
else if (typeof(T) == typeof(ByteString))
|
||||
{
|
||||
Default = (T)(object)ByteString.Empty;
|
||||
IsDefault = CreateDefaultValueCheck<ByteString>(x => x.Length == 0);
|
||||
}
|
||||
else if (!typeof(T).IsValueType)
|
||||
{
|
||||
// Default default
|
||||
IsDefault = CreateDefaultValueCheck<T>(x => x == null);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default default
|
||||
IsDefault = CreateDefaultValueCheck<T>(x => EqualityComparer<T>.Default.Equals(x, default(T)));
|
||||
DefaultDefault = (T)(object)ByteString.Empty;
|
||||
}
|
||||
// Otherwise it's the default value of the CLR type
|
||||
}
|
||||
|
||||
private static Func<T, bool> CreateDefaultValueCheck<TTmp>(Func<TTmp, bool> check)
|
||||
|
@ -182,18 +280,32 @@ namespace Google.Protobuf
|
|||
private readonly uint tag;
|
||||
private readonly int tagSize;
|
||||
private readonly int fixedSize;
|
||||
// Default value for this codec. Usually the same for every instance of the same type, but
|
||||
// for string/ByteString wrapper fields the codec's default value is null, whereas for
|
||||
// other string/ByteString fields it's "" or ByteString.Empty.
|
||||
private readonly T defaultValue;
|
||||
|
||||
internal FieldCodec(
|
||||
Func<CodedInputStream, T> reader,
|
||||
Action<CodedOutputStream, T> writer,
|
||||
Func<T, int> sizeCalculator,
|
||||
uint tag)
|
||||
uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault)
|
||||
{
|
||||
}
|
||||
|
||||
internal FieldCodec(
|
||||
Func<CodedInputStream, T> reader,
|
||||
Action<CodedOutputStream, T> writer,
|
||||
Func<T, int> sizeCalculator,
|
||||
uint tag,
|
||||
T defaultValue)
|
||||
{
|
||||
this.reader = reader;
|
||||
this.writer = writer;
|
||||
this.sizeCalculator = sizeCalculator;
|
||||
this.fixedSize = 0;
|
||||
this.tag = tag;
|
||||
this.defaultValue = defaultValue;
|
||||
tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
|
||||
}
|
||||
|
||||
|
@ -234,7 +346,7 @@ namespace Google.Protobuf
|
|||
|
||||
public uint Tag { get { return tag; } }
|
||||
|
||||
public T DefaultValue { get { return Default; } }
|
||||
public T DefaultValue { get { return defaultValue; } }
|
||||
|
||||
/// <summary>
|
||||
/// Write a tag and the given value, *if* the value is not the default.
|
||||
|
@ -260,6 +372,11 @@ namespace Google.Protobuf
|
|||
public int CalculateSizeWithTag(T value)
|
||||
{
|
||||
return IsDefault(value) ? 0 : sizeCalculator(value) + tagSize;
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsDefault(T value)
|
||||
{
|
||||
return EqualityComparer<T>.Default.Equals(value, defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -442,7 +442,9 @@ libprotoc_la_SOURCES = \
|
|||
google/protobuf/compiler/csharp/csharp_source_generator_base.cc \
|
||||
google/protobuf/compiler/csharp/csharp_source_generator_base.h \
|
||||
google/protobuf/compiler/csharp/csharp_umbrella_class.cc \
|
||||
google/protobuf/compiler/csharp/csharp_umbrella_class.h
|
||||
google/protobuf/compiler/csharp/csharp_umbrella_class.h \
|
||||
google/protobuf/compiler/csharp/csharp_wrapper_field.cc \
|
||||
google/protobuf/compiler/csharp/csharp_wrapper_field.h
|
||||
|
||||
bin_PROGRAMS = protoc
|
||||
protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
|
||||
|
|
|
@ -169,6 +169,18 @@ std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
|
|||
return GetClassName(descriptor->enum_type());
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
case FieldDescriptor::TYPE_GROUP:
|
||||
if (IsWrapperType(descriptor)) {
|
||||
const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
|
||||
string wrapped_field_type_name = type_name(wrapped_field);
|
||||
// String and ByteString go to the same type; other wrapped types go to the
|
||||
// nullable equivalent.
|
||||
if (wrapped_field->type() == FieldDescriptor::TYPE_STRING ||
|
||||
wrapped_field->type() == FieldDescriptor::TYPE_BYTES) {
|
||||
return wrapped_field_type_name;
|
||||
} else {
|
||||
return wrapped_field_type_name + "?";
|
||||
}
|
||||
}
|
||||
return GetClassName(descriptor->message_type());
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
return "double";
|
||||
|
@ -298,14 +310,23 @@ std::string FieldGeneratorBase::GetBytesDefaultValueInternal() {
|
|||
}
|
||||
|
||||
std::string FieldGeneratorBase::default_value() {
|
||||
switch (descriptor_->type()) {
|
||||
return default_value(descriptor_);
|
||||
}
|
||||
|
||||
std::string FieldGeneratorBase::default_value(const FieldDescriptor* descriptor) {
|
||||
switch (descriptor->type()) {
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
return type_name() + "." + descriptor_->default_value_enum()->name();
|
||||
return type_name() + "." + descriptor->default_value_enum()->name();
|
||||
case FieldDescriptor::TYPE_MESSAGE:
|
||||
case FieldDescriptor::TYPE_GROUP:
|
||||
return type_name() + ".DefaultInstance";
|
||||
if (IsWrapperType(descriptor)) {
|
||||
const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
|
||||
return default_value(wrapped_field);
|
||||
} else {
|
||||
return "null";
|
||||
}
|
||||
case FieldDescriptor::TYPE_DOUBLE: {
|
||||
double value = descriptor_->default_value_double();
|
||||
double value = descriptor->default_value_double();
|
||||
if (value == numeric_limits<double>::infinity()) {
|
||||
return "double.PositiveInfinity";
|
||||
} else if (value == -numeric_limits<double>::infinity()) {
|
||||
|
@ -316,7 +337,7 @@ std::string FieldGeneratorBase::default_value() {
|
|||
return SimpleDtoa(value) + "D";
|
||||
}
|
||||
case FieldDescriptor::TYPE_FLOAT: {
|
||||
float value = descriptor_->default_value_float();
|
||||
float value = descriptor->default_value_float();
|
||||
if (value == numeric_limits<float>::infinity()) {
|
||||
return "float.PositiveInfinity";
|
||||
} else if (value == -numeric_limits<float>::infinity()) {
|
||||
|
@ -327,17 +348,17 @@ std::string FieldGeneratorBase::default_value() {
|
|||
return SimpleFtoa(value) + "F";
|
||||
}
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
return SimpleItoa(descriptor_->default_value_int64()) + "L";
|
||||
return SimpleItoa(descriptor->default_value_int64()) + "L";
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
return SimpleItoa(descriptor_->default_value_uint64()) + "UL";
|
||||
return SimpleItoa(descriptor->default_value_uint64()) + "UL";
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
return SimpleItoa(descriptor_->default_value_int32());
|
||||
return SimpleItoa(descriptor->default_value_int32());
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
return SimpleItoa(descriptor_->default_value_uint64()) + "UL";
|
||||
return SimpleItoa(descriptor->default_value_uint64()) + "UL";
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
return SimpleItoa(descriptor_->default_value_uint32());
|
||||
return SimpleItoa(descriptor->default_value_uint32());
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
if (descriptor_->default_value_bool()) {
|
||||
if (descriptor->default_value_bool()) {
|
||||
return "true";
|
||||
} else {
|
||||
return "false";
|
||||
|
@ -347,15 +368,15 @@ std::string FieldGeneratorBase::default_value() {
|
|||
case FieldDescriptor::TYPE_BYTES:
|
||||
return GetBytesDefaultValueInternal();
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
return SimpleItoa(descriptor_->default_value_uint32());
|
||||
return SimpleItoa(descriptor->default_value_uint32());
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
return SimpleItoa(descriptor_->default_value_int32());
|
||||
return SimpleItoa(descriptor->default_value_int32());
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
return SimpleItoa(descriptor_->default_value_int64()) + "L";
|
||||
return SimpleItoa(descriptor->default_value_int64()) + "L";
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
return SimpleItoa(descriptor_->default_value_int32());
|
||||
return SimpleItoa(descriptor->default_value_int32());
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return SimpleItoa(descriptor_->default_value_int64()) + "L";
|
||||
return SimpleItoa(descriptor->default_value_int64()) + "L";
|
||||
default:
|
||||
GOOGLE_LOG(FATAL)<< "Unknown field type.";
|
||||
return "";
|
||||
|
|
|
@ -82,6 +82,7 @@ class FieldGeneratorBase : public SourceGeneratorBase {
|
|||
bool has_default_value();
|
||||
bool is_nullable_type();
|
||||
std::string default_value();
|
||||
std::string default_value(const FieldDescriptor* descriptor);
|
||||
std::string number();
|
||||
std::string capitalized_type_name();
|
||||
std::string field_ordinal();
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
@ -366,31 +367,39 @@ FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
|
|||
return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
} else {
|
||||
if (descriptor->containing_oneof()) {
|
||||
return new MessageOneofFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
return new MessageFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
if (IsWrapperType(descriptor)) {
|
||||
if (descriptor->containing_oneof()) {
|
||||
return new WrapperOneofFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
return new WrapperFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
} else {
|
||||
if (descriptor->containing_oneof()) {
|
||||
return new MessageOneofFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
return new MessageFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
if (descriptor->is_repeated()) {
|
||||
return new RepeatedEnumFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
if (descriptor->containing_oneof()) {
|
||||
return new EnumOneofFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
return new EnumFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
if (descriptor->containing_oneof()) {
|
||||
return new EnumOneofFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
return new EnumFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
}
|
||||
default:
|
||||
if (descriptor->is_repeated()) {
|
||||
return new RepeatedPrimitiveFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
if (descriptor->containing_oneof()) {
|
||||
return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
return new PrimitiveFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
if (descriptor->containing_oneof()) {
|
||||
return new PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal);
|
||||
} else {
|
||||
return new PrimitiveFieldGenerator(descriptor, fieldOrdinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,6 +119,15 @@ inline bool IsDescriptorProto(const FileDescriptor* descriptor) {
|
|||
return descriptor->name() == "google/protobuf/descriptor_proto_file.proto";
|
||||
}
|
||||
|
||||
inline bool IsMapEntry(const Descriptor* descriptor) {
|
||||
return descriptor->options().map_entry();
|
||||
}
|
||||
|
||||
inline bool IsWrapperType(const FieldDescriptor* descriptor) {
|
||||
return descriptor->type() == FieldDescriptor::TYPE_MESSAGE &&
|
||||
descriptor->message_type()->file()->name() == "google/protobuf/wrappers.proto";
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
|
|
@ -61,6 +61,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
|
|||
descriptor_->message_type()->FindFieldByName("value");
|
||||
variables_["key_type_name"] = type_name(key_descriptor);
|
||||
variables_["value_type_name"] = type_name(value_descriptor);
|
||||
variables_["true_for_wrappers"] = IsWrapperType(value_descriptor) ? "true" : "";
|
||||
scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1));
|
||||
scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
|
||||
|
||||
|
@ -74,7 +75,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
|
|||
printer->Print(
|
||||
variables_,
|
||||
", $tag$);\n"
|
||||
"private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
|
||||
"private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>($true_for_wrappers$);\n");
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
|
|
|
@ -39,6 +39,8 @@
|
|||
|
||||
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_repeated_message_field.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_message_field.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
@ -58,7 +60,18 @@ void RepeatedMessageFieldGenerator::GenerateMembers(io::Printer* printer) {
|
|||
printer->Print(
|
||||
variables_,
|
||||
"private static readonly pb::FieldCodec<$type_name$> _repeated_$name$_codec\n"
|
||||
" = pb::FieldCodec.ForMessage($tag$, $type_name$.Parser);\n");
|
||||
" = ");
|
||||
// Don't want to duplicate the codec code here... maybe we should have a
|
||||
// "create single field generator for this repeated field"
|
||||
// function, but it doesn't seem worth it for just this.
|
||||
if (IsWrapperType(descriptor_)) {
|
||||
scoped_ptr<FieldGeneratorBase> single_generator(new WrapperFieldGenerator(descriptor_, fieldOrdinal_));
|
||||
single_generator->GenerateCodecCode(printer);
|
||||
} else {
|
||||
scoped_ptr<FieldGeneratorBase> single_generator(new MessageFieldGenerator(descriptor_, fieldOrdinal_));
|
||||
single_generator->GenerateCodecCode(printer);
|
||||
}
|
||||
printer->Print(";\n");
|
||||
printer->Print(
|
||||
variables_,
|
||||
"private readonly pbc::RepeatedField<$type_name$> $name$_ = new pbc::RepeatedField<$type_name$>();\n");
|
||||
|
|
209
src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
Normal file
209
src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc
Normal file
|
@ -0,0 +1,209 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
#include <google/protobuf/compiler/plugin.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_wrapper_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
WrapperFieldGenerator::WrapperFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int fieldOrdinal)
|
||||
: FieldGeneratorBase(descriptor, fieldOrdinal) {
|
||||
variables_["has_property_check"] = name() + "_ != null";
|
||||
variables_["has_not_property_check"] = name() + "_ == null";
|
||||
const FieldDescriptor* wrapped_field = descriptor->message_type()->field(0);
|
||||
is_value_type = wrapped_field->type() != FieldDescriptor::TYPE_STRING &&
|
||||
wrapped_field->type() != FieldDescriptor::TYPE_BYTES;
|
||||
if (is_value_type) {
|
||||
variables_["nonnullable_type_name"] = type_name(wrapped_field);
|
||||
}
|
||||
}
|
||||
|
||||
WrapperFieldGenerator::~WrapperFieldGenerator() {
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"private static readonly pb::FieldCodec<$type_name$> _single_$name$_codec = ");
|
||||
GenerateCodecCode(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
";\n"
|
||||
"private $type_name$ $name$_;\n");
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$access_level$ $type_name$ $property_name$ {\n"
|
||||
" get { return $name$_; }\n"
|
||||
" set {\n"
|
||||
" pb::Freezable.CheckMutable(this);\n"
|
||||
" $name$_ = value;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::GenerateMergingCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if (other.$has_property_check$) {\n"
|
||||
" if ($has_not_property_check$ || other.$property_name$ != $default_value$) {\n"
|
||||
" $property_name$ = other.$property_name$;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::GenerateParsingCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$type_name$ value = _single_$name$_codec.Read(input);\n"
|
||||
"if ($has_not_property_check$ || value != $default_value$) {\n"
|
||||
" $property_name$ = value;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" _single_$name$_codec.WriteTagAndValue(output, $property_name$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" size += _single_$name$_codec.CalculateSizeWithTag($property_name$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::WriteHash(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) hash ^= $property_name$.GetHashCode();\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::WriteEquals(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($property_name$ != other.$property_name$) return false;\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::WriteToString(io::Printer* printer) {
|
||||
// TODO: Implement if we ever actually need it...
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::GenerateCloningCode(io::Printer* printer) {
|
||||
printer->Print(variables_,
|
||||
"$property_name$ = other.$property_name$;\n");
|
||||
}
|
||||
|
||||
void WrapperFieldGenerator::GenerateCodecCode(io::Printer* printer) {
|
||||
if (is_value_type) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"pb::FieldCodec.ForStructWrapper<$nonnullable_type_name$>($tag$)");
|
||||
} else {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"pb::FieldCodec.ForClassWrapper<$type_name$>($tag$)");
|
||||
}
|
||||
}
|
||||
|
||||
WrapperOneofFieldGenerator::WrapperOneofFieldGenerator(const FieldDescriptor* descriptor,
|
||||
int fieldOrdinal)
|
||||
: WrapperFieldGenerator(descriptor, fieldOrdinal) {
|
||||
SetCommonOneofFieldVariables(&variables_);
|
||||
}
|
||||
|
||||
WrapperOneofFieldGenerator::~WrapperOneofFieldGenerator() {
|
||||
}
|
||||
|
||||
void WrapperOneofFieldGenerator::GenerateMembers(io::Printer* printer) {
|
||||
// Note: deliberately _oneof_$name$_codec, not _$oneof_name$_codec... we have one codec per field.
|
||||
printer->Print(
|
||||
variables_,
|
||||
"private static readonly pb::FieldCodec<$type_name$> _oneof_$name$_codec = ");
|
||||
GenerateCodecCode(printer);
|
||||
printer->Print(";\n");
|
||||
AddDeprecatedFlag(printer);
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$access_level$ $type_name$ $property_name$ {\n"
|
||||
" get { return $has_property_check$ ? ($type_name$) $oneof_name$_ : ($type_name$) null; }\n"
|
||||
" set {\n"
|
||||
" pb::Freezable.CheckMutable(this);\n"
|
||||
" $oneof_name$_ = value;\n"
|
||||
" $oneof_name$Case_ = value == null ? $oneof_property_name$OneofCase.None : $oneof_property_name$OneofCase.$property_name$;\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void WrapperOneofFieldGenerator::GenerateParsingCode(io::Printer* printer) {
|
||||
printer->Print(
|
||||
variables_,
|
||||
"$property_name$ = _oneof_$name$_codec.Read(input);\n");
|
||||
}
|
||||
|
||||
void WrapperOneofFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
|
||||
// TODO: I suspect this is wrong...
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" _oneof_$name$_codec.WriteTagAndValue(output, ($type_name$) $oneof_name$_);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
void WrapperOneofFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
|
||||
// TODO: I suspect this is wrong...
|
||||
printer->Print(
|
||||
variables_,
|
||||
"if ($has_property_check$) {\n"
|
||||
" size += _oneof_$name$_codec.CalculateSizeWithTag($property_name$);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
85
src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
Normal file
85
src/google/protobuf/compiler/csharp/csharp_wrapper_field.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
|
||||
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
#include <google/protobuf/compiler/csharp/csharp_field_base.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace compiler {
|
||||
namespace csharp {
|
||||
|
||||
class WrapperFieldGenerator : public FieldGeneratorBase {
|
||||
public:
|
||||
WrapperFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
|
||||
~WrapperFieldGenerator();
|
||||
|
||||
virtual void GenerateCodecCode(io::Printer* printer);
|
||||
virtual void GenerateCloningCode(io::Printer* printer);
|
||||
virtual void GenerateMembers(io::Printer* printer);
|
||||
virtual void GenerateMergingCode(io::Printer* printer);
|
||||
virtual void GenerateParsingCode(io::Printer* printer);
|
||||
virtual void GenerateSerializationCode(io::Printer* printer);
|
||||
virtual void GenerateSerializedSizeCode(io::Printer* printer);
|
||||
|
||||
virtual void WriteHash(io::Printer* printer);
|
||||
virtual void WriteEquals(io::Printer* printer);
|
||||
virtual void WriteToString(io::Printer* printer);
|
||||
|
||||
private:
|
||||
bool is_value_type; // True for int32 etc; false for bytes and string
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WrapperFieldGenerator);
|
||||
};
|
||||
|
||||
class WrapperOneofFieldGenerator : public WrapperFieldGenerator {
|
||||
public:
|
||||
WrapperOneofFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
|
||||
~WrapperOneofFieldGenerator();
|
||||
|
||||
virtual void GenerateMembers(io::Printer* printer);
|
||||
virtual void GenerateParsingCode(io::Printer* printer);
|
||||
virtual void GenerateSerializationCode(io::Printer* printer);
|
||||
virtual void GenerateSerializedSizeCode(io::Printer* printer);
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WrapperOneofFieldGenerator);
|
||||
};
|
||||
|
||||
} // namespace csharp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_WRAPPER_FIELD_H__
|
|
@ -2,6 +2,7 @@ syntax = "proto3";
|
|||
|
||||
package protobuf_unittest;
|
||||
|
||||
option csharp_namespace = "Google.Protobuf.TestProtos";
|
||||
option java_multiple_files = true;
|
||||
option java_package = "com.google.protobuf.test";
|
||||
|
||||
|
@ -17,6 +18,8 @@ import "google/protobuf/type.proto";
|
|||
import "google/protobuf/wrappers.proto";
|
||||
|
||||
// Test that we can include all well-known types.
|
||||
// Each wrapper type is included separately, as languages
|
||||
// map handle different wrappers in different ways.
|
||||
message TestWellKnownTypes {
|
||||
google.protobuf.Any any_field = 1;
|
||||
google.protobuf.Api api_field = 2;
|
||||
|
@ -27,5 +30,83 @@ message TestWellKnownTypes {
|
|||
google.protobuf.Struct struct_field = 7;
|
||||
google.protobuf.Timestamp timestamp_field = 8;
|
||||
google.protobuf.Type type_field = 9;
|
||||
google.protobuf.Int32Value int32_field = 10;
|
||||
google.protobuf.DoubleValue double_field = 10;
|
||||
google.protobuf.FloatValue float_field = 11;
|
||||
google.protobuf.Int64Value int64_field = 12;
|
||||
google.protobuf.UInt64Value uint64_field = 13;
|
||||
google.protobuf.Int32Value int32_field = 14;
|
||||
google.protobuf.UInt32Value uint32_field = 15;
|
||||
google.protobuf.BoolValue bool_field = 16;
|
||||
google.protobuf.StringValue string_field = 17;
|
||||
google.protobuf.BytesValue bytes_field = 18;
|
||||
}
|
||||
|
||||
// A repeated field for each well-known type.
|
||||
message RepeatedWellKnownTypes {
|
||||
repeated google.protobuf.Any any_field = 1;
|
||||
repeated google.protobuf.Api api_field = 2;
|
||||
repeated google.protobuf.Duration duration_field = 3;
|
||||
repeated google.protobuf.Empty empty_field = 4;
|
||||
repeated google.protobuf.FieldMask field_mask_field = 5;
|
||||
repeated google.protobuf.SourceContext source_context_field = 6;
|
||||
repeated google.protobuf.Struct struct_field = 7;
|
||||
repeated google.protobuf.Timestamp timestamp_field = 8;
|
||||
repeated google.protobuf.Type type_field = 9;
|
||||
// These don't actually make a lot of sense, but they're not prohibited...
|
||||
repeated google.protobuf.DoubleValue double_field = 10;
|
||||
repeated google.protobuf.FloatValue float_field = 11;
|
||||
repeated google.protobuf.Int64Value int64_field = 12;
|
||||
repeated google.protobuf.UInt64Value uint64_field = 13;
|
||||
repeated google.protobuf.Int32Value int32_field = 14;
|
||||
repeated google.protobuf.UInt32Value uint32_field = 15;
|
||||
repeated google.protobuf.BoolValue bool_field = 16;
|
||||
repeated google.protobuf.StringValue string_field = 17;
|
||||
repeated google.protobuf.BytesValue bytes_field = 18;
|
||||
}
|
||||
|
||||
message OneofWellKnownTypes {
|
||||
oneof oneof_field {
|
||||
google.protobuf.Any any_field = 1;
|
||||
google.protobuf.Api api_field = 2;
|
||||
google.protobuf.Duration duration_field = 3;
|
||||
google.protobuf.Empty empty_field = 4;
|
||||
google.protobuf.FieldMask field_mask_field = 5;
|
||||
google.protobuf.SourceContext source_context_field = 6;
|
||||
google.protobuf.Struct struct_field = 7;
|
||||
google.protobuf.Timestamp timestamp_field = 8;
|
||||
google.protobuf.Type type_field = 9;
|
||||
google.protobuf.DoubleValue double_field = 10;
|
||||
google.protobuf.FloatValue float_field = 11;
|
||||
google.protobuf.Int64Value int64_field = 12;
|
||||
google.protobuf.UInt64Value uint64_field = 13;
|
||||
google.protobuf.Int32Value int32_field = 14;
|
||||
google.protobuf.UInt32Value uint32_field = 15;
|
||||
google.protobuf.BoolValue bool_field = 16;
|
||||
google.protobuf.StringValue string_field = 17;
|
||||
google.protobuf.BytesValue bytes_field = 18;
|
||||
}
|
||||
}
|
||||
|
||||
// A map field for each well-known type. We only
|
||||
// need to worry about the value part of the map being the
|
||||
// well-known types, as messages can't be map keys.
|
||||
message MapWellKnownTypes {
|
||||
map<int32,google.protobuf.Any> any_field = 1;
|
||||
map<int32,google.protobuf.Api> api_field = 2;
|
||||
map<int32,google.protobuf.Duration> duration_field = 3;
|
||||
map<int32,google.protobuf.Empty> empty_field = 4;
|
||||
map<int32,google.protobuf.FieldMask> field_mask_field = 5;
|
||||
map<int32,google.protobuf.SourceContext> source_context_field = 6;
|
||||
map<int32,google.protobuf.Struct> struct_field = 7;
|
||||
map<int32,google.protobuf.Timestamp> timestamp_field = 8;
|
||||
map<int32,google.protobuf.Type> type_field = 9;
|
||||
map<int32,google.protobuf.DoubleValue> double_field = 10;
|
||||
map<int32,google.protobuf.FloatValue> float_field = 11;
|
||||
map<int32,google.protobuf.Int64Value> int64_field = 12;
|
||||
map<int32,google.protobuf.UInt64Value> uint64_field = 13;
|
||||
map<int32,google.protobuf.Int32Value> int32_field = 14;
|
||||
map<int32,google.protobuf.UInt32Value> uint32_field = 15;
|
||||
map<int32,google.protobuf.BoolValue> bool_field = 16;
|
||||
map<int32,google.protobuf.StringValue> string_field = 17;
|
||||
map<int32,google.protobuf.BytesValue> bytes_field = 18;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue