|
|
|
@ -33,6 +33,7 @@ |
|
|
|
|
using Google.Protobuf.Compatibility; |
|
|
|
|
using Google.Protobuf.Reflection; |
|
|
|
|
using System; |
|
|
|
|
using System.Buffers; |
|
|
|
|
using System.Collections; |
|
|
|
|
using System.Collections.Generic; |
|
|
|
|
using System.IO; |
|
|
|
@ -431,6 +432,28 @@ namespace Google.Protobuf.Collections |
|
|
|
|
} while (input.MaybeConsumeTag(codec.MapTag)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Adds entries to the map from the given parse context. |
|
|
|
|
/// </summary> |
|
|
|
|
/// <remarks> |
|
|
|
|
/// It is assumed that the input is initially positioned after the tag specified by the codec. |
|
|
|
|
/// This method will continue reading entries from the input until the end is reached, or |
|
|
|
|
/// a different tag is encountered. |
|
|
|
|
/// </remarks> |
|
|
|
|
/// <param name="ctx">Input to read from</param> |
|
|
|
|
/// <param name="codec">Codec describing how the key/value pairs are encoded</param> |
|
|
|
|
public void AddEntriesFrom(ref ParseContext ctx, Codec codec) |
|
|
|
|
{ |
|
|
|
|
// TODO: deduplicate code? |
|
|
|
|
var adapter = new Codec.MessageAdapter(codec); |
|
|
|
|
do |
|
|
|
|
{ |
|
|
|
|
adapter.Reset(); |
|
|
|
|
ctx.ReadMessage(adapter); |
|
|
|
|
this[adapter.Key] = adapter.Value; |
|
|
|
|
} while (ParsingPrimitives.MaybeConsumeTag(ref ctx.buffer, ref ctx.state, codec.MapTag)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Writes the contents of this map to the given coded output stream, using the specified codec |
|
|
|
|
/// to encode each entry. |
|
|
|
@ -620,7 +643,7 @@ namespace Google.Protobuf.Collections |
|
|
|
|
/// 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 |
|
|
|
|
internal class MessageAdapter : IMessage, IBufferMessage |
|
|
|
|
{ |
|
|
|
|
private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 }; |
|
|
|
|
|
|
|
|
@ -666,6 +689,35 @@ namespace Google.Protobuf.Collections |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void MergeFrom_Internal(ref ParseContext ctx) |
|
|
|
|
{ |
|
|
|
|
// TODO(jtattermusch): deduplicate code |
|
|
|
|
uint tag; |
|
|
|
|
while ((tag = ctx.ReadTag()) != 0) |
|
|
|
|
{ |
|
|
|
|
if (tag == codec.keyCodec.Tag) |
|
|
|
|
{ |
|
|
|
|
Key = codec.keyCodec.Read(ref ctx); |
|
|
|
|
} |
|
|
|
|
else if (tag == codec.valueCodec.Tag) |
|
|
|
|
{ |
|
|
|
|
Value = codec.valueCodec.Read(ref ctx); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
ParsingPrimitivesMessages.SkipLastField(ref ctx.buffer, ref ctx.state); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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 input with no data (i.e. create a "default" message). |
|
|
|
|
if (Value == null) |
|
|
|
|
{ |
|
|
|
|
var zeroLengthCtx = new ParseContext(new ReadOnlySequence<byte>(ZeroLengthMessageStreamData)); |
|
|
|
|
Value = codec.valueCodec.Read(ref zeroLengthCtx); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void WriteTo(CodedOutputStream output) |
|
|
|
|
{ |
|
|
|
|
codec.keyCodec.WriteTagAndValue(output, Key); |
|
|
|
|