1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license 2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format 3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2008 Google Inc. All rights reserved. 4*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/ 5*1b3f573fSAndroid Build Coastguard Worker // 6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without 7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are 8*1b3f573fSAndroid Build Coastguard Worker // met: 9*1b3f573fSAndroid Build Coastguard Worker // 10*1b3f573fSAndroid Build Coastguard Worker // * Redistributions of source code must retain the above copyright 11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer. 12*1b3f573fSAndroid Build Coastguard Worker // * Redistributions in binary form must reproduce the above 13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer 14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the 15*1b3f573fSAndroid Build Coastguard Worker // distribution. 16*1b3f573fSAndroid Build Coastguard Worker // * Neither the name of Google Inc. nor the names of its 17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from 18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission. 19*1b3f573fSAndroid Build Coastguard Worker // 20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*1b3f573fSAndroid Build Coastguard Worker #endregion 32*1b3f573fSAndroid Build Coastguard Worker 33*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.Collections; 34*1b3f573fSAndroid Build Coastguard Worker using System; 35*1b3f573fSAndroid Build Coastguard Worker using System.Linq; 36*1b3f573fSAndroid Build Coastguard Worker 37*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf 38*1b3f573fSAndroid Build Coastguard Worker { 39*1b3f573fSAndroid Build Coastguard Worker internal interface IExtensionValue : IEquatable<IExtensionValue>, IDeepCloneable<IExtensionValue> 40*1b3f573fSAndroid Build Coastguard Worker { MergeFrom(ref ParseContext ctx)41*1b3f573fSAndroid Build Coastguard Worker void MergeFrom(ref ParseContext ctx); 42*1b3f573fSAndroid Build Coastguard Worker MergeFrom(IExtensionValue value)43*1b3f573fSAndroid Build Coastguard Worker void MergeFrom(IExtensionValue value); WriteTo(ref WriteContext ctx)44*1b3f573fSAndroid Build Coastguard Worker void WriteTo(ref WriteContext ctx); CalculateSize()45*1b3f573fSAndroid Build Coastguard Worker int CalculateSize(); IsInitialized()46*1b3f573fSAndroid Build Coastguard Worker bool IsInitialized(); GetValue()47*1b3f573fSAndroid Build Coastguard Worker object GetValue(); 48*1b3f573fSAndroid Build Coastguard Worker } 49*1b3f573fSAndroid Build Coastguard Worker 50*1b3f573fSAndroid Build Coastguard Worker internal sealed class ExtensionValue<T> : IExtensionValue 51*1b3f573fSAndroid Build Coastguard Worker { 52*1b3f573fSAndroid Build Coastguard Worker private T field; 53*1b3f573fSAndroid Build Coastguard Worker private FieldCodec<T> codec; 54*1b3f573fSAndroid Build Coastguard Worker ExtensionValue(FieldCodec<T> codec)55*1b3f573fSAndroid Build Coastguard Worker internal ExtensionValue(FieldCodec<T> codec) 56*1b3f573fSAndroid Build Coastguard Worker { 57*1b3f573fSAndroid Build Coastguard Worker this.codec = codec; 58*1b3f573fSAndroid Build Coastguard Worker field = codec.DefaultValue; 59*1b3f573fSAndroid Build Coastguard Worker } 60*1b3f573fSAndroid Build Coastguard Worker CalculateSize()61*1b3f573fSAndroid Build Coastguard Worker public int CalculateSize() 62*1b3f573fSAndroid Build Coastguard Worker { 63*1b3f573fSAndroid Build Coastguard Worker return codec.CalculateUnconditionalSizeWithTag(field); 64*1b3f573fSAndroid Build Coastguard Worker } 65*1b3f573fSAndroid Build Coastguard Worker Clone()66*1b3f573fSAndroid Build Coastguard Worker public IExtensionValue Clone() 67*1b3f573fSAndroid Build Coastguard Worker { 68*1b3f573fSAndroid Build Coastguard Worker return new ExtensionValue<T>(codec) 69*1b3f573fSAndroid Build Coastguard Worker { 70*1b3f573fSAndroid Build Coastguard Worker field = field is IDeepCloneable<T> ? (field as IDeepCloneable<T>).Clone() : field 71*1b3f573fSAndroid Build Coastguard Worker }; 72*1b3f573fSAndroid Build Coastguard Worker } 73*1b3f573fSAndroid Build Coastguard Worker Equals(IExtensionValue other)74*1b3f573fSAndroid Build Coastguard Worker public bool Equals(IExtensionValue other) 75*1b3f573fSAndroid Build Coastguard Worker { 76*1b3f573fSAndroid Build Coastguard Worker if (ReferenceEquals(this, other)) 77*1b3f573fSAndroid Build Coastguard Worker return true; 78*1b3f573fSAndroid Build Coastguard Worker 79*1b3f573fSAndroid Build Coastguard Worker return other is ExtensionValue<T> 80*1b3f573fSAndroid Build Coastguard Worker && codec.Equals((other as ExtensionValue<T>).codec) 81*1b3f573fSAndroid Build Coastguard Worker && Equals(field, (other as ExtensionValue<T>).field); 82*1b3f573fSAndroid Build Coastguard Worker // we check for equality in the codec since we could have equal field values however the values could be written in different ways 83*1b3f573fSAndroid Build Coastguard Worker } 84*1b3f573fSAndroid Build Coastguard Worker GetHashCode()85*1b3f573fSAndroid Build Coastguard Worker public override int GetHashCode() 86*1b3f573fSAndroid Build Coastguard Worker { 87*1b3f573fSAndroid Build Coastguard Worker unchecked 88*1b3f573fSAndroid Build Coastguard Worker { 89*1b3f573fSAndroid Build Coastguard Worker int hash = 17; 90*1b3f573fSAndroid Build Coastguard Worker hash = hash * 31 + field.GetHashCode(); 91*1b3f573fSAndroid Build Coastguard Worker hash = hash * 31 + codec.GetHashCode(); 92*1b3f573fSAndroid Build Coastguard Worker return hash; 93*1b3f573fSAndroid Build Coastguard Worker } 94*1b3f573fSAndroid Build Coastguard Worker } 95*1b3f573fSAndroid Build Coastguard Worker MergeFrom(ref ParseContext ctx)96*1b3f573fSAndroid Build Coastguard Worker public void MergeFrom(ref ParseContext ctx) 97*1b3f573fSAndroid Build Coastguard Worker { 98*1b3f573fSAndroid Build Coastguard Worker codec.ValueMerger(ref ctx, ref field); 99*1b3f573fSAndroid Build Coastguard Worker } 100*1b3f573fSAndroid Build Coastguard Worker MergeFrom(IExtensionValue value)101*1b3f573fSAndroid Build Coastguard Worker public void MergeFrom(IExtensionValue value) 102*1b3f573fSAndroid Build Coastguard Worker { 103*1b3f573fSAndroid Build Coastguard Worker if (value is ExtensionValue<T>) 104*1b3f573fSAndroid Build Coastguard Worker { 105*1b3f573fSAndroid Build Coastguard Worker var extensionValue = value as ExtensionValue<T>; 106*1b3f573fSAndroid Build Coastguard Worker codec.FieldMerger(ref field, extensionValue.field); 107*1b3f573fSAndroid Build Coastguard Worker } 108*1b3f573fSAndroid Build Coastguard Worker } 109*1b3f573fSAndroid Build Coastguard Worker WriteTo(ref WriteContext ctx)110*1b3f573fSAndroid Build Coastguard Worker public void WriteTo(ref WriteContext ctx) 111*1b3f573fSAndroid Build Coastguard Worker { 112*1b3f573fSAndroid Build Coastguard Worker ctx.WriteTag(codec.Tag); 113*1b3f573fSAndroid Build Coastguard Worker codec.ValueWriter(ref ctx, field); 114*1b3f573fSAndroid Build Coastguard Worker if (codec.EndTag != 0) 115*1b3f573fSAndroid Build Coastguard Worker { 116*1b3f573fSAndroid Build Coastguard Worker ctx.WriteTag(codec.EndTag); 117*1b3f573fSAndroid Build Coastguard Worker } 118*1b3f573fSAndroid Build Coastguard Worker } 119*1b3f573fSAndroid Build Coastguard Worker GetValue()120*1b3f573fSAndroid Build Coastguard Worker public T GetValue() => field; 121*1b3f573fSAndroid Build Coastguard Worker IExtensionValue.GetValue()122*1b3f573fSAndroid Build Coastguard Worker object IExtensionValue.GetValue() => field; 123*1b3f573fSAndroid Build Coastguard Worker SetValue(T value)124*1b3f573fSAndroid Build Coastguard Worker public void SetValue(T value) 125*1b3f573fSAndroid Build Coastguard Worker { 126*1b3f573fSAndroid Build Coastguard Worker field = value; 127*1b3f573fSAndroid Build Coastguard Worker } 128*1b3f573fSAndroid Build Coastguard Worker IsInitialized()129*1b3f573fSAndroid Build Coastguard Worker public bool IsInitialized() 130*1b3f573fSAndroid Build Coastguard Worker { 131*1b3f573fSAndroid Build Coastguard Worker if (field is IMessage) 132*1b3f573fSAndroid Build Coastguard Worker { 133*1b3f573fSAndroid Build Coastguard Worker return (field as IMessage).IsInitialized(); 134*1b3f573fSAndroid Build Coastguard Worker } 135*1b3f573fSAndroid Build Coastguard Worker else 136*1b3f573fSAndroid Build Coastguard Worker { 137*1b3f573fSAndroid Build Coastguard Worker return true; 138*1b3f573fSAndroid Build Coastguard Worker } 139*1b3f573fSAndroid Build Coastguard Worker } 140*1b3f573fSAndroid Build Coastguard Worker } 141*1b3f573fSAndroid Build Coastguard Worker 142*1b3f573fSAndroid Build Coastguard Worker internal sealed class RepeatedExtensionValue<T> : IExtensionValue 143*1b3f573fSAndroid Build Coastguard Worker { 144*1b3f573fSAndroid Build Coastguard Worker private RepeatedField<T> field; 145*1b3f573fSAndroid Build Coastguard Worker private readonly FieldCodec<T> codec; 146*1b3f573fSAndroid Build Coastguard Worker RepeatedExtensionValue(FieldCodec<T> codec)147*1b3f573fSAndroid Build Coastguard Worker internal RepeatedExtensionValue(FieldCodec<T> codec) 148*1b3f573fSAndroid Build Coastguard Worker { 149*1b3f573fSAndroid Build Coastguard Worker this.codec = codec; 150*1b3f573fSAndroid Build Coastguard Worker field = new RepeatedField<T>(); 151*1b3f573fSAndroid Build Coastguard Worker } 152*1b3f573fSAndroid Build Coastguard Worker CalculateSize()153*1b3f573fSAndroid Build Coastguard Worker public int CalculateSize() 154*1b3f573fSAndroid Build Coastguard Worker { 155*1b3f573fSAndroid Build Coastguard Worker return field.CalculateSize(codec); 156*1b3f573fSAndroid Build Coastguard Worker } 157*1b3f573fSAndroid Build Coastguard Worker Clone()158*1b3f573fSAndroid Build Coastguard Worker public IExtensionValue Clone() 159*1b3f573fSAndroid Build Coastguard Worker { 160*1b3f573fSAndroid Build Coastguard Worker return new RepeatedExtensionValue<T>(codec) 161*1b3f573fSAndroid Build Coastguard Worker { 162*1b3f573fSAndroid Build Coastguard Worker field = field.Clone() 163*1b3f573fSAndroid Build Coastguard Worker }; 164*1b3f573fSAndroid Build Coastguard Worker } 165*1b3f573fSAndroid Build Coastguard Worker Equals(IExtensionValue other)166*1b3f573fSAndroid Build Coastguard Worker public bool Equals(IExtensionValue other) 167*1b3f573fSAndroid Build Coastguard Worker { 168*1b3f573fSAndroid Build Coastguard Worker if (ReferenceEquals(this, other)) 169*1b3f573fSAndroid Build Coastguard Worker return true; 170*1b3f573fSAndroid Build Coastguard Worker 171*1b3f573fSAndroid Build Coastguard Worker return other is RepeatedExtensionValue<T> 172*1b3f573fSAndroid Build Coastguard Worker && field.Equals((other as RepeatedExtensionValue<T>).field) 173*1b3f573fSAndroid Build Coastguard Worker && codec.Equals((other as RepeatedExtensionValue<T>).codec); 174*1b3f573fSAndroid Build Coastguard Worker } 175*1b3f573fSAndroid Build Coastguard Worker GetHashCode()176*1b3f573fSAndroid Build Coastguard Worker public override int GetHashCode() 177*1b3f573fSAndroid Build Coastguard Worker { 178*1b3f573fSAndroid Build Coastguard Worker unchecked 179*1b3f573fSAndroid Build Coastguard Worker { 180*1b3f573fSAndroid Build Coastguard Worker int hash = 17; 181*1b3f573fSAndroid Build Coastguard Worker hash = hash * 31 + field.GetHashCode(); 182*1b3f573fSAndroid Build Coastguard Worker hash = hash * 31 + codec.GetHashCode(); 183*1b3f573fSAndroid Build Coastguard Worker return hash; 184*1b3f573fSAndroid Build Coastguard Worker } 185*1b3f573fSAndroid Build Coastguard Worker } 186*1b3f573fSAndroid Build Coastguard Worker MergeFrom(ref ParseContext ctx)187*1b3f573fSAndroid Build Coastguard Worker public void MergeFrom(ref ParseContext ctx) 188*1b3f573fSAndroid Build Coastguard Worker { 189*1b3f573fSAndroid Build Coastguard Worker field.AddEntriesFrom(ref ctx, codec); 190*1b3f573fSAndroid Build Coastguard Worker } 191*1b3f573fSAndroid Build Coastguard Worker MergeFrom(IExtensionValue value)192*1b3f573fSAndroid Build Coastguard Worker public void MergeFrom(IExtensionValue value) 193*1b3f573fSAndroid Build Coastguard Worker { 194*1b3f573fSAndroid Build Coastguard Worker if (value is RepeatedExtensionValue<T>) 195*1b3f573fSAndroid Build Coastguard Worker { 196*1b3f573fSAndroid Build Coastguard Worker field.Add((value as RepeatedExtensionValue<T>).field); 197*1b3f573fSAndroid Build Coastguard Worker } 198*1b3f573fSAndroid Build Coastguard Worker } 199*1b3f573fSAndroid Build Coastguard Worker WriteTo(ref WriteContext ctx)200*1b3f573fSAndroid Build Coastguard Worker public void WriteTo(ref WriteContext ctx) 201*1b3f573fSAndroid Build Coastguard Worker { 202*1b3f573fSAndroid Build Coastguard Worker field.WriteTo(ref ctx, codec); 203*1b3f573fSAndroid Build Coastguard Worker } 204*1b3f573fSAndroid Build Coastguard Worker GetValue()205*1b3f573fSAndroid Build Coastguard Worker public RepeatedField<T> GetValue() => field; 206*1b3f573fSAndroid Build Coastguard Worker IExtensionValue.GetValue()207*1b3f573fSAndroid Build Coastguard Worker object IExtensionValue.GetValue() => field; 208*1b3f573fSAndroid Build Coastguard Worker IsInitialized()209*1b3f573fSAndroid Build Coastguard Worker public bool IsInitialized() 210*1b3f573fSAndroid Build Coastguard Worker { 211*1b3f573fSAndroid Build Coastguard Worker for (int i = 0; i < field.Count; i++) 212*1b3f573fSAndroid Build Coastguard Worker { 213*1b3f573fSAndroid Build Coastguard Worker var element = field[i]; 214*1b3f573fSAndroid Build Coastguard Worker if (element is IMessage) 215*1b3f573fSAndroid Build Coastguard Worker { 216*1b3f573fSAndroid Build Coastguard Worker if (!(element as IMessage).IsInitialized()) 217*1b3f573fSAndroid Build Coastguard Worker { 218*1b3f573fSAndroid Build Coastguard Worker return false; 219*1b3f573fSAndroid Build Coastguard Worker } 220*1b3f573fSAndroid Build Coastguard Worker } 221*1b3f573fSAndroid Build Coastguard Worker else 222*1b3f573fSAndroid Build Coastguard Worker { 223*1b3f573fSAndroid Build Coastguard Worker break; 224*1b3f573fSAndroid Build Coastguard Worker } 225*1b3f573fSAndroid Build Coastguard Worker } 226*1b3f573fSAndroid Build Coastguard Worker 227*1b3f573fSAndroid Build Coastguard Worker return true; 228*1b3f573fSAndroid Build Coastguard Worker } 229*1b3f573fSAndroid Build Coastguard Worker } 230*1b3f573fSAndroid Build Coastguard Worker } 231