Commit 6b01539d authored by Jon Skeet's avatar Jon Skeet

Merge pull request #543 from jskeet/proto3-map

Proto3 map support for C#
parents 68a4ee26 286edc0f
......@@ -19,6 +19,7 @@ set(libprotoc_files
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_field_base.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_generator.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_helpers.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_map_field.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_message.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_message_field.cc
${protobuf_source_dir}/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc
......
......@@ -43,10 +43,12 @@ $PROTOC -Isrc --csharp_out=csharp/src/ProtocolBuffers/DescriptorProtos \
rm src/google/protobuf/descriptor_proto_file.proto
$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
$PROTOC -Icsharp/protos/extest --csharp_out=csharp/src/ProtocolBuffers.Test/TestProtos \
csharp/protos/extest/unittest_issues.proto
......
......@@ -155,7 +155,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (Id != 0) hash ^= Id.GetHashCode();
if (Email.Length != 0) hash ^= Email.GetHashCode();
......@@ -200,6 +200,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
return size;
}
public void MergeFrom(Person other) {
if (other == null) {
return;
......@@ -329,7 +330,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Number.Length != 0) hash ^= Number.GetHashCode();
if (Type != global::Google.ProtocolBuffers.Examples.AddressBook.Person.Types.PhoneType.HOME) hash ^= Type.GetHashCode();
return hash;
......@@ -356,6 +357,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
return size;
}
public void MergeFrom(PhoneNumber other) {
if (other == null) {
return;
......@@ -456,7 +458,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= person_.GetHashCode();
return hash;
}
......@@ -477,6 +479,7 @@ namespace Google.ProtocolBuffers.Examples.AddressBook {
}
return size;
}
public void MergeFrom(AddressBook other) {
if (other == null) {
return;
......
#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.Generic;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
namespace Google.Protobuf.Collections
{
/// <summary>
/// Tests for MapField which aren't reliant on the encoded format -
/// tests for serialization/deserialization are part of GeneratedMessageTest.
/// </summary>
public class MapFieldTest
{
// Protobuf-specific tests
[Test]
public void Freeze_FreezesMessages()
{
var message = new ForeignMessage { C = 20 };
var map = new MapField<string, ForeignMessage> { { "x", message } };
map.Freeze();
Assert.IsTrue(message.IsFrozen);
}
[Test]
public void Freeze_PreventsMutation()
{
var map = new MapField<string, string>();
map.Freeze();
Assert.IsTrue(map.IsFrozen);
Assert.IsTrue(map.IsReadOnly);
ICollection<KeyValuePair<string, string>> collection = map;
Assert.Throws<InvalidOperationException>(() => map["x"] = "y");
Assert.Throws<InvalidOperationException>(() => map.Add("x", "y"));
Assert.Throws<InvalidOperationException>(() => map.Remove("x"));
Assert.Throws<InvalidOperationException>(() => map.Clear());
Assert.Throws<InvalidOperationException>(() => collection.Add(NewKeyValuePair("x", "y")));
Assert.Throws<InvalidOperationException>(() => collection.Remove(NewKeyValuePair("x", "y")));
}
[Test]
public void Clone_ReturnsNonFrozen()
{
var map = new MapField<string, string>();
map.Freeze();
var clone = map.Clone();
clone.Add("x", "y");
}
[Test]
public void Clone_ClonesMessages()
{
var message = new ForeignMessage { C = 20 };
var map = new MapField<string, ForeignMessage> { { "x", message } };
var clone = map.Clone();
map["x"].C = 30;
Assert.AreEqual(20, clone["x"].C);
}
[Test]
public void Add_ForbidsNullKeys()
{
var map = new MapField<string, ForeignMessage>();
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()
{
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);
CollectionAssert.AreEqual(new[] { "v1", "v3", "v4" }, map.Values);
}
[Test]
public void EqualityIsOrderInsensitive()
{
var map1 = new MapField<string, string>();
map1.Add("a", "v1");
map1.Add("b", "v2");
var map2 = new MapField<string, string>();
map2.Add("b", "v2");
map2.Add("a", "v1");
EqualityTester.AssertEquality(map1, map2);
}
[Test]
public void EqualityIsKeySensitive()
{
var map1 = new MapField<string, string>();
map1.Add("first key", "v1");
map1.Add("second key", "v2");
var map2 = new MapField<string, string>();
map2.Add("third key", "v1");
map2.Add("fourth key", "v2");
EqualityTester.AssertInequality(map1, map2);
}
[Test]
public void EqualityIsValueSensitive()
{
// 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>();
map1.Add("a", "first value");
map1.Add("b", "second value");
var map2 = new MapField<string, string>();
map2.Add("a", "third value");
map2.Add("b", "fourth value");
EqualityTester.AssertInequality(map1, map2);
}
[Test]
public void EqualityHandlesNullValues()
{
var map1 = new MapField<string, ForeignMessage>();
map1.Add("a", new ForeignMessage { C = 10 });
map1.Add("b", null);
var map2 = new MapField<string, ForeignMessage>();
map2.Add("a", new ForeignMessage { C = 10 });
map2.Add("b", null);
EqualityTester.AssertEquality(map1, map2);
// Check the null value isn't ignored entirely...
Assert.IsTrue(map1.Remove("b"));
EqualityTester.AssertInequality(map1, map2);
map1.Add("b", new ForeignMessage());
EqualityTester.AssertInequality(map1, map2);
map1["b"] = null;
EqualityTester.AssertEquality(map1, map2);
}
[Test]
public void Add_Dictionary()
{
var map1 = new MapField<string, string>
{
{ "x", "y" },
{ "a", "b" }
};
var map2 = new MapField<string, string>
{
{ "before", "" },
map1,
{ "after", "" }
};
var expected = new MapField<string, string>
{
{ "before", "" },
{ "x", "y" },
{ "a", "b" },
{ "after", "" }
};
Assert.AreEqual(expected, map2);
CollectionAssert.AreEqual(new[] { "before", "x", "a", "after" }, map2.Keys);
}
// General IDictionary<TKey, TValue> behavior tests
[Test]
public void Add_KeyAlreadyExists()
{
var map = new MapField<string, string>();
map.Add("foo", "bar");
Assert.Throws<ArgumentException>(() => map.Add("foo", "baz"));
}
[Test]
public void Add_Pair()
{
var map = new MapField<string, string>();
ICollection<KeyValuePair<string, string>> collection = map;
collection.Add(NewKeyValuePair("x", "y"));
Assert.AreEqual("y", map["x"]);
Assert.Throws<ArgumentException>(() => collection.Add(NewKeyValuePair("x", "z")));
}
[Test]
public void Contains_Pair()
{
var map = new MapField<string, string> { { "x", "y" } };
ICollection<KeyValuePair<string, string>> collection = map;
Assert.IsTrue(collection.Contains(NewKeyValuePair("x", "y")));
Assert.IsFalse(collection.Contains(NewKeyValuePair("x", "z")));
Assert.IsFalse(collection.Contains(NewKeyValuePair("z", "y")));
}
[Test]
public void Remove_Key()
{
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);
Assert.IsTrue(map.Remove("foo"));
Assert.AreEqual(0, map.Count);
}
[Test]
public void Remove_Pair()
{
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")));
Assert.AreEqual(1, map.Count);
Assert.IsFalse(collection.Remove(NewKeyValuePair("foo", "wrong value")));
Assert.AreEqual(1, map.Count);
Assert.IsTrue(collection.Remove(NewKeyValuePair("foo", "bar")));
Assert.AreEqual(0, map.Count);
Assert.Throws<ArgumentException>(() => collection.Remove(new KeyValuePair<string, string>(null, "")));
}
[Test]
public void CopyTo_Pair()
{
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);
Assert.AreEqual(NewKeyValuePair("foo", "bar"), array[1]);
}
[Test]
public void Clear()
{
var map = new MapField<string, string> { { "x", "y" } };
Assert.AreEqual(1, map.Count);
map.Clear();
Assert.AreEqual(0, map.Count);
map.Add("x", "y");
Assert.AreEqual(1, map.Count);
}
[Test]
public void Indexer_Get()
{
var map = new MapField<string, string> { { "x", "y" } };
Assert.AreEqual("y", map["x"]);
Assert.Throws<KeyNotFoundException>(() => { var ignored = map["z"]; });
}
[Test]
public void Indexer_Set()
{
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"]);
}
private static KeyValuePair<TKey, TValue> NewKeyValuePair<TKey, TValue>(TKey key, TValue value)
{
return new KeyValuePair<TKey, TValue>(key, value);
}
}
}
using System;
using System.Collections.Generic;
using Google.Protobuf.Collections;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
namespace Google.Protobuf
namespace Google.Protobuf.Collections
{
public class RepeatedFieldTest
{
......
#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.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
namespace Google.Protobuf
{
/// <summary>
/// Helper methods when testing equality. NUnit's Assert.AreEqual and
/// Assert.AreNotEqual methods try to be clever with collections, which can
/// be annoying...
/// </summary>
internal static class EqualityTester
{
public static void AssertEquality<T>(T first, T second) where T : IEquatable<T>
{
Assert.IsTrue(first.Equals(second));
Assert.AreEqual(first.GetHashCode(), second.GetHashCode());
}
public static void AssertInequality<T>(T first, T second) where T : IEquatable<T>
{
Assert.IsFalse(first.Equals(second));
// While this isn't a requirement, the chances of this test failing due to
// coincidence rather than a bug are very small.
Assert.AreNotEqual(first.GetHashCode(), second.GetHashCode());
}
}
}
#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.Collections.Generic;
using System.IO;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
namespace Google.Protobuf
{
public class FieldCodecTest
{
private static readonly List<ICodecTestData> Codecs = new List<ICodecTestData>
{
new FieldCodecTestData<bool>(FieldCodec.ForBool(100), true, "Bool"),
new FieldCodecTestData<string>(FieldCodec.ForString(100), "sample", "String"),
new FieldCodecTestData<ByteString>(FieldCodec.ForBytes(100), ByteString.CopyFrom(1, 2, 3), "Bytes"),
new FieldCodecTestData<int>(FieldCodec.ForInt32(100), -1000, "Int32"),
new FieldCodecTestData<int>(FieldCodec.ForSInt32(100), -1000, "SInt32"),
new FieldCodecTestData<int>(FieldCodec.ForSFixed32(100), -1000, "SFixed32"),
new FieldCodecTestData<uint>(FieldCodec.ForUInt32(100), 1234, "UInt32"),
new FieldCodecTestData<uint>(FieldCodec.ForFixed32(100), 1234, "Fixed32"),
new FieldCodecTestData<long>(FieldCodec.ForInt64(100), -1000, "Int64"),
new FieldCodecTestData<long>(FieldCodec.ForSInt64(100), -1000, "SInt64"),
new FieldCodecTestData<long>(FieldCodec.ForSFixed64(100), -1000, "SFixed64"),
new FieldCodecTestData<ulong>(FieldCodec.ForUInt64(100), 1234, "UInt64"),
new FieldCodecTestData<ulong>(FieldCodec.ForFixed64(100), 1234, "Fixed64"),
new FieldCodecTestData<float>(FieldCodec.ForFloat(100), 1234.5f, "Float"),
new FieldCodecTestData<double>(FieldCodec.ForDouble(100), 1234567890.5d, "Double"),
new FieldCodecTestData<ForeignEnum>(
FieldCodec.ForEnum(100, t => (int) t, t => (ForeignEnum) t), ForeignEnum.FOREIGN_BAZ, "Enum"),
new FieldCodecTestData<ForeignMessage>(
FieldCodec.ForMessage(100, ForeignMessage.Parser), new ForeignMessage { C = 10 }, "Message"),
};
[Test, TestCaseSource("Codecs")]
public void RoundTrip(ICodecTestData codec)
{
codec.TestRoundTrip();
}
[Test, TestCaseSource("Codecs")]
public void CalculateSize(ICodecTestData codec)
{
codec.TestCalculateSize();
}
[Test, TestCaseSource("Codecs")]
public void DefaultValue(ICodecTestData codec)
{
codec.TestDefaultValue();
}
public interface ICodecTestData
{
void TestRoundTrip();
void TestCalculateSize();
void TestDefaultValue();
}
public class FieldCodecTestData<T> : ICodecTestData
{
private readonly FieldCodec<T> codec;
private readonly T sampleValue;
private readonly string name;
public FieldCodecTestData(FieldCodec<T> codec, T sampleValue, string name)
{
this.codec = codec;
this.sampleValue = sampleValue;
this.name = name;
}
public void TestRoundTrip()
{
var stream = new MemoryStream();
var codedOutput = CodedOutputStream.CreateInstance(stream);
codec.Write(codedOutput, sampleValue);
codedOutput.Flush();
stream.Position = 0;
var codedInput = CodedInputStream.CreateInstance(stream);
uint tag;
Assert.IsTrue(codedInput.ReadTag(out tag));
Assert.AreEqual(codec.Tag, tag);
Assert.AreEqual(sampleValue, codec.Read(codedInput));
Assert.IsTrue(codedInput.IsAtEnd);
}
public void TestCalculateSize()
{
var stream = new MemoryStream();
var codedOutput = CodedOutputStream.CreateInstance(stream);
codec.Write(codedOutput, sampleValue);
codedOutput.Flush();
Assert.AreEqual(stream.Position, codec.CalculateSize(sampleValue));
}
public void TestDefaultValue()
{
var stream = new MemoryStream();
var codedOutput = CodedOutputStream.CreateInstance(stream);
codec.Write(codedOutput, codec.DefaultValue);
codedOutput.Flush();
Assert.AreEqual(0, stream.Position);
Assert.AreEqual(0, codec.CalculateSize(codec.DefaultValue));
if (typeof(T).IsValueType)
{
Assert.AreEqual(default(T), codec.DefaultValue);
}
}
public string Description { get { return name; } }
public override string ToString()
{
return name;
}
}
}
}
using System;
using System.IO;
using Google.Protobuf.TestProtos;
using NUnit.Framework;
......@@ -9,6 +10,15 @@ namespace Google.Protobuf
/// </summary>
public class GeneratedMessageTest
{
[Test]
public void EmptyMessageFieldDistinctFromMissingMessageField()
{
// This demonstrates what we're really interested in...
var message1 = new TestAllTypes { SingleForeignMessage = new ForeignMessage() };
var message2 = new TestAllTypes(); // SingleForeignMessage is null
EqualityTester.AssertInequality(message1, message2);
}
[Test]
public void DefaultValues()
{
......@@ -146,6 +156,206 @@ namespace Google.Protobuf
Assert.AreEqual(message, parsed);
}
// Note that not every map within map_unittest_proto3 is used. They all go through very
// similar code paths. The fact that all maps are present is validation that we have codecs
// for every type.
[Test]
public void RoundTrip_Maps()
{
var message = new TestMap
{
MapBoolBool = {
{ false, true },
{ true, false }
},
MapInt32Bytes = {
{ 5, ByteString.CopyFrom(6, 7, 8) },
{ 25, ByteString.CopyFrom(1, 2, 3, 4, 5) },
{ 10, ByteString.Empty }
},
MapInt32ForeignMessage = {
{ 0, new ForeignMessage { C = 10 } },
{ 5, null },
},
MapInt32Enum = {
{ 1, MapEnum.MAP_ENUM_BAR },
{ 2000, MapEnum.MAP_ENUM_FOO }
}
};
byte[] bytes = message.ToByteArray();
TestMap parsed = TestMap.Parser.ParseFrom(bytes);
Assert.AreEqual(message, parsed);
}
[Test]
public void MapWithEmptyEntry()
{
var message = new TestMap
{
MapInt32Bytes = { { 0, ByteString.Empty } }
};
byte[] bytes = message.ToByteArray();
Assert.AreEqual(2, bytes.Length); // Tag for field entry (1 byte), length of entry (0; 1 byte)
var parsed = TestMap.Parser.ParseFrom(bytes);
Assert.AreEqual(1, parsed.MapInt32Bytes.Count);
Assert.AreEqual(ByteString.Empty, parsed.MapInt32Bytes[0]);
}
[Test]
public void MapWithOnlyValue()
{
// Hand-craft the stream to contain a single entry with just a value.
var memoryStream = new MemoryStream();
var output = CodedOutputStream.CreateInstance(memoryStream);
output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited);
var nestedMessage = new ForeignMessage { C = 20 };
// Size of the entry (tag, size written by WriteMessage, data written by WriteMessage)
output.WriteRawVarint32((uint)(nestedMessage.CalculateSize() + 3));
output.WriteTag(2, WireFormat.WireType.LengthDelimited);
output.WriteMessage(nestedMessage);
output.Flush();
var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]);
}
[Test]
public void MapIgnoresExtraFieldsWithinEntryMessages()
{
// Hand-craft the stream to contain a single entry with three fields
var memoryStream = new MemoryStream();
var output = CodedOutputStream.CreateInstance(memoryStream);
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
var key = 10; // Field 1
var value = 20; // Field 2
var extra = 30; // Field 3
// Each field can be represented in a single byte, with a single byte tag.
// Total message size: 6 bytes.
output.WriteRawVarint32(6);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.WriteTag(2, WireFormat.WireType.Varint);
output.WriteInt32(value);
output.WriteTag(3, WireFormat.WireType.Varint);
output.WriteInt32(extra);
output.Flush();
var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
Assert.AreEqual(value, parsed.MapInt32Int32[key]);
}
[Test]
public void MapFieldOrderIsIrrelevant()
{
var memoryStream = new MemoryStream();
var output = CodedOutputStream.CreateInstance(memoryStream);
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
var key = 10;
var value = 20;
// Each field can be represented in a single byte, with a single byte tag.
// Total message size: 4 bytes.
output.WriteRawVarint32(4);
output.WriteTag(2, WireFormat.WireType.Varint);
output.WriteInt32(value);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.Flush();
var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
Assert.AreEqual(value, parsed.MapInt32Int32[key]);
}
[Test]
public void MapNonContiguousEntries()
{
var memoryStream = new MemoryStream();
var output = CodedOutputStream.CreateInstance(memoryStream);
// Message structure:
// Entry for MapInt32Int32
// Entry for MapStringString
// Entry for MapInt32Int32
// First entry
var key1 = 10;
var value1 = 20;
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key1);
output.WriteTag(2, WireFormat.WireType.Varint);
output.WriteInt32(value1);
// Second entry
var key2 = "a";
var value2 = "b";
output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(6); // 3 bytes per entry: tag, size, character
output.WriteTag(1, WireFormat.WireType.LengthDelimited);
output.WriteString(key2);
output.WriteTag(2, WireFormat.WireType.LengthDelimited);
output.WriteString(value2);
// Third entry
var key3 = 15;
var value3 = 25;
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key3);
output.WriteTag(2, WireFormat.WireType.Varint);
output.WriteInt32(value3);
output.Flush();
var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
var expected = new TestMap
{
MapInt32Int32 = { { key1, value1 }, { key3, value3 } },
MapStringString = { { key2, value2 } }
};
Assert.AreEqual(expected, parsed);
}
[Test]
public void DuplicateKeys_LastEntryWins()
{
var memoryStream = new MemoryStream();
var output = CodedOutputStream.CreateInstance(memoryStream);
var key = 10;
var value1 = 20;
var value2 = 30;
// First entry
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.WriteTag(2, WireFormat.WireType.Varint);
output.WriteInt32(value1);
// Second entry - same key, different value
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.WriteTag(2, WireFormat.WireType.Varint);
output.WriteInt32(value2);
output.Flush();
var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
Assert.AreEqual(value2, parsed.MapInt32Int32[key]);
}
[Test]
public void CloneSingleNonMessageValues()
{
......
......@@ -74,8 +74,12 @@
<Compile Include="ByteStringTest.cs" />
<Compile Include="CodedInputStreamTest.cs" />
<Compile Include="CodedOutputStreamTest.cs" />
<Compile Include="EqualityTester.cs" />
<Compile Include="FieldCodecTest.cs" />
<Compile Include="GeneratedMessageTest.cs" />
<Compile Include="RepeatedFieldTest.cs" />
<Compile Include="Collections\MapFieldTest.cs" />
<Compile Include="Collections\RepeatedFieldTest.cs" />
<Compile Include="TestProtos\MapUnittestProto3.cs" />
<Compile Include="TestProtos\UnittestImportProto3.cs" />
<Compile Include="TestProtos\UnittestImportPublicProto3.cs" />
<Compile Include="TestProtos\UnittestIssues.cs" />
......@@ -99,9 +103,7 @@
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<ItemGroup>
<Folder Include="Collections\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -120,7 +120,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (D != 0) hash ^= D.GetHashCode();
return hash;
}
......@@ -139,6 +139,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(ImportMessage other) {
if (other == null) {
return;
......
......@@ -105,7 +105,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (E != 0) hash ^= E.GetHashCode();
return hash;
}
......@@ -124,6 +124,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(PublicImportMessage other) {
if (other == null) {
return;
......
......@@ -168,7 +168,7 @@ namespace UnitTest.Issues.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Value != global::UnitTest.Issues.TestProtos.NegativeEnum.NEGATIVE_ENUM_ZERO) hash ^= Value.GetHashCode();
hash ^= values_.GetHashCode();
hash ^= packedValues_.GetHashCode();
......@@ -212,6 +212,7 @@ namespace UnitTest.Issues.TestProtos {
}
return size;
}
public void MergeFrom(NegativeEnumMessage other) {
if (other == null) {
return;
......@@ -303,7 +304,7 @@ namespace UnitTest.Issues.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -314,6 +315,7 @@ namespace UnitTest.Issues.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(DeprecatedChild other) {
if (other == null) {
return;
......@@ -456,7 +458,7 @@ namespace UnitTest.Issues.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (PrimitiveValue != 0) hash ^= PrimitiveValue.GetHashCode();
hash ^= primitiveArray_.GetHashCode();
if (messageValue_ != null) hash ^= MessageValue.GetHashCode();
......@@ -527,6 +529,7 @@ namespace UnitTest.Issues.TestProtos {
}
return size;
}
public void MergeFrom(DeprecatedFieldsMessage other) {
if (other == null) {
return;
......@@ -655,7 +658,7 @@ namespace UnitTest.Issues.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Item != 0) hash ^= Item.GetHashCode();
return hash;
}
......@@ -674,6 +677,7 @@ namespace UnitTest.Issues.TestProtos {
}
return size;
}
public void MergeFrom(ItemField other) {
if (other == null) {
return;
......
......@@ -995,7 +995,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (SingleInt32 != 0) hash ^= SingleInt32.GetHashCode();
if (SingleInt64 != 0L) hash ^= SingleInt64.GetHashCode();
if (SingleUint32 != 0) hash ^= SingleUint32.GetHashCode();
......@@ -1472,6 +1472,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestAllTypes other) {
if (other == null) {
return;
......@@ -1905,7 +1906,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Bb != 0) hash ^= Bb.GetHashCode();
return hash;
}
......@@ -1924,6 +1925,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(NestedMessage other) {
if (other == null) {
return;
......@@ -2043,7 +2045,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (child_ != null) hash ^= Child.GetHashCode();
if (payload_ != null) hash ^= Payload.GetHashCode();
hash ^= repeatedChild_.GetHashCode();
......@@ -2080,6 +2082,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(NestedTestAllTypes other) {
if (other == null) {
return;
......@@ -2196,7 +2199,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (DeprecatedInt32 != 0) hash ^= DeprecatedInt32.GetHashCode();
return hash;
}
......@@ -2215,6 +2218,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestDeprecatedFields other) {
if (other == null) {
return;
......@@ -2306,7 +2310,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (C != 0) hash ^= C.GetHashCode();
return hash;
}
......@@ -2325,6 +2329,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(ForeignMessage other) {
if (other == null) {
return;
......@@ -2404,7 +2409,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -2415,6 +2420,7 @@ namespace Google.Protobuf.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(TestReservedFields other) {
if (other == null) {
return;
......@@ -2500,7 +2506,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (foreignNested_ != null) hash ^= ForeignNested.GetHashCode();
return hash;
}
......@@ -2519,6 +2525,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestForeignNested other) {
if (other == null) {
return;
......@@ -2628,7 +2635,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (A != 0) hash ^= A.GetHashCode();
if (Bb != 0) hash ^= Bb.GetHashCode();
return hash;
......@@ -2655,6 +2662,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestReallyLargeTagNumber other) {
if (other == null) {
return;
......@@ -2766,7 +2774,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (a_ != null) hash ^= A.GetHashCode();
if (I != 0) hash ^= I.GetHashCode();
return hash;
......@@ -2793,6 +2801,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestRecursiveMessage other) {
if (other == null) {
return;
......@@ -2898,7 +2907,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (bb_ != null) hash ^= Bb.GetHashCode();
return hash;
}
......@@ -2917,6 +2926,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestMutualRecursionA other) {
if (other == null) {
return;
......@@ -3027,7 +3037,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (a_ != null) hash ^= A.GetHashCode();
if (OptionalInt32 != 0) hash ^= OptionalInt32.GetHashCode();
return hash;
......@@ -3054,6 +3064,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestMutualRecursionB other) {
if (other == null) {
return;
......@@ -3231,7 +3242,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (PrimitiveField != 0) hash ^= PrimitiveField.GetHashCode();
if (StringField.Length != 0) hash ^= StringField.GetHashCode();
if (EnumField != global::Google.Protobuf.TestProtos.ForeignEnum.FOREIGN_UNSPECIFIED) hash ^= EnumField.GetHashCode();
......@@ -3322,6 +3333,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestCamelCaseFieldNames other) {
if (other == null) {
return;
......@@ -3499,7 +3511,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (MyString.Length != 0) hash ^= MyString.GetHashCode();
if (MyInt != 0L) hash ^= MyInt.GetHashCode();
if (MyFloat != 0F) hash ^= MyFloat.GetHashCode();
......@@ -3542,6 +3554,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestFieldOrderings other) {
if (other == null) {
return;
......@@ -3673,7 +3686,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Oo != 0L) hash ^= Oo.GetHashCode();
if (Bb != 0) hash ^= Bb.GetHashCode();
return hash;
......@@ -3700,6 +3713,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(NestedMessage other) {
if (other == null) {
return;
......@@ -3803,7 +3817,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (SparseEnum != global::Google.Protobuf.TestProtos.TestSparseEnum.TEST_SPARSE_ENUM_UNSPECIFIED) hash ^= SparseEnum.GetHashCode();
return hash;
}
......@@ -3822,6 +3836,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(SparseEnumMessage other) {
if (other == null) {
return;
......@@ -3913,7 +3928,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data.Length != 0) hash ^= Data.GetHashCode();
return hash;
}
......@@ -3932,6 +3947,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(OneString other) {
if (other == null) {
return;
......@@ -4020,7 +4036,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= data_.GetHashCode();
return hash;
}
......@@ -4043,6 +4059,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(MoreString other) {
if (other == null) {
return;
......@@ -4132,7 +4149,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data.Length != 0) hash ^= Data.GetHashCode();
return hash;
}
......@@ -4151,6 +4168,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(OneBytes other) {
if (other == null) {
return;
......@@ -4242,7 +4260,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data.Length != 0) hash ^= Data.GetHashCode();
return hash;
}
......@@ -4261,6 +4279,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(MoreBytes other) {
if (other == null) {
return;
......@@ -4352,7 +4371,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data != 0) hash ^= Data.GetHashCode();
return hash;
}
......@@ -4371,6 +4390,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(Int32Message other) {
if (other == null) {
return;
......@@ -4462,7 +4482,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data != 0) hash ^= Data.GetHashCode();
return hash;
}
......@@ -4481,6 +4501,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(Uint32Message other) {
if (other == null) {
return;
......@@ -4572,7 +4593,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data != 0L) hash ^= Data.GetHashCode();
return hash;
}
......@@ -4591,6 +4612,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(Int64Message other) {
if (other == null) {
return;
......@@ -4682,7 +4704,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data != 0UL) hash ^= Data.GetHashCode();
return hash;
}
......@@ -4701,6 +4723,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(Uint64Message other) {
if (other == null) {
return;
......@@ -4792,7 +4815,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Data != false) hash ^= Data.GetHashCode();
return hash;
}
......@@ -4811,6 +4834,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(BoolMessage other) {
if (other == null) {
return;
......@@ -4954,7 +4978,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (fooCase_ == FooOneofCase.FooInt) hash ^= FooInt.GetHashCode();
if (fooCase_ == FooOneofCase.FooString) hash ^= FooString.GetHashCode();
if (fooCase_ == FooOneofCase.FooMessage) hash ^= FooMessage.GetHashCode();
......@@ -4989,6 +5013,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestOneof other) {
if (other == null) {
return;
......@@ -5216,7 +5241,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= packedInt32_.GetHashCode();
hash ^= packedInt64_.GetHashCode();
hash ^= packedUint32_.GetHashCode();
......@@ -5395,6 +5420,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestPackedTypes other) {
if (other == null) {
return;
......@@ -5677,7 +5703,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= unpackedInt32_.GetHashCode();
hash ^= unpackedInt64_.GetHashCode();
hash ^= unpackedUint32_.GetHashCode();
......@@ -5842,6 +5868,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestUnpackedTypes other) {
if (other == null) {
return;
......@@ -6052,7 +6079,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= repeatedFixed32_.GetHashCode();
hash ^= repeatedInt32_.GetHashCode();
hash ^= repeatedFixed64_.GetHashCode();
......@@ -6135,6 +6162,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestRepeatedScalarDifferentTagSizes other) {
if (other == null) {
return;
......@@ -6255,7 +6283,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (A.Length != 0) hash ^= A.GetHashCode();
return hash;
}
......@@ -6274,6 +6302,7 @@ namespace Google.Protobuf.TestProtos {
}
return size;
}
public void MergeFrom(TestCommentInjectionMessage other) {
if (other == null) {
return;
......@@ -6353,7 +6382,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -6364,6 +6393,7 @@ namespace Google.Protobuf.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(FooRequest other) {
if (other == null) {
return;
......@@ -6436,7 +6466,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -6447,6 +6477,7 @@ namespace Google.Protobuf.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(FooResponse other) {
if (other == null) {
return;
......@@ -6519,7 +6550,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -6530,6 +6561,7 @@ namespace Google.Protobuf.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(FooClientMessage other) {
if (other == null) {
return;
......@@ -6602,7 +6634,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -6613,6 +6645,7 @@ namespace Google.Protobuf.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(FooServerMessage other) {
if (other == null) {
return;
......@@ -6685,7 +6718,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -6696,6 +6729,7 @@ namespace Google.Protobuf.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(BarRequest other) {
if (other == null) {
return;
......@@ -6768,7 +6802,7 @@ namespace Google.Protobuf.TestProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
return hash;
}
......@@ -6779,6 +6813,7 @@ namespace Google.Protobuf.TestProtos {
int size = 0;
return size;
}
public void MergeFrom(BarResponse other) {
if (other == null) {
return;
......
......@@ -456,14 +456,16 @@ namespace Google.Protobuf
}
/// <summary>
/// Returns true if the next tag is also part of the same unpacked array.
/// Peeks at the next tag in the stream. If it matches <paramref name="tag"/>,
/// the tag is consumed and the method returns <c>true</c>; otherwise, the
/// stream is left in the original position and the method returns <c>false</c>.
/// </summary>
private bool ContinueArray(uint currentTag)
public bool MaybeConsumeTag(uint tag)
{
uint next;
if (PeekNextTag(out next))
{
if (next == currentTag)
if (next == tag)
{
hasNextTag = false;
return true;
......@@ -486,17 +488,7 @@ namespace Google.Protobuf
}
return true;
}
uint next;
if (PeekNextTag(out next))
{
if (next == currentTag)
{
hasNextTag = false;
return true;
}
}
return false;
return MaybeConsumeTag(currentTag);
}
/// <summary>
......@@ -512,7 +504,7 @@ namespace Google.Protobuf
do
{
list.Add(ReadString());
} while (ContinueArray(fieldTag));
} while (MaybeConsumeTag(fieldTag));
}
public void ReadBytesArray(ICollection<ByteString> list)
......@@ -521,7 +513,7 @@ namespace Google.Protobuf
do
{
list.Add(ReadBytes());
} while (ContinueArray(fieldTag));
} while (MaybeConsumeTag(fieldTag));
}
public void ReadBoolArray(ICollection<bool> list)
......@@ -729,7 +721,7 @@ namespace Google.Protobuf
do
{
list.Add((T)(object) ReadEnum());
} while (ContinueArray(fieldTag));
} while (MaybeConsumeTag(fieldTag));
}
}
......@@ -742,7 +734,7 @@ namespace Google.Protobuf
T message = messageParser.CreateTemplate();
ReadMessage(message);
list.Add(message);
} while (ContinueArray(fieldTag));
} while (MaybeConsumeTag(fieldTag));
}
#endregion
......
......@@ -475,6 +475,14 @@ namespace Google.Protobuf
WriteRawVarint32(WireFormat.MakeTag(fieldNumber, type));
}
/// <summary>
/// Writes an already-encoded tag.
/// </summary>
public void WriteTag(uint tag)
{
WriteRawVarint32(tag);
}
/// <summary>
/// Writes the given single-byte tag directly to the stream.
/// </summary>
......
#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 System.Collections.Generic;
using System.Linq;
namespace Google.Protobuf.Collections
{
/// <summary>
/// Representation of a map field in a Protocol Buffer message.
/// </summary>
/// <remarks>
/// This implementation preserves insertion order for simplicity of testing
/// code using maps fields. Overwriting an existing entry does not change the
/// position of that entry within the map. Equality is not order-sensitive.
/// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal"/>.
/// </remarks>
/// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
/// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IFreezable, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>
{
// TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
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>>();
public MapField<TKey, TValue> Clone()
{
var clone = new MapField<TKey, TValue>();
// Keys are never cloneable. Values might be.
if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
{
foreach (var pair in list)
{
clone.Add(pair.Key, pair.Value == null ? pair.Value : ((IDeepCloneable<TValue>) pair.Value).Clone());
}
}
else
{
// Nothing is cloneable, so we don't need to worry.
clone.Add(this);
}
return clone;
}
public void Add(TKey key, TValue value)
{
// Validation of arguments happens in ContainsKey and the indexer
if (ContainsKey(key))
{
throw new ArgumentException("Key already exists in map", "key");
}
this[key] = value;
}
public bool ContainsKey(TKey key)
{
ThrowHelper.ThrowIfNull(key, "key");
return map.ContainsKey(key);
}
public bool Remove(TKey key)
{
this.CheckMutable();
ThrowHelper.ThrowIfNull(key, "key");
LinkedListNode<KeyValuePair<TKey, TValue>> node;
if (map.TryGetValue(key, out node))
{
map.Remove(key);
node.List.Remove(node);
return true;
}
else
{
return false;
}
}
public bool TryGetValue(TKey key, out TValue value)
{
LinkedListNode<KeyValuePair<TKey, TValue>> node;
if (map.TryGetValue(key, out node))
{
value = node.Value.Value;
return true;
}
else
{
value = default(TValue);
return false;
}
}
public TValue this[TKey key]
{
get
{
ThrowHelper.ThrowIfNull(key, "key");
TValue value;
if (TryGetValue(key, out value))
{
return value;
}
throw new KeyNotFoundException();
}
set
{
ThrowHelper.ThrowIfNull(key, "key");
if (value == null && (typeof(TValue) == typeof(ByteString) || typeof(TValue) == typeof(string)))
{
ThrowHelper.ThrowIfNull(value, "value");
}
this.CheckMutable();
LinkedListNode<KeyValuePair<TKey, TValue>> node;
var pair = new KeyValuePair<TKey, TValue>(key, value);
if (map.TryGetValue(key, out node))
{
node.Value = pair;
}
else
{
node = list.AddLast(pair);
map[key] = node;
}
}
}
// TODO: Make these views?
public ICollection<TKey> Keys { get { return list.Select(t => t.Key).ToList(); } }
public ICollection<TValue> Values { get { return list.Select(t => t.Value).ToList(); } }
public void Add(IDictionary<TKey, TValue> entries)
{
ThrowHelper.ThrowIfNull(entries, "entries");
foreach (var pair in entries)
{
Add(pair.Key, pair.Value);
}
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
{
Add(item.Key, item.Value);
}
public void Clear()
{
this.CheckMutable();
list.Clear();
map.Clear();
}
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
TValue value;
return TryGetValue(item.Key, out value)
&& EqualityComparer<TValue>.Default.Equals(item.Value, value);
}
void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
list.CopyTo(array, arrayIndex);
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
this.CheckMutable();
if (item.Key == null)
{
throw new ArgumentException("Key is null", "item");
}
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);
node.List.Remove(node);
return true;
}
else
{
return false;
}
}
public int Count { get { return list.Count; } }
public bool IsReadOnly { get { return frozen; } }
public void Freeze()
{
if (IsFrozen)
{
return;
}
frozen = true;
// Only values can be frozen, as all the key types are simple.
// Everything can be done in-place, as we're just freezing objects.
if (typeof(IFreezable).IsAssignableFrom(typeof(TValue)))
{
for (var node = list.First; node != null; node = node.Next)
{
var pair = node.Value;
IFreezable freezableValue = pair.Value as IFreezable;
if (freezableValue != null)
{
freezableValue.Freeze();
}
}
}
}
public bool IsFrozen { get { return frozen; } }
public override bool Equals(object other)
{
return Equals(other as MapField<TKey, TValue>);
}
public override int GetHashCode()
{
var valueComparer = EqualityComparer<TValue>.Default;
int hash = 0;
foreach (var pair in list)
{
hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value);
}
return hash;
}
public bool Equals(MapField<TKey, TValue> other)
{
if (other == null)
{
return false;
}
if (other == this)
{
return true;
}
if (other.Count != this.Count)
{
return false;
}
var valueComparer = EqualityComparer<TValue>.Default;
foreach (var pair in this)
{
TValue value;
if (!other.TryGetValue(pair.Key, out value))
{
return false;
}
if (!valueComparer.Equals(value, pair.Value))
{
return false;
}
}
return true;
}
/// <summary>
/// Adds entries to the map from the given stream.
/// </summary>
/// <remarks>
/// It is assumed that the stream is initially positioned after the tag specified by the codec.
/// This method will continue reading entries from the stream until the end is reached, or
/// a different tag is encountered.
/// </remarks>
/// <param name="input">Stream to read from</param>
/// <param name="codec">Codec describing how the key/value pairs are encoded</param>
public void AddEntriesFrom(CodedInputStream input, Codec codec)
{
var adapter = new Codec.MessageAdapter(codec);
do
{
adapter.Reset();
input.ReadMessage(adapter);
this[adapter.Key] = adapter.Value;
} while (input.MaybeConsumeTag(codec.MapTag));
}
public void WriteTo(CodedOutputStream output, Codec codec)
{
var message = new Codec.MessageAdapter(codec);
foreach (var entry in list)
{
message.Key = entry.Key;
message.Value = entry.Value;
output.WriteTag(codec.MapTag);
output.WriteMessage(message);
}
}
public int CalculateSize(Codec codec)
{
var message = new Codec.MessageAdapter(codec);
int size = 0;
foreach (var entry in list)
{
message.Key = entry.Key;
message.Value = entry.Value;
size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
size += CodedOutputStream.ComputeMessageSize(message);
}
return size;
}
/// <summary>
/// A codec for a specific map field. This contains all the information required to encoded and
/// decode the nested messages.
/// </summary>
public sealed class Codec
{
private readonly FieldCodec<TKey> keyCodec;
private readonly FieldCodec<TValue> valueCodec;
private readonly uint mapTag;
public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCodec, uint mapTag)
{
this.keyCodec = keyCodec;
this.valueCodec = valueCodec;
this.mapTag = mapTag;
}
/// <summary>
/// The tag used in the enclosing message to indicate map entries.
/// </summary>
internal uint MapTag { get { return mapTag; } }
/// <summary>
/// A mutable message class, used for parsing and serializing. This
/// delegates the work to a codec, but implements the <see cref="IMessage"/> interface
/// for interop with <see cref="CodedInputStream"/> and <see cref="CodedOutputStream"/>.
/// This is nested inside Codec as it's tightly coupled to the associated codec,
/// and it's simpler if it has direct access to all its fields.
/// </summary>
internal class MessageAdapter : IMessage
{
private readonly Codec codec;
internal TKey Key { get; set; }
internal TValue Value { get; set; }
internal MessageAdapter(Codec codec)
{
this.codec = codec;
}
internal void Reset()
{
Key = codec.keyCodec.DefaultValue;
Value = codec.valueCodec.DefaultValue;
}
public void MergeFrom(CodedInputStream input)
{
uint tag;
while (input.ReadTag(out tag))
{
if (tag == 0)
{
throw InvalidProtocolBufferException.InvalidTag();
}
if (tag == codec.keyCodec.Tag)
{
Key = codec.keyCodec.Read(input);
}
else if (tag == codec.valueCodec.Tag)
{
Value = codec.valueCodec.Read(input);
}
else if (WireFormat.IsEndGroupTag(tag))
{
// TODO(jonskeet): Do we need this? (Given that we don't support groups...)
return;
}
}
}
public void WriteTo(CodedOutputStream output)
{
codec.keyCodec.Write(output, Key);
codec.valueCodec.Write(output, Value);
}
public int CalculateSize()
{
return codec.keyCodec.CalculateSize(Key) + codec.valueCodec.CalculateSize(Value);
}
}
}
}
}
......@@ -193,7 +193,7 @@ namespace Google.Protobuf.Collections
public override int GetHashCode()
{
int hash = 23;
int hash = 0;
for (int i = 0; i < count; i++)
{
hash = hash * 31 + array[i].GetHashCode();
......
......@@ -335,7 +335,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= file_.GetHashCode();
return hash;
}
......@@ -356,6 +356,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(FileDescriptorSet other) {
if (other == null) {
return;
......@@ -558,7 +559,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (Package.Length != 0) hash ^= Package.GetHashCode();
hash ^= dependency_.GetHashCode();
......@@ -685,6 +686,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(FileDescriptorProto other) {
if (other == null) {
return;
......@@ -938,7 +940,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
hash ^= field_.GetHashCode();
hash ^= extension_.GetHashCode();
......@@ -1047,6 +1049,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(DescriptorProto other) {
if (other == null) {
return;
......@@ -1204,7 +1207,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Start != 0) hash ^= Start.GetHashCode();
if (End != 0) hash ^= End.GetHashCode();
return hash;
......@@ -1231,6 +1234,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(ExtensionRange other) {
if (other == null) {
return;
......@@ -1341,7 +1345,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Start != 0) hash ^= Start.GetHashCode();
if (End != 0) hash ^= End.GetHashCode();
return hash;
......@@ -1368,6 +1372,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(ReservedRange other) {
if (other == null) {
return;
......@@ -1568,7 +1573,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (Number != 0) hash ^= Number.GetHashCode();
if (Label != global::Google.Protobuf.DescriptorProtos.FieldDescriptorProto.Types.Label.LABEL_OPTIONAL) hash ^= Label.GetHashCode();
......@@ -1651,6 +1656,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(FieldDescriptorProto other) {
if (other == null) {
return;
......@@ -1837,7 +1843,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
return hash;
}
......@@ -1856,6 +1862,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(OneofDescriptorProto other) {
if (other == null) {
return;
......@@ -1969,7 +1976,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
hash ^= value_.GetHashCode();
if (options_ != null) hash ^= Options.GetHashCode();
......@@ -2006,6 +2013,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(EnumDescriptorProto other) {
if (other == null) {
return;
......@@ -2140,7 +2148,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (Number != 0) hash ^= Number.GetHashCode();
if (options_ != null) hash ^= Options.GetHashCode();
......@@ -2175,6 +2183,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(EnumValueDescriptorProto other) {
if (other == null) {
return;
......@@ -2308,7 +2317,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
hash ^= method_.GetHashCode();
if (options_ != null) hash ^= Options.GetHashCode();
......@@ -2345,6 +2354,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(ServiceDescriptorProto other) {
if (other == null) {
return;
......@@ -2515,7 +2525,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Name.Length != 0) hash ^= Name.GetHashCode();
if (InputType.Length != 0) hash ^= InputType.GetHashCode();
if (OutputType.Length != 0) hash ^= OutputType.GetHashCode();
......@@ -2574,6 +2584,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(MethodDescriptorProto other) {
if (other == null) {
return;
......@@ -2871,7 +2882,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (JavaPackage.Length != 0) hash ^= JavaPackage.GetHashCode();
if (JavaOuterClassname.Length != 0) hash ^= JavaOuterClassname.GetHashCode();
if (JavaMultipleFiles != false) hash ^= JavaMultipleFiles.GetHashCode();
......@@ -3004,6 +3015,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(FileOptions other) {
if (other == null) {
return;
......@@ -3248,7 +3260,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (MessageSetWireFormat != false) hash ^= MessageSetWireFormat.GetHashCode();
if (NoStandardDescriptorAccessor != false) hash ^= NoStandardDescriptorAccessor.GetHashCode();
if (Deprecated != false) hash ^= Deprecated.GetHashCode();
......@@ -3301,6 +3313,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(MessageOptions other) {
if (other == null) {
return;
......@@ -3487,7 +3500,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Ctype != global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.CType.STRING) hash ^= Ctype.GetHashCode();
if (Packed != false) hash ^= Packed.GetHashCode();
if (Jstype != global::Google.Protobuf.DescriptorProtos.FieldOptions.Types.JSType.JS_NORMAL) hash ^= Jstype.GetHashCode();
......@@ -3556,6 +3569,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(FieldOptions other) {
if (other == null) {
return;
......@@ -3726,7 +3740,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (AllowAlias != false) hash ^= AllowAlias.GetHashCode();
if (Deprecated != false) hash ^= Deprecated.GetHashCode();
hash ^= uninterpretedOption_.GetHashCode();
......@@ -3763,6 +3777,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(EnumOptions other) {
if (other == null) {
return;
......@@ -3875,7 +3890,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Deprecated != false) hash ^= Deprecated.GetHashCode();
hash ^= uninterpretedOption_.GetHashCode();
return hash;
......@@ -3904,6 +3919,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(EnumValueOptions other) {
if (other == null) {
return;
......@@ -4009,7 +4025,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Deprecated != false) hash ^= Deprecated.GetHashCode();
hash ^= uninterpretedOption_.GetHashCode();
return hash;
......@@ -4038,6 +4054,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(ServiceOptions other) {
if (other == null) {
return;
......@@ -4143,7 +4160,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (Deprecated != false) hash ^= Deprecated.GetHashCode();
hash ^= uninterpretedOption_.GetHashCode();
return hash;
......@@ -4172,6 +4189,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(MethodOptions other) {
if (other == null) {
return;
......@@ -4337,7 +4355,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= name_.GetHashCode();
if (IdentifierValue.Length != 0) hash ^= IdentifierValue.GetHashCode();
if (PositiveIntValue != 0UL) hash ^= PositiveIntValue.GetHashCode();
......@@ -4406,6 +4424,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(UninterpretedOption other) {
if (other == null) {
return;
......@@ -4550,7 +4569,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
if (NamePart_.Length != 0) hash ^= NamePart_.GetHashCode();
if (IsExtension != false) hash ^= IsExtension.GetHashCode();
return hash;
......@@ -4577,6 +4596,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(NamePart other) {
if (other == null) {
return;
......@@ -4677,7 +4697,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= location_.GetHashCode();
return hash;
}
......@@ -4698,6 +4718,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(SourceCodeInfo other) {
if (other == null) {
return;
......@@ -4827,7 +4848,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
public override int GetHashCode() {
int hash = 0;
int hash = 1;
hash ^= path_.GetHashCode();
hash ^= span_.GetHashCode();
if (LeadingComments.Length != 0) hash ^= LeadingComments.GetHashCode();
......@@ -4892,6 +4913,7 @@ namespace Google.Protobuf.DescriptorProtos {
}
return size;
}
public void MergeFrom(Location other) {
if (other == null) {
return;
......
using System;
using System.Collections.Generic;
namespace Google.Protobuf
{
/// <summary>
/// Factory methods for <see cref="FieldCodec{T}"/>.
/// </summary>
public static class FieldCodec
{
public static FieldCodec<string> ForString(uint tag)
{
return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
}
public static FieldCodec<ByteString> ForBytes(uint tag)
{
return new FieldCodec<ByteString>(input => input.ReadBytes(), (output, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
}
public static FieldCodec<bool> ForBool(uint tag)
{
return new FieldCodec<bool>(input => input.ReadBool(), (output, value) => output.WriteBool(value), CodedOutputStream.ComputeBoolSize, tag);
}
public static FieldCodec<int> ForInt32(uint tag)
{
return new FieldCodec<int>(input => input.ReadInt32(), (output, value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
}
public static FieldCodec<int> ForSInt32(uint tag)
{
return new FieldCodec<int>(input => input.ReadSInt32(), (output, value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
}
public static FieldCodec<uint> ForFixed32(uint tag)
{
return new FieldCodec<uint>(input => input.ReadFixed32(), (output, value) => output.WriteFixed32(value), CodedOutputStream.ComputeFixed32Size, tag);
}
public static FieldCodec<int> ForSFixed32(uint tag)
{
return new FieldCodec<int>(input => input.ReadSFixed32(), (output, value) => output.WriteSFixed32(value), CodedOutputStream.ComputeSFixed32Size, tag);
}
public static FieldCodec<uint> ForUInt32(uint tag)
{
return new FieldCodec<uint>(input => input.ReadUInt32(), (output, value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
}
public static FieldCodec<long> ForInt64(uint tag)
{
return new FieldCodec<long>(input => input.ReadInt64(), (output, value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
}
public static FieldCodec<long> ForSInt64(uint tag)
{
return new FieldCodec<long>(input => input.ReadSInt64(), (output, value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
}
public static FieldCodec<ulong> ForFixed64(uint tag)
{
return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), CodedOutputStream.ComputeFixed64Size, tag);
}
public static FieldCodec<long> ForSFixed64(uint tag)
{
return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), CodedOutputStream.ComputeSFixed64Size, tag);
}
public static FieldCodec<ulong> ForUInt64(uint tag)
{
return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
}
public static FieldCodec<float> ForFloat(uint tag)
{
return new FieldCodec<float>(input => input.ReadFloat(), (output, value) => output.WriteFloat(value), CodedOutputStream.ComputeFloatSize, tag);
}
public static FieldCodec<double> ForDouble(uint tag)
{
return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.ComputeDoubleSize, tag);
}
// Enums are tricky. We can probably use expression trees to build these delegates automatically,
// but it's easy to generate the code fdor it.
public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)
{
return new FieldCodec<T>(input => fromInt32(
input.ReadEnum()),
(output, value) => output.WriteEnum(toInt32(value)),
value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag);
}
public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : IMessage<T>
{
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>
/// An encode/decode pair for a single field. This effectively encapsulates
/// all the information needed to read or write the field value from/to a coded
/// stream.
/// </summary>
/// <remarks>
/// This never writes default values to the stream, and is not currently designed
/// to play well with packed arrays.
/// </remarks>
public sealed class FieldCodec<T>
{
private static readonly Func<T, bool> IsDefault;
private static readonly T Default;
static FieldCodec()
{
if (typeof(T) == typeof(string))
{
Default = (T)(object)"";
IsDefault = CreateDefaultValueCheck<string>(x => x.Length == 0);
}
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)));
}
}
private static Func<T, bool> CreateDefaultValueCheck<TTmp>(Func<TTmp, bool> check)
{
return (Func<T, bool>)(object)check;
}
private readonly Func<CodedInputStream, T> reader;
private readonly Action<CodedOutputStream, T> writer;
private readonly Func<T, int> sizeComputer;
private readonly uint tag;
private readonly int tagSize;
internal FieldCodec(
Func<CodedInputStream, T> reader,
Action<CodedOutputStream, T> writer,
Func<T, int> sizeComputer,
uint tag)
{
this.reader = reader;
this.writer = writer;
this.sizeComputer = sizeComputer;
this.tag = tag;
tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
}
public uint Tag { get { return tag; } }
public T DefaultValue { get { return Default; } }
public void Write(CodedOutputStream output, T value)
{
if (!IsDefault(value))
{
output.WriteTag(tag);
writer(output, value);
}
}
public T Read(CodedInputStream input)
{
return reader(input);
}
public int CalculateSize(T value)
{
return IsDefault(value) ? 0 : sizeComputer(value) + CodedOutputStream.ComputeRawVarint32Size(tag);
}
}
}
......@@ -60,6 +60,7 @@
<Compile Include="CodedOutputStream.cs" />
<Compile Include="Collections\Dictionaries.cs" />
<Compile Include="Collections\Lists.cs" />
<Compile Include="Collections\MapField.cs" />
<Compile Include="Collections\ReadOnlyDictionary.cs" />
<Compile Include="Collections\RepeatedField.cs" />
<Compile Include="Collections\RepeatedFieldExtensions.cs" />
......@@ -84,6 +85,7 @@
<Compile Include="Descriptors\MethodDescriptor.cs" />
<Compile Include="Descriptors\PackageDescriptor.cs" />
<Compile Include="Descriptors\ServiceDescriptor.cs" />
<Compile Include="FieldCodec.cs" />
<Compile Include="FrameworkPortability.cs" />
<Compile Include="Freezable.cs" />
<Compile Include="MessageExtensions.cs" />
......
......@@ -425,6 +425,8 @@ libprotoc_la_SOURCES = \
google/protobuf/compiler/csharp/csharp_generator.cc \
google/protobuf/compiler/csharp/csharp_helpers.cc \
google/protobuf/compiler/csharp/csharp_helpers.h \
google/protobuf/compiler/csharp/csharp_map_field.cc \
google/protobuf/compiler/csharp/csharp_map_field.h \
google/protobuf/compiler/csharp/csharp_message.cc \
google/protobuf/compiler/csharp/csharp_message.h \
google/protobuf/compiler/csharp/csharp_message_field.cc \
......
......@@ -74,6 +74,12 @@ void EnumFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
"}\n");
}
void EnumFieldGenerator::GenerateCodecCode(io::Printer* printer) {
printer->Print(
variables_,
"pb::FieldCodec.ForEnum($tag$, x => (int) x, x => ($type_name$) x)");
}
EnumOneofFieldGenerator::EnumOneofFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal)
: PrimitiveOneofFieldGenerator(descriptor, fieldOrdinal) {
......
......@@ -46,6 +46,7 @@ class EnumFieldGenerator : public PrimitiveFieldGenerator {
EnumFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~EnumFieldGenerator();
virtual void GenerateCodecCode(io::Printer* printer);
virtual void GenerateParsingCode(io::Printer* printer);
virtual void GenerateSerializationCode(io::Printer* printer);
virtual void GenerateSerializedSizeCode(io::Printer* printer);
......
......@@ -65,6 +65,7 @@ void FieldGeneratorBase::SetCommonFieldVariables(
tag_bytes += ", " + SimpleItoa(tag_array[i]);
}
(*variables)["tag"] = SimpleItoa(tag);
(*variables)["tag_size"] = SimpleItoa(tag_size);
(*variables)["tag_bytes"] = tag_bytes;
......@@ -112,6 +113,11 @@ void FieldGeneratorBase::GenerateFreezingCode(io::Printer* printer) {
// special handling for freezing, so default to not generating any code.
}
void FieldGeneratorBase::GenerateCodecCode(io::Printer* printer) {
// No-op: expect this to be overridden by appropriate types.
// Could fail if we get called here though...
}
void FieldGeneratorBase::AddDeprecatedFlag(io::Printer* printer) {
if (descriptor_->options().deprecated())
{
......@@ -151,12 +157,16 @@ std::string FieldGeneratorBase::name() {
}
std::string FieldGeneratorBase::type_name() {
switch (descriptor_->type()) {
return type_name(descriptor_);
}
std::string FieldGeneratorBase::type_name(const FieldDescriptor* descriptor) {
switch (descriptor->type()) {
case FieldDescriptor::TYPE_ENUM:
return GetClassName(descriptor_->enum_type());
return GetClassName(descriptor->enum_type());
case FieldDescriptor::TYPE_MESSAGE:
case FieldDescriptor::TYPE_GROUP:
return GetClassName(descriptor_->message_type());
return GetClassName(descriptor->message_type());
case FieldDescriptor::TYPE_DOUBLE:
return "double";
case FieldDescriptor::TYPE_FLOAT:
......
......@@ -49,6 +49,7 @@ class FieldGeneratorBase : public SourceGeneratorBase {
virtual void GenerateCloningCode(io::Printer* printer) = 0;
virtual void GenerateFreezingCode(io::Printer* printer);
virtual void GenerateCodecCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer) = 0;
virtual void GenerateMergingCode(io::Printer* printer) = 0;
virtual void GenerateParsingCode(io::Printer* printer) = 0;
......@@ -76,6 +77,7 @@ class FieldGeneratorBase : public SourceGeneratorBase {
std::string property_name();
std::string name();
std::string type_name();
std::string type_name(const FieldDescriptor* descriptor);
bool has_default_value();
bool is_nullable_type();
std::string default_value();
......
......@@ -46,6 +46,7 @@
#include <google/protobuf/compiler/csharp/csharp_field_base.h>
#include <google/protobuf/compiler/csharp/csharp_enum_field.h>
#include <google/protobuf/compiler/csharp/csharp_map_field.h>
#include <google/protobuf/compiler/csharp/csharp_message_field.h>
#include <google/protobuf/compiler/csharp/csharp_primitive_field.h>
#include <google/protobuf/compiler/csharp/csharp_repeated_enum_field.h>
......@@ -355,7 +356,11 @@ FieldGeneratorBase* CreateFieldGenerator(const FieldDescriptor* descriptor,
case FieldDescriptor::TYPE_GROUP:
case FieldDescriptor::TYPE_MESSAGE:
if (descriptor->is_repeated()) {
if (descriptor->is_map()) {
return new MapFieldGenerator(descriptor, fieldOrdinal);
} else {
return new RepeatedMessageFieldGenerator(descriptor, fieldOrdinal);
}
} else {
if (descriptor->containing_oneof()) {
return new MessageOneofFieldGenerator(descriptor, fieldOrdinal);
......
// 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.
#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/stubs/strutil.h>
#include <google/protobuf/compiler/csharp/csharp_helpers.h>
#include <google/protobuf/compiler/csharp/csharp_map_field.h>
namespace google {
namespace protobuf {
namespace compiler {
namespace csharp {
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal)
: FieldGeneratorBase(descriptor, fieldOrdinal) {
}
MapFieldGenerator::~MapFieldGenerator() {
}
void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
const FieldDescriptor* key_descriptor =
descriptor_->message_type()->FindFieldByName("key");
const FieldDescriptor* value_descriptor =
descriptor_->message_type()->FindFieldByName("value");
variables_["key_type_name"] = type_name(key_descriptor);
variables_["value_type_name"] = type_name(value_descriptor);
scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1));
scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
printer->Print(
variables_,
"private static readonly pbc::MapField<$key_type_name$, $value_type_name$>.Codec _map_$name$_codec\n"
" = new pbc::MapField<$key_type_name$, $value_type_name$>.Codec(");
key_generator->GenerateCodecCode(printer);
printer->Print(", ");
value_generator->GenerateCodecCode(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");
AddDeprecatedFlag(printer);
printer->Print(
variables_,
"public pbc::MapField<$key_type_name$, $value_type_name$> $property_name$ {\n"
" get { return $name$_; }\n"
"}\n");
}
void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) {
printer->Print(
variables_,
"$name$_.Add(other.$name$_);\n");
}
void MapFieldGenerator::GenerateParsingCode(io::Printer* printer) {
printer->Print(
variables_,
"$name$_.AddEntriesFrom(input, _map_$name$_codec);\n");
}
void MapFieldGenerator::GenerateSerializationCode(io::Printer* printer) {
printer->Print(
variables_,
"$name$_.WriteTo(output, _map_$name$_codec);\n");
}
void MapFieldGenerator::GenerateSerializedSizeCode(io::Printer* printer) {
printer->Print(
variables_,
"size += $name$_.CalculateSize(_map_$name$_codec);\n");
}
void MapFieldGenerator::WriteHash(io::Printer* printer) {
printer->Print(
variables_,
"hash ^= $property_name$.GetHashCode();\n");
}
void MapFieldGenerator::WriteEquals(io::Printer* printer) {
printer->Print(
variables_,
"if (!$property_name$.Equals(other.$property_name$)) return false;\n");
}
void MapFieldGenerator::WriteToString(io::Printer* printer) {
/*
variables_["field_name"] = GetFieldName(descriptor_);
printer->Print(
variables_,
"PrintField(\"$field_name$\", has$property_name$, $name$_, writer);\n");*/
}
void MapFieldGenerator::GenerateCloningCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_ = other.$name$_.Clone();\n");
}
void MapFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
printer->Print(variables_,
"$name$_.Freeze();\n");
}
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
// 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_MAP_FIELD_H__
#define GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_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 MapFieldGenerator : public FieldGeneratorBase {
public:
MapFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~MapFieldGenerator();
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateFreezingCode(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:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
};
} // namespace csharp
} // namespace compiler
} // namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CSHARP_MAP_FIELD_H__
......@@ -268,8 +268,6 @@ void MessageGenerator::Generate(io::Printer* printer) {
"}\n\n");
}
// TODO(jonskeet): Map properties
// Standard methods
GenerateFrameworkMethods(printer);
GenerateMessageSerializationMethods(printer);
......@@ -299,7 +297,6 @@ void MessageGenerator::Generate(io::Printer* printer) {
printer->Outdent();
printer->Print("}\n");
printer->Print("\n");
}
void MessageGenerator::GenerateCloningCode(io::Printer* printer) {
......@@ -408,9 +405,10 @@ void MessageGenerator::GenerateFrameworkMethods(io::Printer* printer) {
"}\n\n");
// GetHashCode
// Start with a non-zero value to easily distinguish between null and "empty" messages.
printer->Print(
"public override int GetHashCode() {\n"
" int hash = 0;\n");
" int hash = 1;\n");
printer->Indent();
for (int i = 0; i < descriptor_->field_count(); i++) {
scoped_ptr<FieldGeneratorBase> generator(
......@@ -451,7 +449,7 @@ void MessageGenerator::GenerateMessageSerializationMethods(io::Printer* printer)
}
printer->Print("return size;\n");
printer->Outdent();
printer->Print("}\n");
printer->Print("}\n\n");
}
void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
......@@ -469,7 +467,6 @@ void MessageGenerator::GenerateMergingMethods(io::Printer* printer) {
"if (other == null) {\n"
" return;\n"
"}\n");
// TODO(jonskeet): Maps?
// Merge non-oneof fields
for (int i = 0; i < descriptor_->field_count(); i++) {
if (!descriptor_->field(i)->containing_oneof()) {
......
......@@ -138,6 +138,12 @@ void MessageFieldGenerator::GenerateFreezingCode(io::Printer* printer) {
"if ($has_property_check$) $property_name$.Freeze();\n");
}
void MessageFieldGenerator::GenerateCodecCode(io::Printer* printer) {
printer->Print(
variables_,
"pb::FieldCodec.ForMessage($tag$, $type_name$.Parser)");
}
MessageOneofFieldGenerator::MessageOneofFieldGenerator(const FieldDescriptor* descriptor,
int fieldOrdinal)
: MessageFieldGenerator(descriptor, fieldOrdinal) {
......
......@@ -46,6 +46,7 @@ class MessageFieldGenerator : public FieldGeneratorBase {
MessageFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~MessageFieldGenerator();
virtual void GenerateCodecCode(io::Printer* printer);
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateFreezingCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
......
......@@ -155,6 +155,12 @@ void PrimitiveFieldGenerator::GenerateCloningCode(io::Printer* printer) {
"$name$_ = other.$name$_;\n");
}
void PrimitiveFieldGenerator::GenerateCodecCode(io::Printer* printer) {
printer->Print(
variables_,
"pb::FieldCodec.For$capitalized_type_name$($tag$)");
}
PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
const FieldDescriptor* descriptor, int fieldOrdinal)
: PrimitiveFieldGenerator(descriptor, fieldOrdinal) {
......
......@@ -46,6 +46,7 @@ class PrimitiveFieldGenerator : public FieldGeneratorBase {
PrimitiveFieldGenerator(const FieldDescriptor* descriptor, int fieldOrdinal);
~PrimitiveFieldGenerator();
virtual void GenerateCodecCode(io::Printer* printer);
virtual void GenerateCloningCode(io::Printer* printer);
virtual void GenerateMembers(io::Printer* printer);
virtual void GenerateMergingCode(io::Printer* printer);
......
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// This file is mostly equivalent to map_unittest.proto, but imports
// unittest_proto3.proto instead of unittest.proto, so that it only
// uses proto3 messages. This makes it suitable for testing
// implementations which only support proto3.
// The TestRequiredMessageMap message has been removed as there are no
// required fields in proto3.
syntax = "proto3";
option cc_enable_arenas = true;
option csharp_namespace = "Google.Protobuf.TestProtos";
import "google/protobuf/unittest_proto3.proto";
// We don't put this in a package within proto2 because we need to make sure
// that the generated code doesn't depend on being in the proto2 namespace.
// In map_test_util.h we do "using namespace unittest = protobuf_unittest".
package protobuf_unittest;
// Tests maps.
message TestMap {
map<int32 , int32 > map_int32_int32 = 1;
map<int64 , int64 > map_int64_int64 = 2;
map<uint32 , uint32 > map_uint32_uint32 = 3;
map<uint64 , uint64 > map_uint64_uint64 = 4;
map<sint32 , sint32 > map_sint32_sint32 = 5;
map<sint64 , sint64 > map_sint64_sint64 = 6;
map<fixed32 , fixed32 > map_fixed32_fixed32 = 7;
map<fixed64 , fixed64 > map_fixed64_fixed64 = 8;
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
map<int32 , float > map_int32_float = 11;
map<int32 , double > map_int32_double = 12;
map<bool , bool > map_bool_bool = 13;
map<string , string > map_string_string = 14;
map<int32 , bytes > map_int32_bytes = 15;
map<int32 , MapEnum > map_int32_enum = 16;
map<int32 , ForeignMessage> map_int32_foreign_message = 17;
}
message TestMapSubmessage {
TestMap test_map = 1;
}
message TestMessageMap {
map<int32, TestAllTypes> map_int32_message = 1;
}
// Two map fields share the same entry default instance.
message TestSameTypeMap {
map<int32, int32> map1 = 1;
map<int32, int32> map2 = 2;
}
enum MapEnum {
MAP_ENUM_FOO = 0;
MAP_ENUM_BAR = 1;
MAP_ENUM_BAZ = 2;
}
message TestArenaMap {
map<int32 , int32 > map_int32_int32 = 1;
map<int64 , int64 > map_int64_int64 = 2;
map<uint32 , uint32 > map_uint32_uint32 = 3;
map<uint64 , uint64 > map_uint64_uint64 = 4;
map<sint32 , sint32 > map_sint32_sint32 = 5;
map<sint64 , sint64 > map_sint64_sint64 = 6;
map<fixed32 , fixed32 > map_fixed32_fixed32 = 7;
map<fixed64 , fixed64 > map_fixed64_fixed64 = 8;
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 9;
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 10;
map<int32 , float > map_int32_float = 11;
map<int32 , double > map_int32_double = 12;
map<bool , bool > map_bool_bool = 13;
map<int32 , MapEnum > map_int32_enum = 14;
map<int32 , ForeignMessage> map_int32_foreign_message = 15;
}
// Previously, message containing enum called Type cannot be used as value of
// map field.
message MessageContainingEnumCalledType {
enum Type {
TYPE_FOO = 0;
}
map<int32, MessageContainingEnumCalledType> type = 1;
}
// Previously, message cannot contain map field called "entry".
message MessageContainingMapCalledEntry {
map<int32, int32> entry = 1;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment