123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- #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
- namespace XGame.Framework.Network.Protobuf
- {
- public sealed class MapFieldCodec<TKey, TValue>
- {
- private readonly FieldCodec<TKey> keyCodec;
- private readonly FieldCodec<TValue> valueCodec;
- private readonly uint mapTag;
- /// <summary>
- /// Creates a new entry codec based on a separate key codec and value codec,
- /// and the tag to use for each map entry.
- /// </summary>
- /// <param name="keyCodec">The key codec.</param>
- /// <param name="valueCodec">The value codec.</param>
- /// <param name="mapTag">The map tag to use to introduce each map entry.</param>
- public MapFieldCodec(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>
- public 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>
- public class MessageAdapter : IMsgParser
- {
- private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 };
- private readonly MapFieldCodec<TKey, TValue> codec;
- public TKey Key { get; set; }
- public TValue Value { get; set; }
- public MessageAdapter(MapFieldCodec<TKey, TValue> codec)
- {
- this.codec = codec;
- }
- public void Reset()
- {
- Key = codec.keyCodec.DefaultValue;
- Value = codec.valueCodec.DefaultValue;
- }
- public void MergeFrom(CodedInputStream input)
- {
- uint tag;
- while ((tag = input.ReadTag()) != 0)
- {
- if (tag == codec.keyCodec.Tag)
- {
- Key = codec.keyCodec.Read(input);
- }
- else if (tag == codec.valueCodec.Tag)
- {
- Value = codec.valueCodec.Read(input);
- }
- else
- {
- 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)
- {
- codec.keyCodec.WriteTagAndValue(output, Key);
- codec.valueCodec.WriteTagAndValue(output, Value);
- }
- public int CalculateSize()
- {
- return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valueCodec.CalculateSizeWithTag(Value);
- }
- public void Clear() { }
- //MessageDescriptor IMessage.Descriptor { get { return null; } }
- }
- }
- }
|