Commit 9e4f354f authored by Jon Skeet's avatar Jon Skeet

Prohibit null values in map fields

On deserialization, missing values for message types
are replaced with a "default" message.
parent 5700a105
...@@ -56,7 +56,7 @@ namespace Google.Protobuf.Collections ...@@ -56,7 +56,7 @@ namespace Google.Protobuf.Collections
} }
[Test] [Test]
public void NullValues() public void NullValuesProhibited()
{ {
TestNullValues<int?>(0); TestNullValues<int?>(0);
TestNullValues(""); TestNullValues("");
...@@ -65,19 +65,12 @@ namespace Google.Protobuf.Collections ...@@ -65,19 +65,12 @@ namespace Google.Protobuf.Collections
private void TestNullValues<T>(T nonNullValue) private void TestNullValues<T>(T nonNullValue)
{ {
var map = new MapField<int, T>(false); var map = new MapField<int, T>();
var nullValue = (T) (object) null; var nullValue = (T) (object) null;
Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue)); Assert.Throws<ArgumentNullException>(() => map.Add(0, nullValue));
Assert.Throws<ArgumentNullException>(() => map[0] = nullValue); Assert.Throws<ArgumentNullException>(() => map[0] = nullValue);
map.Add(1, nonNullValue); map.Add(1, nonNullValue);
map[1] = nonNullValue; map[1] = nonNullValue;
// Doesn't throw...
map = new MapField<int, T>(true);
map.Add(0, nullValue);
map[0] = nullValue;
map.Add(1, nonNullValue);
map[1] = nonNullValue;
} }
[Test] [Test]
...@@ -160,27 +153,6 @@ namespace Google.Protobuf.Collections ...@@ -160,27 +153,6 @@ namespace Google.Protobuf.Collections
EqualityTester.AssertInequality(map1, map2); 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] [Test]
public void Add_Dictionary() public void Add_Dictionary()
{ {
...@@ -453,30 +425,6 @@ namespace Google.Protobuf.Collections ...@@ -453,30 +425,6 @@ namespace Google.Protobuf.Collections
Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null); Assert.Throws<ArgumentNullException>(() => dictionary["x"] = null);
} }
[Test]
public void AllowNullValues_Property()
{
// Non-message reference type values are non-nullable by default, but can be overridden
Assert.IsFalse(new MapField<int, string>().AllowsNullValues);
Assert.IsFalse(new MapField<int, string>(false).AllowsNullValues);
Assert.IsTrue(new MapField<int, string>(true).AllowsNullValues);
// Non-nullable value type values are never nullable
Assert.IsFalse(new MapField<int, int>().AllowsNullValues);
Assert.IsFalse(new MapField<int, int>(false).AllowsNullValues);
Assert.Throws<ArgumentException>(() => new MapField<int, int>(true));
// Message type values are nullable by default, but can be overridden
Assert.IsTrue(new MapField<int, TestAllTypes>().AllowsNullValues);
Assert.IsFalse(new MapField<int, TestAllTypes>(false).AllowsNullValues);
Assert.IsTrue(new MapField<int, TestAllTypes>(true).AllowsNullValues);
// Nullable value type values are nullable by default, but can be overridden
Assert.IsTrue(new MapField<int, int?>().AllowsNullValues);
Assert.IsFalse(new MapField<int, int?>(false).AllowsNullValues);
Assert.IsTrue(new MapField<int, int?>(true).AllowsNullValues);
}
[Test] [Test]
public void KeysReturnsLiveView() public void KeysReturnsLiveView()
{ {
......
...@@ -221,7 +221,7 @@ namespace Google.Protobuf ...@@ -221,7 +221,7 @@ namespace Google.Protobuf
}, },
MapInt32ForeignMessage = { MapInt32ForeignMessage = {
{ 0, new ForeignMessage { C = 10 } }, { 0, new ForeignMessage { C = 10 } },
{ 5, null }, { 5, new ForeignMessage() },
}, },
MapInt32Enum = { MapInt32Enum = {
{ 1, MapEnum.MAP_ENUM_BAR }, { 1, MapEnum.MAP_ENUM_BAR },
...@@ -268,6 +268,40 @@ namespace Google.Protobuf ...@@ -268,6 +268,40 @@ namespace Google.Protobuf
Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]); Assert.AreEqual(nestedMessage, parsed.MapInt32ForeignMessage[0]);
} }
[Test]
public void MapWithOnlyKey_PrimitiveValue()
{
// Hand-craft the stream to contain a single entry with just a key.
var memoryStream = new MemoryStream();
var output = new CodedOutputStream(memoryStream);
output.WriteTag(TestMap.MapInt32DoubleFieldNumber, WireFormat.WireType.LengthDelimited);
int key = 10;
output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key));
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.Flush();
var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
Assert.AreEqual(0.0, parsed.MapInt32Double[key]);
}
[Test]
public void MapWithOnlyKey_MessageValue()
{
// Hand-craft the stream to contain a single entry with just a key.
var memoryStream = new MemoryStream();
var output = new CodedOutputStream(memoryStream);
output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited);
int key = 10;
output.WriteLength(1 + CodedOutputStream.ComputeInt32Size(key));
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.Flush();
var parsed = TestMap.Parser.ParseFrom(memoryStream.ToArray());
Assert.AreEqual(new ForeignMessage(), parsed.MapInt32ForeignMessage[key]);
}
[Test] [Test]
public void MapIgnoresExtraFieldsWithinEntryMessages() public void MapIgnoresExtraFieldsWithinEntryMessages()
{ {
......
...@@ -195,13 +195,6 @@ namespace Google.Protobuf ...@@ -195,13 +195,6 @@ namespace Google.Protobuf
AssertJson("{ 'repeatedForeignEnum': [ ] }", JsonFormatter.Default.Format(message)); AssertJson("{ 'repeatedForeignEnum': [ ] }", JsonFormatter.Default.Format(message));
} }
[Test]
public void NullValueForMessage()
{
var message = new TestMap { MapInt32ForeignMessage = { { 10, null } } };
AssertJson("{ 'mapInt32ForeignMessage': { '10': null } }", JsonFormatter.Default.Format(message));
}
[Test] [Test]
[TestCase("a\u17b4b", "a\\u17b4b")] // Explicit [TestCase("a\u17b4b", "a\\u17b4b")] // Explicit
[TestCase("a\u0601b", "a\\u0601b")] // Ranged [TestCase("a\u0601b", "a\\u0601b")] // Ranged
......
...@@ -2080,7 +2080,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2080,7 +2080,7 @@ namespace Google.Protobuf.TestProtos {
public const int DoubleFieldFieldNumber = 10; public const int DoubleFieldFieldNumber = 10;
private static readonly pbc::MapField<int, double?>.Codec _map_doubleField_codec private static readonly pbc::MapField<int, double?>.Codec _map_doubleField_codec
= new pbc::MapField<int, double?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<double>(18), 82); = new pbc::MapField<int, double?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<double>(18), 82);
private readonly pbc::MapField<int, double?> doubleField_ = new pbc::MapField<int, double?>(true); private readonly pbc::MapField<int, double?> doubleField_ = new pbc::MapField<int, double?>();
public pbc::MapField<int, double?> DoubleField { public pbc::MapField<int, double?> DoubleField {
get { return doubleField_; } get { return doubleField_; }
} }
...@@ -2089,7 +2089,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2089,7 +2089,7 @@ namespace Google.Protobuf.TestProtos {
public const int FloatFieldFieldNumber = 11; public const int FloatFieldFieldNumber = 11;
private static readonly pbc::MapField<int, float?>.Codec _map_floatField_codec private static readonly pbc::MapField<int, float?>.Codec _map_floatField_codec
= new pbc::MapField<int, float?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<float>(18), 90); = new pbc::MapField<int, float?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<float>(18), 90);
private readonly pbc::MapField<int, float?> floatField_ = new pbc::MapField<int, float?>(true); private readonly pbc::MapField<int, float?> floatField_ = new pbc::MapField<int, float?>();
public pbc::MapField<int, float?> FloatField { public pbc::MapField<int, float?> FloatField {
get { return floatField_; } get { return floatField_; }
} }
...@@ -2098,7 +2098,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2098,7 +2098,7 @@ namespace Google.Protobuf.TestProtos {
public const int Int64FieldFieldNumber = 12; public const int Int64FieldFieldNumber = 12;
private static readonly pbc::MapField<int, long?>.Codec _map_int64Field_codec private static readonly pbc::MapField<int, long?>.Codec _map_int64Field_codec
= new pbc::MapField<int, long?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<long>(18), 98); = new pbc::MapField<int, long?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<long>(18), 98);
private readonly pbc::MapField<int, long?> int64Field_ = new pbc::MapField<int, long?>(true); private readonly pbc::MapField<int, long?> int64Field_ = new pbc::MapField<int, long?>();
public pbc::MapField<int, long?> Int64Field { public pbc::MapField<int, long?> Int64Field {
get { return int64Field_; } get { return int64Field_; }
} }
...@@ -2107,7 +2107,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2107,7 +2107,7 @@ namespace Google.Protobuf.TestProtos {
public const int Uint64FieldFieldNumber = 13; public const int Uint64FieldFieldNumber = 13;
private static readonly pbc::MapField<int, ulong?>.Codec _map_uint64Field_codec private static readonly pbc::MapField<int, ulong?>.Codec _map_uint64Field_codec
= new pbc::MapField<int, ulong?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<ulong>(18), 106); = new pbc::MapField<int, ulong?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<ulong>(18), 106);
private readonly pbc::MapField<int, ulong?> uint64Field_ = new pbc::MapField<int, ulong?>(true); private readonly pbc::MapField<int, ulong?> uint64Field_ = new pbc::MapField<int, ulong?>();
public pbc::MapField<int, ulong?> Uint64Field { public pbc::MapField<int, ulong?> Uint64Field {
get { return uint64Field_; } get { return uint64Field_; }
} }
...@@ -2116,7 +2116,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2116,7 +2116,7 @@ namespace Google.Protobuf.TestProtos {
public const int Int32FieldFieldNumber = 14; public const int Int32FieldFieldNumber = 14;
private static readonly pbc::MapField<int, int?>.Codec _map_int32Field_codec private static readonly pbc::MapField<int, int?>.Codec _map_int32Field_codec
= new pbc::MapField<int, int?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<int>(18), 114); = new pbc::MapField<int, int?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<int>(18), 114);
private readonly pbc::MapField<int, int?> int32Field_ = new pbc::MapField<int, int?>(true); private readonly pbc::MapField<int, int?> int32Field_ = new pbc::MapField<int, int?>();
public pbc::MapField<int, int?> Int32Field { public pbc::MapField<int, int?> Int32Field {
get { return int32Field_; } get { return int32Field_; }
} }
...@@ -2125,7 +2125,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2125,7 +2125,7 @@ namespace Google.Protobuf.TestProtos {
public const int Uint32FieldFieldNumber = 15; public const int Uint32FieldFieldNumber = 15;
private static readonly pbc::MapField<int, uint?>.Codec _map_uint32Field_codec private static readonly pbc::MapField<int, uint?>.Codec _map_uint32Field_codec
= new pbc::MapField<int, uint?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<uint>(18), 122); = new pbc::MapField<int, uint?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<uint>(18), 122);
private readonly pbc::MapField<int, uint?> uint32Field_ = new pbc::MapField<int, uint?>(true); private readonly pbc::MapField<int, uint?> uint32Field_ = new pbc::MapField<int, uint?>();
public pbc::MapField<int, uint?> Uint32Field { public pbc::MapField<int, uint?> Uint32Field {
get { return uint32Field_; } get { return uint32Field_; }
} }
...@@ -2134,7 +2134,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2134,7 +2134,7 @@ namespace Google.Protobuf.TestProtos {
public const int BoolFieldFieldNumber = 16; public const int BoolFieldFieldNumber = 16;
private static readonly pbc::MapField<int, bool?>.Codec _map_boolField_codec private static readonly pbc::MapField<int, bool?>.Codec _map_boolField_codec
= new pbc::MapField<int, bool?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<bool>(18), 130); = new pbc::MapField<int, bool?>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForStructWrapper<bool>(18), 130);
private readonly pbc::MapField<int, bool?> boolField_ = new pbc::MapField<int, bool?>(true); private readonly pbc::MapField<int, bool?> boolField_ = new pbc::MapField<int, bool?>();
public pbc::MapField<int, bool?> BoolField { public pbc::MapField<int, bool?> BoolField {
get { return boolField_; } get { return boolField_; }
} }
...@@ -2143,7 +2143,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2143,7 +2143,7 @@ namespace Google.Protobuf.TestProtos {
public const int StringFieldFieldNumber = 17; public const int StringFieldFieldNumber = 17;
private static readonly pbc::MapField<int, string>.Codec _map_stringField_codec private static readonly pbc::MapField<int, string>.Codec _map_stringField_codec
= new pbc::MapField<int, string>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<string>(18), 138); = new pbc::MapField<int, string>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<string>(18), 138);
private readonly pbc::MapField<int, string> stringField_ = new pbc::MapField<int, string>(true); private readonly pbc::MapField<int, string> stringField_ = new pbc::MapField<int, string>();
public pbc::MapField<int, string> StringField { public pbc::MapField<int, string> StringField {
get { return stringField_; } get { return stringField_; }
} }
...@@ -2152,7 +2152,7 @@ namespace Google.Protobuf.TestProtos { ...@@ -2152,7 +2152,7 @@ namespace Google.Protobuf.TestProtos {
public const int BytesFieldFieldNumber = 18; public const int BytesFieldFieldNumber = 18;
private static readonly pbc::MapField<int, pb::ByteString>.Codec _map_bytesField_codec private static readonly pbc::MapField<int, pb::ByteString>.Codec _map_bytesField_codec
= new pbc::MapField<int, pb::ByteString>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<pb::ByteString>(18), 146); = new pbc::MapField<int, pb::ByteString>.Codec(pb::FieldCodec.ForInt32(8), pb::FieldCodec.ForClassWrapper<pb::ByteString>(18), 146);
private readonly pbc::MapField<int, pb::ByteString> bytesField_ = new pbc::MapField<int, pb::ByteString>(true); private readonly pbc::MapField<int, pb::ByteString> bytesField_ = new pbc::MapField<int, pb::ByteString>();
public pbc::MapField<int, pb::ByteString> BytesField { public pbc::MapField<int, pb::ByteString> BytesField {
get { return bytesField_; } get { return bytesField_; }
} }
......
...@@ -151,6 +151,8 @@ namespace Google.Protobuf.WellKnownTypes ...@@ -151,6 +151,8 @@ namespace Google.Protobuf.WellKnownTypes
[Test] [Test]
public void MapWrappersSerializeDeserialize() public void MapWrappersSerializeDeserialize()
{ {
// Note: no null values here, as they are prohibited in map fields
// (despite being representable).
var message = new MapWellKnownTypes var message = new MapWellKnownTypes
{ {
BoolField = { { 10, false }, { 20, true } }, BoolField = { { 10, false }, { 20, true } },
...@@ -158,13 +160,12 @@ namespace Google.Protobuf.WellKnownTypes ...@@ -158,13 +160,12 @@ namespace Google.Protobuf.WellKnownTypes
{ -1, ByteString.CopyFrom(1, 2, 3) }, { -1, ByteString.CopyFrom(1, 2, 3) },
{ 10, ByteString.CopyFrom(4, 5, 6) }, { 10, ByteString.CopyFrom(4, 5, 6) },
{ 1000, ByteString.Empty }, { 1000, ByteString.Empty },
{ 10000, null }
}, },
DoubleField = { { 1, 12.5 }, { 10, -1.5 }, { 20, 0d } }, DoubleField = { { 1, 12.5 }, { 10, -1.5 }, { 20, 0d } },
FloatField = { { 2, 123.25f }, { 3, -20f }, { 4, 0f } }, FloatField = { { 2, 123.25f }, { 3, -20f }, { 4, 0f } },
Int32Field = { { 5, int.MaxValue }, { 6, int.MinValue }, { 7, 0 } }, Int32Field = { { 5, int.MaxValue }, { 6, int.MinValue }, { 7, 0 } },
Int64Field = { { 8, long.MaxValue }, { 9, long.MinValue }, { 10, 0L } }, Int64Field = { { 8, long.MaxValue }, { 9, long.MinValue }, { 10, 0L } },
StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" }, { 14, null } }, StringField = { { 11, "First" }, { 12, "Second" }, { 13, "" } },
Uint32Field = { { 15, uint.MaxValue }, { 16, uint.MinValue }, { 17, 0U } }, Uint32Field = { { 15, uint.MaxValue }, { 16, uint.MinValue }, { 17, 0U } },
Uint64Field = { { 18, ulong.MaxValue }, { 19, ulong.MinValue }, { 20, 0UL } }, Uint64Field = { { 18, ulong.MaxValue }, { 19, ulong.MinValue }, { 20, 0UL } },
}; };
...@@ -224,13 +225,11 @@ namespace Google.Protobuf.WellKnownTypes ...@@ -224,13 +225,11 @@ namespace Google.Protobuf.WellKnownTypes
[Test] [Test]
public void Reflection_MapFields() public void Reflection_MapFields()
{ {
// Just a single example... note that we can't have a null value here // Just a single example... note that we can't have a null value here despite the value type being int?
var message = new MapWellKnownTypes { Int32Field = { { 1, 2 }, { 3, null } } }; var message = new MapWellKnownTypes { Int32Field = { { 1, 2 } } };
var fields = MapWellKnownTypes.Descriptor.Fields; var fields = MapWellKnownTypes.Descriptor.Fields;
var dictionary = (IDictionary) fields[MapWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message); var dictionary = (IDictionary) fields[MapWellKnownTypes.Int32FieldFieldNumber].Accessor.GetValue(message);
Assert.AreEqual(2, dictionary[1]); Assert.AreEqual(2, dictionary[1]);
Assert.IsNull(dictionary[3]);
Assert.IsTrue(dictionary.Contains(3));
} }
[Test] [Test]
......
...@@ -53,6 +53,13 @@ namespace Google.Protobuf.Collections ...@@ -53,6 +53,13 @@ namespace Google.Protobuf.Collections
/// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />. /// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
/// </para> /// </para>
/// <para> /// <para>
/// Null values are not permitted in the map, either for wrapper types or regular messages.
/// If a map is deserialized from a data stream and the value is missing from an entry, a default value
/// is created instead. For primitive types, that is the regular default value (0, the empty string and so
/// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
/// encoded value for the field.
/// </para>
/// <para>
/// This implementation does not generally prohibit the use of key/value types which are not /// This implementation does not generally prohibit the use of key/value types which are not
/// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
/// that all operations will work in such cases. /// that all operations will work in such cases.
...@@ -61,34 +68,10 @@ namespace Google.Protobuf.Collections ...@@ -61,34 +68,10 @@ namespace Google.Protobuf.Collections
public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
{ {
// TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.) // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
private readonly bool allowNullValues;
private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map = private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(); new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>(); private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
/// <summary>
/// Constructs a new map field, defaulting the value nullability to only allow null values for message types
/// and non-nullable value types.
/// </summary>
public MapField() : this(typeof(IMessage).IsAssignableFrom(typeof(TValue)) || Nullable.GetUnderlyingType(typeof(TValue)) != null)
{
}
/// <summary>
/// Constructs a new map field, overriding the choice of whether null values are permitted in the map.
/// This is used by wrapper types, where maps with string and bytes wrappers as the value types
/// support null values.
/// </summary>
/// <param name="allowNullValues">Whether null values are permitted in the map or not.</param>
public MapField(bool allowNullValues)
{
if (allowNullValues && typeof(TValue).IsValueType() && Nullable.GetUnderlyingType(typeof(TValue)) == null)
{
throw new ArgumentException("allowNullValues", "Non-nullable value types do not support null values");
}
this.allowNullValues = allowNullValues;
}
/// <summary> /// <summary>
/// Creates a deep clone of this object. /// Creates a deep clone of this object.
/// </summary> /// </summary>
...@@ -97,13 +80,13 @@ namespace Google.Protobuf.Collections ...@@ -97,13 +80,13 @@ namespace Google.Protobuf.Collections
/// </returns> /// </returns>
public MapField<TKey, TValue> Clone() public MapField<TKey, TValue> Clone()
{ {
var clone = new MapField<TKey, TValue>(allowNullValues); var clone = new MapField<TKey, TValue>();
// Keys are never cloneable. Values might be. // Keys are never cloneable. Values might be.
if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue))) if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
{ {
foreach (var pair in list) foreach (var pair in list)
{ {
clone.Add(pair.Key, pair.Value == null ? pair.Value : ((IDeepCloneable<TValue>)pair.Value).Clone()); clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());
} }
} }
else else
...@@ -217,7 +200,7 @@ namespace Google.Protobuf.Collections ...@@ -217,7 +200,7 @@ namespace Google.Protobuf.Collections
{ {
Preconditions.CheckNotNullUnconstrained(key, "key"); Preconditions.CheckNotNullUnconstrained(key, "key");
// value == null check here is redundant, but avoids boxing. // value == null check here is redundant, but avoids boxing.
if (value == null && !allowNullValues) if (value == null)
{ {
Preconditions.CheckNotNullUnconstrained(value, "value"); Preconditions.CheckNotNullUnconstrained(value, "value");
} }
...@@ -246,7 +229,7 @@ namespace Google.Protobuf.Collections ...@@ -246,7 +229,7 @@ namespace Google.Protobuf.Collections
public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } } public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
/// <summary> /// <summary>
/// Adds the specified entries to the map. /// Adds the specified entries to the map. The keys and values are not automatically cloned.
/// </summary> /// </summary>
/// <param name="entries">The entries to add to the map.</param> /// <param name="entries">The entries to add to the map.</param>
public void Add(IDictionary<TKey, TValue> entries) public void Add(IDictionary<TKey, TValue> entries)
...@@ -346,11 +329,6 @@ namespace Google.Protobuf.Collections ...@@ -346,11 +329,6 @@ namespace Google.Protobuf.Collections
} }
} }
/// <summary>
/// Returns whether or not this map allows values to be null.
/// </summary>
public bool AllowsNullValues { get { return allowNullValues; } }
/// <summary> /// <summary>
/// Gets the number of elements contained in the map. /// Gets the number of elements contained in the map.
/// </summary> /// </summary>
...@@ -632,6 +610,8 @@ namespace Google.Protobuf.Collections ...@@ -632,6 +610,8 @@ namespace Google.Protobuf.Collections
/// </summary> /// </summary>
internal class MessageAdapter : IMessage internal class MessageAdapter : IMessage
{ {
private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 };
private readonly Codec codec; private readonly Codec codec;
internal TKey Key { get; set; } internal TKey Key { get; set; }
internal TValue Value { get; set; } internal TValue Value { get; set; }
...@@ -665,6 +645,13 @@ namespace Google.Protobuf.Collections ...@@ -665,6 +645,13 @@ namespace Google.Protobuf.Collections
input.SkipLastField(); input.SkipLastField();
} }
} }
// Corner case: a map entry with a key but no value, where the value type is a message.
// Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
if (Value == null)
{
Value = codec.valueCodec.Read(new CodedInputStream(ZeroLengthMessageStreamData));
}
} }
public void WriteTo(CodedOutputStream output) public void WriteTo(CodedOutputStream output)
......
...@@ -61,8 +61,8 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -61,8 +61,8 @@ namespace Google.Protobuf.WellKnownTypes {
/// ///
/// If the embedded message type is well-known and has a custom JSON /// If the embedded message type is well-known and has a custom JSON
/// representation, that representation will be embedded adding a field /// representation, that representation will be embedded adding a field
/// `value` which holds the custom JSON in addition to the the `@type` /// `value` which holds the custom JSON in addition to the `@type`
/// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]): /// field. Example (for message [google.protobuf.Duration][]):
/// ///
/// { /// {
/// "@type": "type.googleapis.com/google.protobuf.Duration", /// "@type": "type.googleapis.com/google.protobuf.Duration",
...@@ -110,7 +110,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -110,7 +110,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// * If no schema is provided, `https` is assumed. /// * If no schema is provided, `https` is assumed.
/// * The last segment of the URL's path must represent the fully /// * The last segment of the URL's path must represent the fully
/// qualified name of the type (as in `path/google.protobuf.Duration`). /// qualified name of the type (as in `path/google.protobuf.Duration`).
/// * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type] /// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
/// value in binary format, or produce an error. /// value in binary format, or produce an error.
/// * Applications are allowed to cache lookup results based on the /// * Applications are allowed to cache lookup results based on the
/// URL, or have them precompiled into a binary to avoid any /// URL, or have them precompiled into a binary to avoid any
......
...@@ -653,7 +653,6 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -653,7 +653,6 @@ namespace Google.Protobuf.WellKnownTypes {
/// ///
/// package google.storage.v2; /// package google.storage.v2;
/// service Storage { /// service Storage {
/// // (-- see AccessControl.GetAcl --)
/// rpc GetAcl(GetAclRequest) returns (Acl); /// rpc GetAcl(GetAclRequest) returns (Acl);
/// ///
/// // Get a data record. /// // Get a data record.
......
...@@ -24,9 +24,9 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -24,9 +24,9 @@ namespace Google.Protobuf.WellKnownTypes {
byte[] descriptorData = global::System.Convert.FromBase64String( byte[] descriptorData = global::System.Convert.FromBase64String(
string.Concat( string.Concat(
"Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1", "Chtnb29nbGUvcHJvdG9idWYvZW1wdHkucHJvdG8SD2dvb2dsZS5wcm90b2J1",
"ZiIHCgVFbXB0eUJNChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv", "ZiIHCgVFbXB0eUJQChNjb20uZ29vZ2xlLnByb3RvYnVmQgpFbXB0eVByb3Rv",
"UAGgAQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNi", "UAGgAQH4AQGiAgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlw",
"BnByb3RvMw==")); "ZXNiBnByb3RvMw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { }, new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
......
...@@ -69,7 +69,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -69,7 +69,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// z: 8 /// z: 8
/// ///
/// The result will not contain specific values for fields x,y and z /// The result will not contain specific values for fields x,y and z
/// (there value will be set to the default, and omitted in proto text /// (their value will be set to the default, and omitted in proto text
/// output): /// output):
/// ///
/// f { /// f {
......
...@@ -25,9 +25,9 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -25,9 +25,9 @@ namespace Google.Protobuf.WellKnownTypes {
string.Concat( string.Concat(
"Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv", "Ch9nb29nbGUvcHJvdG9idWYvdGltZXN0YW1wLnByb3RvEg9nb29nbGUucHJv",
"dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY", "dG9idWYiKwoJVGltZXN0YW1wEg8KB3NlY29uZHMYASABKAMSDQoFbmFub3MY",
"AiABKAVCUQoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q", "AiABKAVCVAoTY29tLmdvb2dsZS5wcm90b2J1ZkIOVGltZXN0YW1wUHJvdG9Q",
"AaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBlc2IG", "AaABAfgBAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25vd25UeXBl",
"cHJvdG8z")); "c2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { }, new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
......
...@@ -30,38 +30,39 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -30,38 +30,39 @@ namespace Google.Protobuf.WellKnownTypes {
"b2ZzGAMgAygJEigKB29wdGlvbnMYBCADKAsyFy5nb29nbGUucHJvdG9idWYu", "b2ZzGAMgAygJEigKB29wdGlvbnMYBCADKAsyFy5nb29nbGUucHJvdG9idWYu",
"T3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAUgASgLMh4uZ29vZ2xlLnByb3Rv", "T3B0aW9uEjYKDnNvdXJjZV9jb250ZXh0GAUgASgLMh4uZ29vZ2xlLnByb3Rv",
"YnVmLlNvdXJjZUNvbnRleHQSJwoGc3ludGF4GAYgASgOMhcuZ29vZ2xlLnBy", "YnVmLlNvdXJjZUNvbnRleHQSJwoGc3ludGF4GAYgASgOMhcuZ29vZ2xlLnBy",
"b3RvYnVmLlN5bnRheCK+BQoFRmllbGQSKQoEa2luZBgBIAEoDjIbLmdvb2ds", "b3RvYnVmLlN5bnRheCLVBQoFRmllbGQSKQoEa2luZBgBIAEoDjIbLmdvb2ds",
"ZS5wcm90b2J1Zi5GaWVsZC5LaW5kEjcKC2NhcmRpbmFsaXR5GAIgASgOMiIu", "ZS5wcm90b2J1Zi5GaWVsZC5LaW5kEjcKC2NhcmRpbmFsaXR5GAIgASgOMiIu",
"Z29vZ2xlLnByb3RvYnVmLkZpZWxkLkNhcmRpbmFsaXR5Eg4KBm51bWJlchgD", "Z29vZ2xlLnByb3RvYnVmLkZpZWxkLkNhcmRpbmFsaXR5Eg4KBm51bWJlchgD",
"IAEoBRIMCgRuYW1lGAQgASgJEhAKCHR5cGVfdXJsGAYgASgJEhMKC29uZW9m", "IAEoBRIMCgRuYW1lGAQgASgJEhAKCHR5cGVfdXJsGAYgASgJEhMKC29uZW9m",
"X2luZGV4GAcgASgFEg4KBnBhY2tlZBgIIAEoCBIoCgdvcHRpb25zGAkgAygL", "X2luZGV4GAcgASgFEg4KBnBhY2tlZBgIIAEoCBIoCgdvcHRpb25zGAkgAygL",
"MhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhIRCglqc29uX25hbWUYCiABKAki", "MhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhIRCglqc29uX25hbWUYCiABKAkS",
"yAIKBEtpbmQSEAoMVFlQRV9VTktOT1dOEAASDwoLVFlQRV9ET1VCTEUQARIO", "FQoNZGVmYXVsdF92YWx1ZRgLIAEoCSLIAgoES2luZBIQCgxUWVBFX1VOS05P",
"CgpUWVBFX0ZMT0FUEAISDgoKVFlQRV9JTlQ2NBADEg8KC1RZUEVfVUlOVDY0", "V04QABIPCgtUWVBFX0RPVUJMRRABEg4KClRZUEVfRkxPQVQQAhIOCgpUWVBF",
"EAQSDgoKVFlQRV9JTlQzMhAFEhAKDFRZUEVfRklYRUQ2NBAGEhAKDFRZUEVf", "X0lOVDY0EAMSDwoLVFlQRV9VSU5UNjQQBBIOCgpUWVBFX0lOVDMyEAUSEAoM",
"RklYRUQzMhAHEg0KCVRZUEVfQk9PTBAIEg8KC1RZUEVfU1RSSU5HEAkSDgoK", "VFlQRV9GSVhFRDY0EAYSEAoMVFlQRV9GSVhFRDMyEAcSDQoJVFlQRV9CT09M",
"VFlQRV9HUk9VUBAKEhAKDFRZUEVfTUVTU0FHRRALEg4KClRZUEVfQllURVMQ", "EAgSDwoLVFlQRV9TVFJJTkcQCRIOCgpUWVBFX0dST1VQEAoSEAoMVFlQRV9N",
"DBIPCgtUWVBFX1VJTlQzMhANEg0KCVRZUEVfRU5VTRAOEhEKDVRZUEVfU0ZJ", "RVNTQUdFEAsSDgoKVFlQRV9CWVRFUxAMEg8KC1RZUEVfVUlOVDMyEA0SDQoJ",
"WEVEMzIQDxIRCg1UWVBFX1NGSVhFRDY0EBASDwoLVFlQRV9TSU5UMzIQERIP", "VFlQRV9FTlVNEA4SEQoNVFlQRV9TRklYRUQzMhAPEhEKDVRZUEVfU0ZJWEVE",
"CgtUWVBFX1NJTlQ2NBASInQKC0NhcmRpbmFsaXR5EhcKE0NBUkRJTkFMSVRZ", "NjQQEBIPCgtUWVBFX1NJTlQzMhAREg8KC1RZUEVfU0lOVDY0EBIidAoLQ2Fy",
"X1VOS05PV04QABIYChRDQVJESU5BTElUWV9PUFRJT05BTBABEhgKFENBUkRJ", "ZGluYWxpdHkSFwoTQ0FSRElOQUxJVFlfVU5LTk9XThAAEhgKFENBUkRJTkFM",
"TkFMSVRZX1JFUVVJUkVEEAISGAoUQ0FSRElOQUxJVFlfUkVQRUFURUQQAyLO", "SVRZX09QVElPTkFMEAESGAoUQ0FSRElOQUxJVFlfUkVRVUlSRUQQAhIYChRD",
"AQoERW51bRIMCgRuYW1lGAEgASgJEi0KCWVudW12YWx1ZRgCIAMoCzIaLmdv", "QVJESU5BTElUWV9SRVBFQVRFRBADIs4BCgRFbnVtEgwKBG5hbWUYASABKAkS",
"b2dsZS5wcm90b2J1Zi5FbnVtVmFsdWUSKAoHb3B0aW9ucxgDIAMoCzIXLmdv", "LQoJZW51bXZhbHVlGAIgAygLMhouZ29vZ2xlLnByb3RvYnVmLkVudW1WYWx1",
"b2dsZS5wcm90b2J1Zi5PcHRpb24SNgoOc291cmNlX2NvbnRleHQYBCABKAsy", "ZRIoCgdvcHRpb25zGAMgAygLMhcuZ29vZ2xlLnByb3RvYnVmLk9wdGlvbhI2",
"Hi5nb29nbGUucHJvdG9idWYuU291cmNlQ29udGV4dBInCgZzeW50YXgYBSAB", "Cg5zb3VyY2VfY29udGV4dBgEIAEoCzIeLmdvb2dsZS5wcm90b2J1Zi5Tb3Vy",
"KA4yFy5nb29nbGUucHJvdG9idWYuU3ludGF4IlMKCUVudW1WYWx1ZRIMCgRu", "Y2VDb250ZXh0EicKBnN5bnRheBgFIAEoDjIXLmdvb2dsZS5wcm90b2J1Zi5T",
"YW1lGAEgASgJEg4KBm51bWJlchgCIAEoBRIoCgdvcHRpb25zGAMgAygLMhcu", "eW50YXgiUwoJRW51bVZhbHVlEgwKBG5hbWUYASABKAkSDgoGbnVtYmVyGAIg",
"Z29vZ2xlLnByb3RvYnVmLk9wdGlvbiI7CgZPcHRpb24SDAoEbmFtZRgBIAEo", "ASgFEigKB29wdGlvbnMYAyADKAsyFy5nb29nbGUucHJvdG9idWYuT3B0aW9u",
"CRIjCgV2YWx1ZRgCIAEoCzIULmdvb2dsZS5wcm90b2J1Zi5BbnkqLgoGU3lu", "IjsKBk9wdGlvbhIMCgRuYW1lGAEgASgJEiMKBXZhbHVlGAIgASgLMhQuZ29v",
"dGF4EhEKDVNZTlRBWF9QUk9UTzIQABIRCg1TWU5UQVhfUFJPVE8zEAFCTAoT", "Z2xlLnByb3RvYnVmLkFueSouCgZTeW50YXgSEQoNU1lOVEFYX1BST1RPMhAA",
"Y29tLmdvb2dsZS5wcm90b2J1ZkIJVHlwZVByb3RvUAGgAQGiAgNHUEKqAh5H", "EhEKDVNZTlRBWF9QUk9UTzMQAUJMChNjb20uZ29vZ2xlLnByb3RvYnVmQglU",
"b29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw==")); "eXBlUHJvdG9QAaABAaICA0dQQqoCHkdvb2dsZS5Qcm90b2J1Zi5XZWxsS25v",
"d25UeXBlc2IGcHJvdG8z"));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, }, new pbr::FileDescriptor[] { global::Google.Protobuf.WellKnownTypes.AnyReflection.Descriptor, global::Google.Protobuf.WellKnownTypes.SourceContextReflection.Descriptor, },
new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(new[] {typeof(global::Google.Protobuf.WellKnownTypes.Syntax), }, new pbr::GeneratedCodeInfo[] {
new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Type), global::Google.Protobuf.WellKnownTypes.Type.Parser, new[]{ "Name", "Fields", "Oneofs", "Options", "SourceContext", "Syntax" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Field), global::Google.Protobuf.WellKnownTypes.Field.Parser, new[]{ "Kind", "Cardinality", "Number", "Name", "TypeUrl", "OneofIndex", "Packed", "Options", "JsonName" }, null, new[]{ typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Kind), typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) }, null), new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Field), global::Google.Protobuf.WellKnownTypes.Field.Parser, new[]{ "Kind", "Cardinality", "Number", "Name", "TypeUrl", "OneofIndex", "Packed", "Options", "JsonName", "DefaultValue" }, null, new[]{ typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Kind), typeof(global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality) }, null),
new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), global::Google.Protobuf.WellKnownTypes.Enum.Parser, new[]{ "Name", "Enumvalue", "Options", "SourceContext", "Syntax" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Enum), global::Google.Protobuf.WellKnownTypes.Enum.Parser, new[]{ "Name", "Enumvalue", "Options", "SourceContext", "Syntax" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.EnumValue), global::Google.Protobuf.WellKnownTypes.EnumValue.Parser, new[]{ "Name", "Number", "Options" }, null, null, null), new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.EnumValue), global::Google.Protobuf.WellKnownTypes.EnumValue.Parser, new[]{ "Name", "Number", "Options" }, null, null, null),
new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Option), global::Google.Protobuf.WellKnownTypes.Option.Parser, new[]{ "Name", "Value" }, null, null, null) new pbr::GeneratedCodeInfo(typeof(global::Google.Protobuf.WellKnownTypes.Option), global::Google.Protobuf.WellKnownTypes.Option.Parser, new[]{ "Name", "Value" }, null, null, null)
...@@ -72,15 +73,15 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -72,15 +73,15 @@ namespace Google.Protobuf.WellKnownTypes {
} }
#region Enums #region Enums
/// <summary> /// <summary>
/// Syntax specifies the syntax in which a service element was defined. /// The syntax in which a protocol buffer element is defined.
/// </summary> /// </summary>
public enum Syntax { public enum Syntax {
/// <summary> /// <summary>
/// Syntax "proto2" /// Syntax `proto2`.
/// </summary> /// </summary>
SYNTAX_PROTO2 = 0, SYNTAX_PROTO2 = 0,
/// <summary> /// <summary>
/// Syntax "proto3" /// Syntax `proto3`.
/// </summary> /// </summary>
SYNTAX_PROTO3 = 1, SYNTAX_PROTO3 = 1,
} }
...@@ -89,7 +90,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -89,7 +90,7 @@ namespace Google.Protobuf.WellKnownTypes {
#region Messages #region Messages
/// <summary> /// <summary>
/// A light-weight descriptor for a proto message type. /// A protocol buffer message type.
/// </summary> /// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class Type : pb::IMessage<Type> { public sealed partial class Type : pb::IMessage<Type> {
...@@ -154,7 +155,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -154,7 +155,7 @@ namespace Google.Protobuf.WellKnownTypes {
= pb::FieldCodec.ForString(26); = pb::FieldCodec.ForString(26);
private readonly pbc::RepeatedField<string> oneofs_ = new pbc::RepeatedField<string>(); private readonly pbc::RepeatedField<string> oneofs_ = new pbc::RepeatedField<string>();
/// <summary> /// <summary>
/// The list of oneof definitions. /// The list of types appearing in `oneof` definitions in this type.
/// </summary> /// </summary>
public pbc::RepeatedField<string> Oneofs { public pbc::RepeatedField<string> Oneofs {
get { return oneofs_; } get { return oneofs_; }
...@@ -166,7 +167,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -166,7 +167,7 @@ namespace Google.Protobuf.WellKnownTypes {
= pb::FieldCodec.ForMessage(34, global::Google.Protobuf.WellKnownTypes.Option.Parser); = pb::FieldCodec.ForMessage(34, global::Google.Protobuf.WellKnownTypes.Option.Parser);
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>(); private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
/// <summary> /// <summary>
/// The proto options. /// The protocol buffer options.
/// </summary> /// </summary>
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options { public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
get { return options_; } get { return options_; }
...@@ -330,7 +331,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -330,7 +331,7 @@ namespace Google.Protobuf.WellKnownTypes {
} }
/// <summary> /// <summary>
/// Field represents a single field of a message type. /// A single field of a message type.
/// </summary> /// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class Field : pb::IMessage<Field> { public sealed partial class Field : pb::IMessage<Field> {
...@@ -361,6 +362,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -361,6 +362,7 @@ namespace Google.Protobuf.WellKnownTypes {
packed_ = other.packed_; packed_ = other.packed_;
options_ = other.options_.Clone(); options_ = other.options_.Clone();
jsonName_ = other.jsonName_; jsonName_ = other.jsonName_;
defaultValue_ = other.defaultValue_;
} }
public Field Clone() { public Field Clone() {
...@@ -371,7 +373,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -371,7 +373,7 @@ namespace Google.Protobuf.WellKnownTypes {
public const int KindFieldNumber = 1; public const int KindFieldNumber = 1;
private global::Google.Protobuf.WellKnownTypes.Field.Types.Kind kind_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN; private global::Google.Protobuf.WellKnownTypes.Field.Types.Kind kind_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Kind.TYPE_UNKNOWN;
/// <summary> /// <summary>
/// The field kind. /// The field type.
/// </summary> /// </summary>
public global::Google.Protobuf.WellKnownTypes.Field.Types.Kind Kind { public global::Google.Protobuf.WellKnownTypes.Field.Types.Kind Kind {
get { return kind_; } get { return kind_; }
...@@ -384,7 +386,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -384,7 +386,7 @@ namespace Google.Protobuf.WellKnownTypes {
public const int CardinalityFieldNumber = 2; public const int CardinalityFieldNumber = 2;
private global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality cardinality_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN; private global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality cardinality_ = global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality.CARDINALITY_UNKNOWN;
/// <summary> /// <summary>
/// The field cardinality, i.e. optional/required/repeated. /// The field cardinality.
/// </summary> /// </summary>
public global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality Cardinality { public global::Google.Protobuf.WellKnownTypes.Field.Types.Cardinality Cardinality {
get { return cardinality_; } get { return cardinality_; }
...@@ -397,7 +399,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -397,7 +399,7 @@ namespace Google.Protobuf.WellKnownTypes {
public const int NumberFieldNumber = 3; public const int NumberFieldNumber = 3;
private int number_; private int number_;
/// <summary> /// <summary>
/// The proto field number. /// The field number.
/// </summary> /// </summary>
public int Number { public int Number {
get { return number_; } get { return number_; }
...@@ -423,8 +425,8 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -423,8 +425,8 @@ namespace Google.Protobuf.WellKnownTypes {
public const int TypeUrlFieldNumber = 6; public const int TypeUrlFieldNumber = 6;
private string typeUrl_ = ""; private string typeUrl_ = "";
/// <summary> /// <summary>
/// The type URL (without the scheme) when the type is MESSAGE or ENUM, /// The field type URL, without the scheme, for message or enumeration
/// such as `type.googleapis.com/google.protobuf.Empty`. /// types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
/// </summary> /// </summary>
public string TypeUrl { public string TypeUrl {
get { return typeUrl_; } get { return typeUrl_; }
...@@ -437,7 +439,8 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -437,7 +439,8 @@ namespace Google.Protobuf.WellKnownTypes {
public const int OneofIndexFieldNumber = 7; public const int OneofIndexFieldNumber = 7;
private int oneofIndex_; private int oneofIndex_;
/// <summary> /// <summary>
/// Index in Type.oneofs. Starts at 1. Zero means no oneof mapping. /// The index of the field type in `Type.oneofs`, for message or enumeration
/// types. The first type has index 1; zero means the type is not in the list.
/// </summary> /// </summary>
public int OneofIndex { public int OneofIndex {
get { return oneofIndex_; } get { return oneofIndex_; }
...@@ -465,7 +468,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -465,7 +468,7 @@ namespace Google.Protobuf.WellKnownTypes {
= pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Option.Parser); = pb::FieldCodec.ForMessage(74, global::Google.Protobuf.WellKnownTypes.Option.Parser);
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>(); private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
/// <summary> /// <summary>
/// The proto options. /// The protocol buffer options.
/// </summary> /// </summary>
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options { public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
get { return options_; } get { return options_; }
...@@ -475,7 +478,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -475,7 +478,7 @@ namespace Google.Protobuf.WellKnownTypes {
public const int JsonNameFieldNumber = 10; public const int JsonNameFieldNumber = 10;
private string jsonName_ = ""; private string jsonName_ = "";
/// <summary> /// <summary>
/// The JSON name for this field. /// The field JSON name.
/// </summary> /// </summary>
public string JsonName { public string JsonName {
get { return jsonName_; } get { return jsonName_; }
...@@ -484,6 +487,19 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -484,6 +487,19 @@ namespace Google.Protobuf.WellKnownTypes {
} }
} }
/// <summary>Field number for the "default_value" field.</summary>
public const int DefaultValueFieldNumber = 11;
private string defaultValue_ = "";
/// <summary>
/// The string value of the default value of this field. Proto2 syntax only.
/// </summary>
public string DefaultValue {
get { return defaultValue_; }
set {
defaultValue_ = pb::Preconditions.CheckNotNull(value, "value");
}
}
public override bool Equals(object other) { public override bool Equals(object other) {
return Equals(other as Field); return Equals(other as Field);
} }
...@@ -504,6 +520,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -504,6 +520,7 @@ namespace Google.Protobuf.WellKnownTypes {
if (Packed != other.Packed) return false; if (Packed != other.Packed) return false;
if(!options_.Equals(other.options_)) return false; if(!options_.Equals(other.options_)) return false;
if (JsonName != other.JsonName) return false; if (JsonName != other.JsonName) return false;
if (DefaultValue != other.DefaultValue) return false;
return true; return true;
} }
...@@ -518,6 +535,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -518,6 +535,7 @@ namespace Google.Protobuf.WellKnownTypes {
if (Packed != false) hash ^= Packed.GetHashCode(); if (Packed != false) hash ^= Packed.GetHashCode();
hash ^= options_.GetHashCode(); hash ^= options_.GetHashCode();
if (JsonName.Length != 0) hash ^= JsonName.GetHashCode(); if (JsonName.Length != 0) hash ^= JsonName.GetHashCode();
if (DefaultValue.Length != 0) hash ^= DefaultValue.GetHashCode();
return hash; return hash;
} }
...@@ -559,6 +577,10 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -559,6 +577,10 @@ namespace Google.Protobuf.WellKnownTypes {
output.WriteRawTag(82); output.WriteRawTag(82);
output.WriteString(JsonName); output.WriteString(JsonName);
} }
if (DefaultValue.Length != 0) {
output.WriteRawTag(90);
output.WriteString(DefaultValue);
}
} }
public int CalculateSize() { public int CalculateSize() {
...@@ -588,6 +610,9 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -588,6 +610,9 @@ namespace Google.Protobuf.WellKnownTypes {
if (JsonName.Length != 0) { if (JsonName.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName); size += 1 + pb::CodedOutputStream.ComputeStringSize(JsonName);
} }
if (DefaultValue.Length != 0) {
size += 1 + pb::CodedOutputStream.ComputeStringSize(DefaultValue);
}
return size; return size;
} }
...@@ -620,6 +645,9 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -620,6 +645,9 @@ namespace Google.Protobuf.WellKnownTypes {
if (other.JsonName.Length != 0) { if (other.JsonName.Length != 0) {
JsonName = other.JsonName; JsonName = other.JsonName;
} }
if (other.DefaultValue.Length != 0) {
DefaultValue = other.DefaultValue;
}
} }
public void MergeFrom(pb::CodedInputStream input) { public void MergeFrom(pb::CodedInputStream input) {
...@@ -665,6 +693,10 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -665,6 +693,10 @@ namespace Google.Protobuf.WellKnownTypes {
JsonName = input.ReadString(); JsonName = input.ReadString();
break; break;
} }
case 90: {
DefaultValue = input.ReadString();
break;
}
} }
} }
} }
...@@ -674,7 +706,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -674,7 +706,7 @@ namespace Google.Protobuf.WellKnownTypes {
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static partial class Types { public static partial class Types {
/// <summary> /// <summary>
/// Kind represents a basic field type. /// Basic field types.
/// </summary> /// </summary>
public enum Kind { public enum Kind {
/// <summary> /// <summary>
...@@ -718,7 +750,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -718,7 +750,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// </summary> /// </summary>
TYPE_STRING = 9, TYPE_STRING = 9,
/// <summary> /// <summary>
/// Field type group (deprecated proto2 type) /// Field type group. Proto2 syntax only, and deprecated.
/// </summary> /// </summary>
TYPE_GROUP = 10, TYPE_GROUP = 10,
/// <summary> /// <summary>
...@@ -756,12 +788,11 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -756,12 +788,11 @@ namespace Google.Protobuf.WellKnownTypes {
} }
/// <summary> /// <summary>
/// Cardinality represents whether a field is optional, required, or /// Whether a field is optional, required, or repeated.
/// repeated.
/// </summary> /// </summary>
public enum Cardinality { public enum Cardinality {
/// <summary> /// <summary>
/// The field cardinality is unknown. Typically an error condition. /// For fields with unknown cardinality.
/// </summary> /// </summary>
CARDINALITY_UNKNOWN = 0, CARDINALITY_UNKNOWN = 0,
/// <summary> /// <summary>
...@@ -769,7 +800,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -769,7 +800,7 @@ namespace Google.Protobuf.WellKnownTypes {
/// </summary> /// </summary>
CARDINALITY_OPTIONAL = 1, CARDINALITY_OPTIONAL = 1,
/// <summary> /// <summary>
/// For required fields. Not used for proto3. /// For required fields. Proto2 syntax only.
/// </summary> /// </summary>
CARDINALITY_REQUIRED = 2, CARDINALITY_REQUIRED = 2,
/// <summary> /// <summary>
...@@ -848,7 +879,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -848,7 +879,7 @@ namespace Google.Protobuf.WellKnownTypes {
= pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser); = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>(); private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
/// <summary> /// <summary>
/// Proto options for the enum type. /// Protocol buffer options.
/// </summary> /// </summary>
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options { public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
get { return options_; } get { return options_; }
...@@ -1066,7 +1097,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1066,7 +1097,7 @@ namespace Google.Protobuf.WellKnownTypes {
= pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser); = pb::FieldCodec.ForMessage(26, global::Google.Protobuf.WellKnownTypes.Option.Parser);
private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>(); private readonly pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> options_ = new pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option>();
/// <summary> /// <summary>
/// Proto options for the enum value. /// Protocol buffer options.
/// </summary> /// </summary>
public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options { public pbc::RepeatedField<global::Google.Protobuf.WellKnownTypes.Option> Options {
get { return options_; } get { return options_; }
...@@ -1164,7 +1195,8 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1164,7 +1195,8 @@ namespace Google.Protobuf.WellKnownTypes {
} }
/// <summary> /// <summary>
/// Proto option attached to messages/fields/enums etc. /// A protocol buffer option, which can be attached to a message, field,
/// enumeration, etc.
/// </summary> /// </summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
public sealed partial class Option : pb::IMessage<Option> { public sealed partial class Option : pb::IMessage<Option> {
...@@ -1198,7 +1230,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1198,7 +1230,7 @@ namespace Google.Protobuf.WellKnownTypes {
public const int NameFieldNumber = 1; public const int NameFieldNumber = 1;
private string name_ = ""; private string name_ = "";
/// <summary> /// <summary>
/// Proto option name. /// The option's name. For example, `"java_package"`.
/// </summary> /// </summary>
public string Name { public string Name {
get { return name_; } get { return name_; }
...@@ -1211,7 +1243,7 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -1211,7 +1243,7 @@ namespace Google.Protobuf.WellKnownTypes {
public const int ValueFieldNumber = 2; public const int ValueFieldNumber = 2;
private global::Google.Protobuf.WellKnownTypes.Any value_; private global::Google.Protobuf.WellKnownTypes.Any value_;
/// <summary> /// <summary>
/// Proto option value. /// The option's value. For example, `"com.google.protobuf"`.
/// </summary> /// </summary>
public global::Google.Protobuf.WellKnownTypes.Any Value { public global::Google.Protobuf.WellKnownTypes.Any Value {
get { return value_; } get { return value_; }
......
...@@ -29,9 +29,10 @@ namespace Google.Protobuf.WellKnownTypes { ...@@ -29,9 +29,10 @@ namespace Google.Protobuf.WellKnownTypes {
"KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1", "KAMiHAoLVUludDY0VmFsdWUSDQoFdmFsdWUYASABKAQiGwoKSW50MzJWYWx1",
"ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo", "ZRINCgV2YWx1ZRgBIAEoBSIcCgtVSW50MzJWYWx1ZRINCgV2YWx1ZRgBIAEo",
"DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS", "DSIaCglCb29sVmFsdWUSDQoFdmFsdWUYASABKAgiHAoLU3RyaW5nVmFsdWUS",
"DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJQ", "DQoFdmFsdWUYASABKAkiGwoKQnl0ZXNWYWx1ZRINCgV2YWx1ZRgBIAEoDEJT",
"ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQGiAgNH", "ChNjb20uZ29vZ2xlLnByb3RvYnVmQg1XcmFwcGVyc1Byb3RvUAGgAQH4AQGi",
"UEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3RvMw==")); "AgNHUEKqAh5Hb29nbGUuUHJvdG9idWYuV2VsbEtub3duVHlwZXNiBnByb3Rv",
"Mw=="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { }, new pbr::FileDescriptor[] { },
new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] { new pbr::GeneratedCodeInfo(null, new pbr::GeneratedCodeInfo[] {
......
...@@ -62,7 +62,6 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) { ...@@ -62,7 +62,6 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
descriptor_->message_type()->FindFieldByName("value"); descriptor_->message_type()->FindFieldByName("value");
variables_["key_type_name"] = type_name(key_descriptor); variables_["key_type_name"] = type_name(key_descriptor);
variables_["value_type_name"] = type_name(value_descriptor); variables_["value_type_name"] = type_name(value_descriptor);
variables_["true_for_wrappers"] = IsWrapperType(value_descriptor) ? "true" : "";
scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1)); scoped_ptr<FieldGeneratorBase> key_generator(CreateFieldGenerator(key_descriptor, 1));
scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2)); scoped_ptr<FieldGeneratorBase> value_generator(CreateFieldGenerator(value_descriptor, 2));
...@@ -76,7 +75,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) { ...@@ -76,7 +75,7 @@ void MapFieldGenerator::GenerateMembers(io::Printer* printer) {
printer->Print( printer->Print(
variables_, variables_,
", $tag$);\n" ", $tag$);\n"
"private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>($true_for_wrappers$);\n"); "private readonly pbc::MapField<$key_type_name$, $value_type_name$> $name$_ = new pbc::MapField<$key_type_name$, $value_type_name$>();\n");
WritePropertyDocComment(printer, descriptor_); WritePropertyDocComment(printer, descriptor_);
AddDeprecatedFlag(printer); AddDeprecatedFlag(printer);
printer->Print( printer->Print(
......
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