#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 { private readonly FieldCodec keyCodec; private readonly FieldCodec valueCodec; private readonly uint mapTag; /// /// Creates a new entry codec based on a separate key codec and value codec, /// and the tag to use for each map entry. /// /// The key codec. /// The value codec. /// The map tag to use to introduce each map entry. public MapFieldCodec(FieldCodec keyCodec, FieldCodec valueCodec, uint mapTag) { this.keyCodec = keyCodec; this.valueCodec = valueCodec; this.mapTag = mapTag; } /// /// The tag used in the enclosing message to indicate map entries. /// public uint MapTag { get { return mapTag; } } /// /// A mutable message class, used for parsing and serializing. This /// delegates the work to a codec, but implements the interface /// for interop with and . /// 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. /// public class MessageAdapter : IMsgParser { private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 }; private readonly MapFieldCodec codec; public TKey Key { get; set; } public TValue Value { get; set; } public MessageAdapter(MapFieldCodec 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; } } } } }