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 2015 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 Google.Protobuf.Compatibility; 35*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.WellKnownTypes; 36*1b3f573fSAndroid Build Coastguard Worker using System; 37*1b3f573fSAndroid Build Coastguard Worker using System.Collections.Generic; 38*1b3f573fSAndroid Build Coastguard Worker using System.Security; 39*1b3f573fSAndroid Build Coastguard Worker 40*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf 41*1b3f573fSAndroid Build Coastguard Worker { 42*1b3f573fSAndroid Build Coastguard Worker /// <summary> 43*1b3f573fSAndroid Build Coastguard Worker /// Factory methods for <see cref="FieldCodec{T}"/>. 44*1b3f573fSAndroid Build Coastguard Worker /// </summary> 45*1b3f573fSAndroid Build Coastguard Worker public static class FieldCodec 46*1b3f573fSAndroid Build Coastguard Worker { 47*1b3f573fSAndroid Build Coastguard Worker // TODO: Avoid the "dual hit" of lambda expressions: create open delegates instead. (At least test...) 48*1b3f573fSAndroid Build Coastguard Worker 49*1b3f573fSAndroid Build Coastguard Worker /// <summary> 50*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a string field with the given tag. 51*1b3f573fSAndroid Build Coastguard Worker /// </summary> 52*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 53*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForString(uint tag)54*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<string> ForString(uint tag) 55*1b3f573fSAndroid Build Coastguard Worker { 56*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForString(tag, ""); 57*1b3f573fSAndroid Build Coastguard Worker } 58*1b3f573fSAndroid Build Coastguard Worker 59*1b3f573fSAndroid Build Coastguard Worker /// <summary> 60*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a bytes field with the given tag. 61*1b3f573fSAndroid Build Coastguard Worker /// </summary> 62*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 63*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForBytes(uint tag)64*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<ByteString> ForBytes(uint tag) 65*1b3f573fSAndroid Build Coastguard Worker { 66*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForBytes(tag, ByteString.Empty); 67*1b3f573fSAndroid Build Coastguard Worker } 68*1b3f573fSAndroid Build Coastguard Worker 69*1b3f573fSAndroid Build Coastguard Worker /// <summary> 70*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a bool field with the given tag. 71*1b3f573fSAndroid Build Coastguard Worker /// </summary> 72*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 73*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForBool(uint tag)74*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<bool> ForBool(uint tag) 75*1b3f573fSAndroid Build Coastguard Worker { 76*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForBool(tag, false); 77*1b3f573fSAndroid Build Coastguard Worker } 78*1b3f573fSAndroid Build Coastguard Worker 79*1b3f573fSAndroid Build Coastguard Worker /// <summary> 80*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an int32 field with the given tag. 81*1b3f573fSAndroid Build Coastguard Worker /// </summary> 82*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 83*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForInt32(uint tag)84*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<int> ForInt32(uint tag) 85*1b3f573fSAndroid Build Coastguard Worker { 86*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForInt32(tag, 0); 87*1b3f573fSAndroid Build Coastguard Worker } 88*1b3f573fSAndroid Build Coastguard Worker 89*1b3f573fSAndroid Build Coastguard Worker /// <summary> 90*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sint32 field with the given tag. 91*1b3f573fSAndroid Build Coastguard Worker /// </summary> 92*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 93*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSInt32(uint tag)94*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<int> ForSInt32(uint tag) 95*1b3f573fSAndroid Build Coastguard Worker { 96*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForSInt32(tag, 0); 97*1b3f573fSAndroid Build Coastguard Worker } 98*1b3f573fSAndroid Build Coastguard Worker 99*1b3f573fSAndroid Build Coastguard Worker /// <summary> 100*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a fixed32 field with the given tag. 101*1b3f573fSAndroid Build Coastguard Worker /// </summary> 102*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 103*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForFixed32(uint tag)104*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<uint> ForFixed32(uint tag) 105*1b3f573fSAndroid Build Coastguard Worker { 106*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForFixed32(tag, 0); 107*1b3f573fSAndroid Build Coastguard Worker } 108*1b3f573fSAndroid Build Coastguard Worker 109*1b3f573fSAndroid Build Coastguard Worker /// <summary> 110*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sfixed32 field with the given tag. 111*1b3f573fSAndroid Build Coastguard Worker /// </summary> 112*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 113*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSFixed32(uint tag)114*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<int> ForSFixed32(uint tag) 115*1b3f573fSAndroid Build Coastguard Worker { 116*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForSFixed32(tag, 0); 117*1b3f573fSAndroid Build Coastguard Worker } 118*1b3f573fSAndroid Build Coastguard Worker 119*1b3f573fSAndroid Build Coastguard Worker /// <summary> 120*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a uint32 field with the given tag. 121*1b3f573fSAndroid Build Coastguard Worker /// </summary> 122*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 123*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForUInt32(uint tag)124*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<uint> ForUInt32(uint tag) 125*1b3f573fSAndroid Build Coastguard Worker { 126*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForUInt32(tag, 0); 127*1b3f573fSAndroid Build Coastguard Worker } 128*1b3f573fSAndroid Build Coastguard Worker 129*1b3f573fSAndroid Build Coastguard Worker /// <summary> 130*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an int64 field with the given tag. 131*1b3f573fSAndroid Build Coastguard Worker /// </summary> 132*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 133*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForInt64(uint tag)134*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<long> ForInt64(uint tag) 135*1b3f573fSAndroid Build Coastguard Worker { 136*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForInt64(tag, 0); 137*1b3f573fSAndroid Build Coastguard Worker } 138*1b3f573fSAndroid Build Coastguard Worker 139*1b3f573fSAndroid Build Coastguard Worker /// <summary> 140*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sint64 field with the given tag. 141*1b3f573fSAndroid Build Coastguard Worker /// </summary> 142*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 143*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSInt64(uint tag)144*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<long> ForSInt64(uint tag) 145*1b3f573fSAndroid Build Coastguard Worker { 146*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForSInt64(tag, 0); 147*1b3f573fSAndroid Build Coastguard Worker } 148*1b3f573fSAndroid Build Coastguard Worker 149*1b3f573fSAndroid Build Coastguard Worker /// <summary> 150*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a fixed64 field with the given tag. 151*1b3f573fSAndroid Build Coastguard Worker /// </summary> 152*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 153*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForFixed64(uint tag)154*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<ulong> ForFixed64(uint tag) 155*1b3f573fSAndroid Build Coastguard Worker { 156*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForFixed64(tag, 0); 157*1b3f573fSAndroid Build Coastguard Worker } 158*1b3f573fSAndroid Build Coastguard Worker 159*1b3f573fSAndroid Build Coastguard Worker /// <summary> 160*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sfixed64 field with the given tag. 161*1b3f573fSAndroid Build Coastguard Worker /// </summary> 162*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 163*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSFixed64(uint tag)164*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<long> ForSFixed64(uint tag) 165*1b3f573fSAndroid Build Coastguard Worker { 166*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForSFixed64(tag, 0); 167*1b3f573fSAndroid Build Coastguard Worker } 168*1b3f573fSAndroid Build Coastguard Worker 169*1b3f573fSAndroid Build Coastguard Worker /// <summary> 170*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a uint64 field with the given tag. 171*1b3f573fSAndroid Build Coastguard Worker /// </summary> 172*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 173*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForUInt64(uint tag)174*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<ulong> ForUInt64(uint tag) 175*1b3f573fSAndroid Build Coastguard Worker { 176*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForUInt64(tag, 0); 177*1b3f573fSAndroid Build Coastguard Worker } 178*1b3f573fSAndroid Build Coastguard Worker 179*1b3f573fSAndroid Build Coastguard Worker /// <summary> 180*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a float field with the given tag. 181*1b3f573fSAndroid Build Coastguard Worker /// </summary> 182*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 183*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForFloat(uint tag)184*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<float> ForFloat(uint tag) 185*1b3f573fSAndroid Build Coastguard Worker { 186*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForFloat(tag, 0); 187*1b3f573fSAndroid Build Coastguard Worker } 188*1b3f573fSAndroid Build Coastguard Worker 189*1b3f573fSAndroid Build Coastguard Worker /// <summary> 190*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a double field with the given tag. 191*1b3f573fSAndroid Build Coastguard Worker /// </summary> 192*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 193*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForDouble(uint tag)194*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<double> ForDouble(uint tag) 195*1b3f573fSAndroid Build Coastguard Worker { 196*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForDouble(tag, 0); 197*1b3f573fSAndroid Build Coastguard Worker } 198*1b3f573fSAndroid Build Coastguard Worker 199*1b3f573fSAndroid Build Coastguard Worker // Enums are tricky. We can probably use expression trees to build these delegates automatically, 200*1b3f573fSAndroid Build Coastguard Worker // but it's easy to generate the code for it. 201*1b3f573fSAndroid Build Coastguard Worker 202*1b3f573fSAndroid Build Coastguard Worker /// <summary> 203*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an enum field with the given tag. 204*1b3f573fSAndroid Build Coastguard Worker /// </summary> 205*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 206*1b3f573fSAndroid Build Coastguard Worker /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param> 207*1b3f573fSAndroid Build Coastguard Worker /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param> 208*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForEnum(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32)209*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32) 210*1b3f573fSAndroid Build Coastguard Worker { 211*1b3f573fSAndroid Build Coastguard Worker return FieldCodec.ForEnum(tag, toInt32, fromInt32, default(T)); 212*1b3f573fSAndroid Build Coastguard Worker } 213*1b3f573fSAndroid Build Coastguard Worker 214*1b3f573fSAndroid Build Coastguard Worker /// <summary> 215*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a string field with the given tag. 216*1b3f573fSAndroid Build Coastguard Worker /// </summary> 217*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 218*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 219*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForString(uint tag, string defaultValue)220*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<string> ForString(uint tag, string defaultValue) 221*1b3f573fSAndroid Build Coastguard Worker { 222*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<string>((ref ParseContext ctx) => ctx.ReadString(), (ref WriteContext ctx, string value) => ctx.WriteString(value), CodedOutputStream.ComputeStringSize, tag, defaultValue); 223*1b3f573fSAndroid Build Coastguard Worker } 224*1b3f573fSAndroid Build Coastguard Worker 225*1b3f573fSAndroid Build Coastguard Worker /// <summary> 226*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a bytes field with the given tag. 227*1b3f573fSAndroid Build Coastguard Worker /// </summary> 228*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 229*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 230*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForBytes(uint tag, ByteString defaultValue)231*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<ByteString> ForBytes(uint tag, ByteString defaultValue) 232*1b3f573fSAndroid Build Coastguard Worker { 233*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<ByteString>((ref ParseContext ctx) => ctx.ReadBytes(), (ref WriteContext ctx, ByteString value) => ctx.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag, defaultValue); 234*1b3f573fSAndroid Build Coastguard Worker } 235*1b3f573fSAndroid Build Coastguard Worker 236*1b3f573fSAndroid Build Coastguard Worker /// <summary> 237*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a bool field with the given tag. 238*1b3f573fSAndroid Build Coastguard Worker /// </summary> 239*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 240*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 241*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForBool(uint tag, bool defaultValue)242*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<bool> ForBool(uint tag, bool defaultValue) 243*1b3f573fSAndroid Build Coastguard Worker { 244*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<bool>((ref ParseContext ctx) => ctx.ReadBool(), (ref WriteContext ctx, bool value) => ctx.WriteBool(value), CodedOutputStream.BoolSize, tag, defaultValue); 245*1b3f573fSAndroid Build Coastguard Worker } 246*1b3f573fSAndroid Build Coastguard Worker 247*1b3f573fSAndroid Build Coastguard Worker /// <summary> 248*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an int32 field with the given tag. 249*1b3f573fSAndroid Build Coastguard Worker /// </summary> 250*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 251*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 252*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForInt32(uint tag, int defaultValue)253*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<int> ForInt32(uint tag, int defaultValue) 254*1b3f573fSAndroid Build Coastguard Worker { 255*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<int>((ref ParseContext ctx) => ctx.ReadInt32(), (ref WriteContext output, int value) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag, defaultValue); 256*1b3f573fSAndroid Build Coastguard Worker } 257*1b3f573fSAndroid Build Coastguard Worker 258*1b3f573fSAndroid Build Coastguard Worker /// <summary> 259*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sint32 field with the given tag. 260*1b3f573fSAndroid Build Coastguard Worker /// </summary> 261*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 262*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 263*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSInt32(uint tag, int defaultValue)264*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<int> ForSInt32(uint tag, int defaultValue) 265*1b3f573fSAndroid Build Coastguard Worker { 266*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<int>((ref ParseContext ctx) => ctx.ReadSInt32(), (ref WriteContext output, int value) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag, defaultValue); 267*1b3f573fSAndroid Build Coastguard Worker } 268*1b3f573fSAndroid Build Coastguard Worker 269*1b3f573fSAndroid Build Coastguard Worker /// <summary> 270*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a fixed32 field with the given tag. 271*1b3f573fSAndroid Build Coastguard Worker /// </summary> 272*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 273*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 274*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForFixed32(uint tag, uint defaultValue)275*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<uint> ForFixed32(uint tag, uint defaultValue) 276*1b3f573fSAndroid Build Coastguard Worker { 277*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<uint>((ref ParseContext ctx) => ctx.ReadFixed32(), (ref WriteContext output, uint value) => output.WriteFixed32(value), 4, tag, defaultValue); 278*1b3f573fSAndroid Build Coastguard Worker } 279*1b3f573fSAndroid Build Coastguard Worker 280*1b3f573fSAndroid Build Coastguard Worker /// <summary> 281*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sfixed32 field with the given tag. 282*1b3f573fSAndroid Build Coastguard Worker /// </summary> 283*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 284*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 285*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSFixed32(uint tag, int defaultValue)286*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<int> ForSFixed32(uint tag, int defaultValue) 287*1b3f573fSAndroid Build Coastguard Worker { 288*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<int>((ref ParseContext ctx) => ctx.ReadSFixed32(), (ref WriteContext output, int value) => output.WriteSFixed32(value), 4, tag, defaultValue); 289*1b3f573fSAndroid Build Coastguard Worker } 290*1b3f573fSAndroid Build Coastguard Worker 291*1b3f573fSAndroid Build Coastguard Worker /// <summary> 292*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a uint32 field with the given tag. 293*1b3f573fSAndroid Build Coastguard Worker /// </summary> 294*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 295*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 296*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForUInt32(uint tag, uint defaultValue)297*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<uint> ForUInt32(uint tag, uint defaultValue) 298*1b3f573fSAndroid Build Coastguard Worker { 299*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<uint>((ref ParseContext ctx) => ctx.ReadUInt32(), (ref WriteContext output, uint value) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag, defaultValue); 300*1b3f573fSAndroid Build Coastguard Worker } 301*1b3f573fSAndroid Build Coastguard Worker 302*1b3f573fSAndroid Build Coastguard Worker /// <summary> 303*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an int64 field with the given tag. 304*1b3f573fSAndroid Build Coastguard Worker /// </summary> 305*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 306*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 307*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForInt64(uint tag, long defaultValue)308*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<long> ForInt64(uint tag, long defaultValue) 309*1b3f573fSAndroid Build Coastguard Worker { 310*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<long>((ref ParseContext ctx) => ctx.ReadInt64(), (ref WriteContext output, long value) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag, defaultValue); 311*1b3f573fSAndroid Build Coastguard Worker } 312*1b3f573fSAndroid Build Coastguard Worker 313*1b3f573fSAndroid Build Coastguard Worker /// <summary> 314*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sint64 field with the given tag. 315*1b3f573fSAndroid Build Coastguard Worker /// </summary> 316*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 317*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 318*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSInt64(uint tag, long defaultValue)319*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<long> ForSInt64(uint tag, long defaultValue) 320*1b3f573fSAndroid Build Coastguard Worker { 321*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<long>((ref ParseContext ctx) => ctx.ReadSInt64(), (ref WriteContext output, long value) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag, defaultValue); 322*1b3f573fSAndroid Build Coastguard Worker } 323*1b3f573fSAndroid Build Coastguard Worker 324*1b3f573fSAndroid Build Coastguard Worker /// <summary> 325*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a fixed64 field with the given tag. 326*1b3f573fSAndroid Build Coastguard Worker /// </summary> 327*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 328*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 329*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForFixed64(uint tag, ulong defaultValue)330*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<ulong> ForFixed64(uint tag, ulong defaultValue) 331*1b3f573fSAndroid Build Coastguard Worker { 332*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<ulong>((ref ParseContext ctx) => ctx.ReadFixed64(), (ref WriteContext output, ulong value) => output.WriteFixed64(value), 8, tag, defaultValue); 333*1b3f573fSAndroid Build Coastguard Worker } 334*1b3f573fSAndroid Build Coastguard Worker 335*1b3f573fSAndroid Build Coastguard Worker /// <summary> 336*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an sfixed64 field with the given tag. 337*1b3f573fSAndroid Build Coastguard Worker /// </summary> 338*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 339*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 340*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForSFixed64(uint tag, long defaultValue)341*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<long> ForSFixed64(uint tag, long defaultValue) 342*1b3f573fSAndroid Build Coastguard Worker { 343*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<long>((ref ParseContext ctx) => ctx.ReadSFixed64(), (ref WriteContext output, long value) => output.WriteSFixed64(value), 8, tag, defaultValue); 344*1b3f573fSAndroid Build Coastguard Worker } 345*1b3f573fSAndroid Build Coastguard Worker 346*1b3f573fSAndroid Build Coastguard Worker /// <summary> 347*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a uint64 field with the given tag. 348*1b3f573fSAndroid Build Coastguard Worker /// </summary> 349*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 350*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 351*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForUInt64(uint tag, ulong defaultValue)352*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<ulong> ForUInt64(uint tag, ulong defaultValue) 353*1b3f573fSAndroid Build Coastguard Worker { 354*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<ulong>((ref ParseContext ctx) => ctx.ReadUInt64(), (ref WriteContext output, ulong value) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag, defaultValue); 355*1b3f573fSAndroid Build Coastguard Worker } 356*1b3f573fSAndroid Build Coastguard Worker 357*1b3f573fSAndroid Build Coastguard Worker /// <summary> 358*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a float field with the given tag. 359*1b3f573fSAndroid Build Coastguard Worker /// </summary> 360*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 361*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 362*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForFloat(uint tag, float defaultValue)363*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<float> ForFloat(uint tag, float defaultValue) 364*1b3f573fSAndroid Build Coastguard Worker { 365*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<float>((ref ParseContext ctx) => ctx.ReadFloat(), (ref WriteContext output, float value) => output.WriteFloat(value), CodedOutputStream.FloatSize, tag, defaultValue); 366*1b3f573fSAndroid Build Coastguard Worker } 367*1b3f573fSAndroid Build Coastguard Worker 368*1b3f573fSAndroid Build Coastguard Worker /// <summary> 369*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a double field with the given tag. 370*1b3f573fSAndroid Build Coastguard Worker /// </summary> 371*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 372*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 373*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForDouble(uint tag, double defaultValue)374*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<double> ForDouble(uint tag, double defaultValue) 375*1b3f573fSAndroid Build Coastguard Worker { 376*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<double>((ref ParseContext ctx) => ctx.ReadDouble(), (ref WriteContext output, double value) => output.WriteDouble(value), CodedOutputStream.DoubleSize, tag, defaultValue); 377*1b3f573fSAndroid Build Coastguard Worker } 378*1b3f573fSAndroid Build Coastguard Worker 379*1b3f573fSAndroid Build Coastguard Worker // Enums are tricky. We can probably use expression trees to build these delegates automatically, 380*1b3f573fSAndroid Build Coastguard Worker // but it's easy to generate the code for it. 381*1b3f573fSAndroid Build Coastguard Worker 382*1b3f573fSAndroid Build Coastguard Worker /// <summary> 383*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for an enum field with the given tag. 384*1b3f573fSAndroid Build Coastguard Worker /// </summary> 385*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 386*1b3f573fSAndroid Build Coastguard Worker /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param> 387*1b3f573fSAndroid Build Coastguard Worker /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param> 388*1b3f573fSAndroid Build Coastguard Worker /// <param name="defaultValue">The default value.</param> 389*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> ForEnum(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32, T defaultValue)390*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, Func<int, T> fromInt32, T defaultValue) 391*1b3f573fSAndroid Build Coastguard Worker { 392*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<T>((ref ParseContext ctx) => fromInt32( 393*1b3f573fSAndroid Build Coastguard Worker ctx.ReadEnum()), 394*1b3f573fSAndroid Build Coastguard Worker (ref WriteContext output, T value) => output.WriteEnum(toInt32(value)), 395*1b3f573fSAndroid Build Coastguard Worker value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag, defaultValue); 396*1b3f573fSAndroid Build Coastguard Worker } 397*1b3f573fSAndroid Build Coastguard Worker 398*1b3f573fSAndroid Build Coastguard Worker /// <summary> 399*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a message field with the given tag. 400*1b3f573fSAndroid Build Coastguard Worker /// </summary> 401*1b3f573fSAndroid Build Coastguard Worker /// <param name="tag">The tag.</param> 402*1b3f573fSAndroid Build Coastguard Worker /// <param name="parser">A parser to use for the message type.</param> 403*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for the given tag.</returns> 404*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> parser) where T : class, IMessage<T> 405*1b3f573fSAndroid Build Coastguard Worker { 406*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<T>( 407*1b3f573fSAndroid Build Coastguard Worker (ref ParseContext ctx) => 408*1b3f573fSAndroid Build Coastguard Worker { 409*1b3f573fSAndroid Build Coastguard Worker T message = parser.CreateTemplate(); ctx.ReadMessage(message)410*1b3f573fSAndroid Build Coastguard Worker ctx.ReadMessage(message); 411*1b3f573fSAndroid Build Coastguard Worker return message; 412*1b3f573fSAndroid Build Coastguard Worker }, 413*1b3f573fSAndroid Build Coastguard Worker (ref WriteContext output, T value) => output.WriteMessage(value), 414*1b3f573fSAndroid Build Coastguard Worker (ref ParseContext ctx, ref T v) => 415*1b3f573fSAndroid Build Coastguard Worker { 416*1b3f573fSAndroid Build Coastguard Worker if (v == null) 417*1b3f573fSAndroid Build Coastguard Worker { 418*1b3f573fSAndroid Build Coastguard Worker v = parser.CreateTemplate(); 419*1b3f573fSAndroid Build Coastguard Worker } 420*1b3f573fSAndroid Build Coastguard Worker 421*1b3f573fSAndroid Build Coastguard Worker ctx.ReadMessage(v); 422*1b3f573fSAndroid Build Coastguard Worker }, 423*1b3f573fSAndroid Build Coastguard Worker (ref T v, T v2) => 424*1b3f573fSAndroid Build Coastguard Worker { 425*1b3f573fSAndroid Build Coastguard Worker if (v2 == null) 426*1b3f573fSAndroid Build Coastguard Worker { 427*1b3f573fSAndroid Build Coastguard Worker return false; 428*1b3f573fSAndroid Build Coastguard Worker } 429*1b3f573fSAndroid Build Coastguard Worker else if (v == null) 430*1b3f573fSAndroid Build Coastguard Worker { 431*1b3f573fSAndroid Build Coastguard Worker v = v2.Clone(); 432*1b3f573fSAndroid Build Coastguard Worker } 433*1b3f573fSAndroid Build Coastguard Worker else 434*1b3f573fSAndroid Build Coastguard Worker { 435*1b3f573fSAndroid Build Coastguard Worker v.MergeFrom(v2); 436*1b3f573fSAndroid Build Coastguard Worker } 437*1b3f573fSAndroid Build Coastguard Worker return true; 438*1b3f573fSAndroid Build Coastguard Worker }, 439*1b3f573fSAndroid Build Coastguard Worker message => CodedOutputStream.ComputeMessageSize(message), tag); 440*1b3f573fSAndroid Build Coastguard Worker } 441*1b3f573fSAndroid Build Coastguard Worker 442*1b3f573fSAndroid Build Coastguard Worker /// <summary> 443*1b3f573fSAndroid Build Coastguard Worker /// Retrieves a codec suitable for a group field with the given tag. 444*1b3f573fSAndroid Build Coastguard Worker /// </summary> 445*1b3f573fSAndroid Build Coastguard Worker /// <param name="startTag">The start group tag.</param> 446*1b3f573fSAndroid Build Coastguard Worker /// <param name="endTag">The end group tag.</param> 447*1b3f573fSAndroid Build Coastguard Worker /// <param name="parser">A parser to use for the group message type.</param> 448*1b3f573fSAndroid Build Coastguard Worker /// <returns>A codec for given tag</returns> 449*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<T> ForGroup<T>(uint startTag, uint endTag, MessageParser<T> parser) where T : class, IMessage<T> 450*1b3f573fSAndroid Build Coastguard Worker { 451*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<T>( 452*1b3f573fSAndroid Build Coastguard Worker (ref ParseContext ctx) => 453*1b3f573fSAndroid Build Coastguard Worker { 454*1b3f573fSAndroid Build Coastguard Worker T message = parser.CreateTemplate(); ctx.ReadGroup(message)455*1b3f573fSAndroid Build Coastguard Worker ctx.ReadGroup(message); 456*1b3f573fSAndroid Build Coastguard Worker return message; 457*1b3f573fSAndroid Build Coastguard Worker }, 458*1b3f573fSAndroid Build Coastguard Worker (ref WriteContext output, T value) => output.WriteGroup(value), 459*1b3f573fSAndroid Build Coastguard Worker (ref ParseContext ctx, ref T v) => 460*1b3f573fSAndroid Build Coastguard Worker { 461*1b3f573fSAndroid Build Coastguard Worker if (v == null) 462*1b3f573fSAndroid Build Coastguard Worker { 463*1b3f573fSAndroid Build Coastguard Worker v = parser.CreateTemplate(); 464*1b3f573fSAndroid Build Coastguard Worker } 465*1b3f573fSAndroid Build Coastguard Worker 466*1b3f573fSAndroid Build Coastguard Worker ctx.ReadGroup(v); 467*1b3f573fSAndroid Build Coastguard Worker }, 468*1b3f573fSAndroid Build Coastguard Worker (ref T v, T v2) => 469*1b3f573fSAndroid Build Coastguard Worker { 470*1b3f573fSAndroid Build Coastguard Worker if (v2 == null) 471*1b3f573fSAndroid Build Coastguard Worker { 472*1b3f573fSAndroid Build Coastguard Worker return v == null; 473*1b3f573fSAndroid Build Coastguard Worker } 474*1b3f573fSAndroid Build Coastguard Worker else if (v == null) 475*1b3f573fSAndroid Build Coastguard Worker { 476*1b3f573fSAndroid Build Coastguard Worker v = v2.Clone(); 477*1b3f573fSAndroid Build Coastguard Worker } 478*1b3f573fSAndroid Build Coastguard Worker else 479*1b3f573fSAndroid Build Coastguard Worker { 480*1b3f573fSAndroid Build Coastguard Worker v.MergeFrom(v2); 481*1b3f573fSAndroid Build Coastguard Worker } 482*1b3f573fSAndroid Build Coastguard Worker return true; 483*1b3f573fSAndroid Build Coastguard Worker }, 484*1b3f573fSAndroid Build Coastguard Worker message => CodedOutputStream.ComputeGroupSize(message), startTag, endTag); 485*1b3f573fSAndroid Build Coastguard Worker } 486*1b3f573fSAndroid Build Coastguard Worker 487*1b3f573fSAndroid Build Coastguard Worker /// <summary> 488*1b3f573fSAndroid Build Coastguard Worker /// Creates a codec for a wrapper type of a class - which must be string or ByteString. 489*1b3f573fSAndroid Build Coastguard Worker /// </summary> 490*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<T> ForClassWrapper<T>(uint tag) where T : class 491*1b3f573fSAndroid Build Coastguard Worker { 492*1b3f573fSAndroid Build Coastguard Worker var nestedCodec = WrapperCodecs.GetCodec<T>(); 493*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<T>( 494*1b3f573fSAndroid Build Coastguard Worker (ref ParseContext ctx) => WrapperCodecs.Read<T>(ref ctx, nestedCodec), 495*1b3f573fSAndroid Build Coastguard Worker (ref WriteContext output, T value) => WrapperCodecs.Write<T>(ref output, value, nestedCodec), 496*1b3f573fSAndroid Build Coastguard Worker (ref ParseContext ctx, ref T v) => v = WrapperCodecs.Read<T>(ref ctx, nestedCodec), 497*1b3f573fSAndroid Build Coastguard Worker (ref T v, T v2) => { v = v2; return v == null; }, 498*1b3f573fSAndroid Build Coastguard Worker value => WrapperCodecs.CalculateSize<T>(value, nestedCodec), 499*1b3f573fSAndroid Build Coastguard Worker tag, 0, 500*1b3f573fSAndroid Build Coastguard Worker null); // Default value for the wrapper 501*1b3f573fSAndroid Build Coastguard Worker } 502*1b3f573fSAndroid Build Coastguard Worker 503*1b3f573fSAndroid Build Coastguard Worker /// <summary> 504*1b3f573fSAndroid Build Coastguard Worker /// Creates a codec for a wrapper type of a struct - which must be Int32, Int64, UInt32, UInt64, 505*1b3f573fSAndroid Build Coastguard Worker /// Bool, Single or Double. 506*1b3f573fSAndroid Build Coastguard Worker /// </summary> 507*1b3f573fSAndroid Build Coastguard Worker public static FieldCodec<T?> ForStructWrapper<T>(uint tag) where T : struct 508*1b3f573fSAndroid Build Coastguard Worker { 509*1b3f573fSAndroid Build Coastguard Worker var nestedCodec = WrapperCodecs.GetCodec<T>(); 510*1b3f573fSAndroid Build Coastguard Worker return new FieldCodec<T?>( 511*1b3f573fSAndroid Build Coastguard Worker WrapperCodecs.GetReader<T>(), 512*1b3f573fSAndroid Build Coastguard Worker (ref WriteContext output, T? value) => WrapperCodecs.Write<T>(ref output, value.Value, nestedCodec), 513*1b3f573fSAndroid Build Coastguard Worker (ref ParseContext ctx, ref T? v) => v = WrapperCodecs.Read<T>(ref ctx, nestedCodec), 514*1b3f573fSAndroid Build Coastguard Worker (ref T? v, T? v2) => { if (v2.HasValue) { v = v2; } return v.HasValue; }, 515*1b3f573fSAndroid Build Coastguard Worker value => value == null ? 0 : WrapperCodecs.CalculateSize<T>(value.Value, nestedCodec), 516*1b3f573fSAndroid Build Coastguard Worker tag, 0, 517*1b3f573fSAndroid Build Coastguard Worker null); // Default value for the wrapper 518*1b3f573fSAndroid Build Coastguard Worker } 519*1b3f573fSAndroid Build Coastguard Worker 520*1b3f573fSAndroid Build Coastguard Worker /// <summary> 521*1b3f573fSAndroid Build Coastguard Worker /// Helper code to create codecs for wrapper types. 522*1b3f573fSAndroid Build Coastguard Worker /// </summary> 523*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 524*1b3f573fSAndroid Build Coastguard Worker /// Somewhat ugly with all the static methods, but the conversions involved to/from nullable types make it 525*1b3f573fSAndroid Build Coastguard Worker /// slightly tricky to improve. So long as we keep the public API (ForClassWrapper, ForStructWrapper) in place, 526*1b3f573fSAndroid Build Coastguard Worker /// we can refactor later if we come up with something cleaner. 527*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 528*1b3f573fSAndroid Build Coastguard Worker private static class WrapperCodecs 529*1b3f573fSAndroid Build Coastguard Worker { 530*1b3f573fSAndroid Build Coastguard Worker private static readonly Dictionary<System.Type, object> Codecs = new Dictionary<System.Type, object> 531*1b3f573fSAndroid Build Coastguard Worker { 532*1b3f573fSAndroid Build Coastguard Worker { typeof(bool), ForBool(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) }, 533*1b3f573fSAndroid Build Coastguard Worker { typeof(int), ForInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) }, 534*1b3f573fSAndroid Build Coastguard Worker { typeof(long), ForInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) }, 535*1b3f573fSAndroid Build Coastguard Worker { typeof(uint), ForUInt32(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) }, 536*1b3f573fSAndroid Build Coastguard Worker { typeof(ulong), ForUInt64(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Varint)) }, 537*1b3f573fSAndroid Build Coastguard Worker { typeof(float), ForFloat(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) }, 538*1b3f573fSAndroid Build Coastguard Worker { typeof(double), ForDouble(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) }, 539*1b3f573fSAndroid Build Coastguard Worker { typeof(string), ForString(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }, 540*1b3f573fSAndroid Build Coastguard Worker { typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflection.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) } 541*1b3f573fSAndroid Build Coastguard Worker }; 542*1b3f573fSAndroid Build Coastguard Worker 543*1b3f573fSAndroid Build Coastguard Worker private static readonly Dictionary<System.Type, object> Readers = new Dictionary<System.Type, object> 544*1b3f573fSAndroid Build Coastguard Worker { 545*1b3f573fSAndroid Build Coastguard Worker // TODO: Provide more optimized readers. 546*1b3f573fSAndroid Build Coastguard Worker { typeof(bool), (ValueReader<bool?>)ParsingPrimitivesWrappers.ReadBoolWrapper }, 547*1b3f573fSAndroid Build Coastguard Worker { typeof(int), (ValueReader<int?>)ParsingPrimitivesWrappers.ReadInt32Wrapper }, 548*1b3f573fSAndroid Build Coastguard Worker { typeof(long), (ValueReader<long?>)ParsingPrimitivesWrappers.ReadInt64Wrapper }, 549*1b3f573fSAndroid Build Coastguard Worker { typeof(uint), (ValueReader<uint?>)ParsingPrimitivesWrappers.ReadUInt32Wrapper }, 550*1b3f573fSAndroid Build Coastguard Worker { typeof(ulong), (ValueReader<ulong?>)ParsingPrimitivesWrappers.ReadUInt64Wrapper }, 551*1b3f573fSAndroid Build Coastguard Worker { typeof(float), BitConverter.IsLittleEndian ? 552*1b3f573fSAndroid Build Coastguard Worker (ValueReader<float?>)ParsingPrimitivesWrappers.ReadFloatWrapperLittleEndian : 553*1b3f573fSAndroid Build Coastguard Worker (ValueReader<float?>)ParsingPrimitivesWrappers.ReadFloatWrapperSlow }, 554*1b3f573fSAndroid Build Coastguard Worker { typeof(double), BitConverter.IsLittleEndian ? 555*1b3f573fSAndroid Build Coastguard Worker (ValueReader<double?>)ParsingPrimitivesWrappers.ReadDoubleWrapperLittleEndian : 556*1b3f573fSAndroid Build Coastguard Worker (ValueReader<double?>)ParsingPrimitivesWrappers.ReadDoubleWrapperSlow }, 557*1b3f573fSAndroid Build Coastguard Worker // `string` and `ByteString` less performance-sensitive. Do not implement for now. 558*1b3f573fSAndroid Build Coastguard Worker { typeof(string), null }, 559*1b3f573fSAndroid Build Coastguard Worker { typeof(ByteString), null }, 560*1b3f573fSAndroid Build Coastguard Worker }; 561*1b3f573fSAndroid Build Coastguard Worker 562*1b3f573fSAndroid Build Coastguard Worker /// <summary> 563*1b3f573fSAndroid Build Coastguard Worker /// Returns a field codec which effectively wraps a value of type T in a message. 564*1b3f573fSAndroid Build Coastguard Worker /// 565*1b3f573fSAndroid Build Coastguard Worker /// </summary> 566*1b3f573fSAndroid Build Coastguard Worker internal static FieldCodec<T> GetCodec<T>() 567*1b3f573fSAndroid Build Coastguard Worker { 568*1b3f573fSAndroid Build Coastguard Worker object value; 569*1b3f573fSAndroid Build Coastguard Worker if (!Codecs.TryGetValue(typeof(T), out value)) 570*1b3f573fSAndroid Build Coastguard Worker { 571*1b3f573fSAndroid Build Coastguard Worker throw new InvalidOperationException("Invalid type argument requested for wrapper codec: " + typeof(T)); 572*1b3f573fSAndroid Build Coastguard Worker } 573*1b3f573fSAndroid Build Coastguard Worker return (FieldCodec<T>) value; 574*1b3f573fSAndroid Build Coastguard Worker } 575*1b3f573fSAndroid Build Coastguard Worker 576*1b3f573fSAndroid Build Coastguard Worker internal static ValueReader<T?> GetReader<T>() where T : struct 577*1b3f573fSAndroid Build Coastguard Worker { 578*1b3f573fSAndroid Build Coastguard Worker object value; 579*1b3f573fSAndroid Build Coastguard Worker if (!Readers.TryGetValue(typeof(T), out value)) 580*1b3f573fSAndroid Build Coastguard Worker { 581*1b3f573fSAndroid Build Coastguard Worker throw new InvalidOperationException("Invalid type argument requested for wrapper reader: " + typeof(T)); 582*1b3f573fSAndroid Build Coastguard Worker } 583*1b3f573fSAndroid Build Coastguard Worker if (value == null) 584*1b3f573fSAndroid Build Coastguard Worker { 585*1b3f573fSAndroid Build Coastguard Worker // Return default unoptimized reader for the wrapper type. 586*1b3f573fSAndroid Build Coastguard Worker var nestedCoded = GetCodec<T>(); 587*1b3f573fSAndroid Build Coastguard Worker return (ref ParseContext ctx) => Read<T>(ref ctx, nestedCoded); 588*1b3f573fSAndroid Build Coastguard Worker } 589*1b3f573fSAndroid Build Coastguard Worker // Return optimized read for the wrapper type. 590*1b3f573fSAndroid Build Coastguard Worker return (ValueReader<T?>)value; 591*1b3f573fSAndroid Build Coastguard Worker } 592*1b3f573fSAndroid Build Coastguard Worker 593*1b3f573fSAndroid Build Coastguard Worker [SecuritySafeCritical] 594*1b3f573fSAndroid Build Coastguard Worker internal static T Read<T>(ref ParseContext ctx, FieldCodec<T> codec) 595*1b3f573fSAndroid Build Coastguard Worker { 596*1b3f573fSAndroid Build Coastguard Worker int length = ctx.ReadLength(); 597*1b3f573fSAndroid Build Coastguard Worker int oldLimit = SegmentedBufferHelper.PushLimit(ref ctx.state, length); 598*1b3f573fSAndroid Build Coastguard Worker 599*1b3f573fSAndroid Build Coastguard Worker uint tag; 600*1b3f573fSAndroid Build Coastguard Worker T value = codec.DefaultValue; 601*1b3f573fSAndroid Build Coastguard Worker while ((tag = ctx.ReadTag()) != 0) 602*1b3f573fSAndroid Build Coastguard Worker { 603*1b3f573fSAndroid Build Coastguard Worker if (tag == codec.Tag) 604*1b3f573fSAndroid Build Coastguard Worker { 605*1b3f573fSAndroid Build Coastguard Worker value = codec.Read(ref ctx); 606*1b3f573fSAndroid Build Coastguard Worker } 607*1b3f573fSAndroid Build Coastguard Worker else 608*1b3f573fSAndroid Build Coastguard Worker { 609*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.SkipLastField(ref ctx.buffer, ref ctx.state); 610*1b3f573fSAndroid Build Coastguard Worker } 611*1b3f573fSAndroid Build Coastguard Worker 612*1b3f573fSAndroid Build Coastguard Worker } 613*1b3f573fSAndroid Build Coastguard Worker ParsingPrimitivesMessages.CheckReadEndOfStreamTag(ref ctx.state); 614*1b3f573fSAndroid Build Coastguard Worker SegmentedBufferHelper.PopLimit(ref ctx.state, oldLimit); 615*1b3f573fSAndroid Build Coastguard Worker 616*1b3f573fSAndroid Build Coastguard Worker return value; 617*1b3f573fSAndroid Build Coastguard Worker } 618*1b3f573fSAndroid Build Coastguard Worker 619*1b3f573fSAndroid Build Coastguard Worker internal static void Write<T>(ref WriteContext ctx, T value, FieldCodec<T> codec) 620*1b3f573fSAndroid Build Coastguard Worker { 621*1b3f573fSAndroid Build Coastguard Worker ctx.WriteLength(codec.CalculateSizeWithTag(value)); 622*1b3f573fSAndroid Build Coastguard Worker codec.WriteTagAndValue(ref ctx, value); 623*1b3f573fSAndroid Build Coastguard Worker } 624*1b3f573fSAndroid Build Coastguard Worker 625*1b3f573fSAndroid Build Coastguard Worker internal static int CalculateSize<T>(T value, FieldCodec<T> codec) 626*1b3f573fSAndroid Build Coastguard Worker { 627*1b3f573fSAndroid Build Coastguard Worker int fieldLength = codec.CalculateSizeWithTag(value); 628*1b3f573fSAndroid Build Coastguard Worker return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldLength; 629*1b3f573fSAndroid Build Coastguard Worker } 630*1b3f573fSAndroid Build Coastguard Worker } 631*1b3f573fSAndroid Build Coastguard Worker } 632*1b3f573fSAndroid Build Coastguard Worker 633*1b3f573fSAndroid Build Coastguard Worker internal delegate TValue ValueReader<out TValue>(ref ParseContext ctx); 634*1b3f573fSAndroid Build Coastguard Worker internal delegate void ValueWriter<T>(ref WriteContext ctx, T value); 635*1b3f573fSAndroid Build Coastguard Worker 636*1b3f573fSAndroid Build Coastguard Worker /// <summary> 637*1b3f573fSAndroid Build Coastguard Worker /// <para> 638*1b3f573fSAndroid Build Coastguard Worker /// An encode/decode pair for a single field. This effectively encapsulates 639*1b3f573fSAndroid Build Coastguard Worker /// all the information needed to read or write the field value from/to a coded 640*1b3f573fSAndroid Build Coastguard Worker /// stream. 641*1b3f573fSAndroid Build Coastguard Worker /// </para> 642*1b3f573fSAndroid Build Coastguard Worker /// <para> 643*1b3f573fSAndroid Build Coastguard Worker /// This class is public and has to be as it is used by generated code, but its public 644*1b3f573fSAndroid Build Coastguard Worker /// API is very limited - just what the generated code needs to call directly. 645*1b3f573fSAndroid Build Coastguard Worker /// </para> 646*1b3f573fSAndroid Build Coastguard Worker /// </summary> 647*1b3f573fSAndroid Build Coastguard Worker /// <remarks> 648*1b3f573fSAndroid Build Coastguard Worker /// This never writes default values to the stream, and does not address "packedness" 649*1b3f573fSAndroid Build Coastguard Worker /// in repeated fields itself, other than to know whether or not the field *should* be packed. 650*1b3f573fSAndroid Build Coastguard Worker /// </remarks> 651*1b3f573fSAndroid Build Coastguard Worker public sealed class FieldCodec<T> 652*1b3f573fSAndroid Build Coastguard Worker { 653*1b3f573fSAndroid Build Coastguard Worker private static readonly EqualityComparer<T> EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<T>(); 654*1b3f573fSAndroid Build Coastguard Worker private static readonly T DefaultDefault; 655*1b3f573fSAndroid Build Coastguard Worker // Only non-nullable value types support packing. This is the simplest way of detecting that. 656*1b3f573fSAndroid Build Coastguard Worker private static readonly bool TypeSupportsPacking = default(T) != null; 657*1b3f573fSAndroid Build Coastguard Worker 658*1b3f573fSAndroid Build Coastguard Worker /// <summary> 659*1b3f573fSAndroid Build Coastguard Worker /// Merges an input stream into a value 660*1b3f573fSAndroid Build Coastguard Worker /// </summary> 661*1b3f573fSAndroid Build Coastguard Worker internal delegate void InputMerger(ref ParseContext ctx, ref T value); 662*1b3f573fSAndroid Build Coastguard Worker 663*1b3f573fSAndroid Build Coastguard Worker /// <summary> 664*1b3f573fSAndroid Build Coastguard Worker /// Merges a value into a reference to another value, returning a boolean if the value was set 665*1b3f573fSAndroid Build Coastguard Worker /// </summary> 666*1b3f573fSAndroid Build Coastguard Worker internal delegate bool ValuesMerger(ref T value, T other); 667*1b3f573fSAndroid Build Coastguard Worker 668*1b3f573fSAndroid Build Coastguard Worker static FieldCodec() 669*1b3f573fSAndroid Build Coastguard Worker { 670*1b3f573fSAndroid Build Coastguard Worker if (typeof(T) == typeof(string)) 671*1b3f573fSAndroid Build Coastguard Worker { 672*1b3f573fSAndroid Build Coastguard Worker DefaultDefault = (T)(object)""; 673*1b3f573fSAndroid Build Coastguard Worker } 674*1b3f573fSAndroid Build Coastguard Worker else if (typeof(T) == typeof(ByteString)) 675*1b3f573fSAndroid Build Coastguard Worker { 676*1b3f573fSAndroid Build Coastguard Worker DefaultDefault = (T)(object)ByteString.Empty; 677*1b3f573fSAndroid Build Coastguard Worker } 678*1b3f573fSAndroid Build Coastguard Worker // Otherwise it's the default value of the CLR type 679*1b3f573fSAndroid Build Coastguard Worker } 680*1b3f573fSAndroid Build Coastguard Worker 681*1b3f573fSAndroid Build Coastguard Worker internal static bool IsPackedRepeatedField(uint tag) => 682*1b3f573fSAndroid Build Coastguard Worker TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.WireType.LengthDelimited; 683*1b3f573fSAndroid Build Coastguard Worker 684*1b3f573fSAndroid Build Coastguard Worker internal bool PackedRepeatedField { get; } 685*1b3f573fSAndroid Build Coastguard Worker 686*1b3f573fSAndroid Build Coastguard Worker /// <summary> 687*1b3f573fSAndroid Build Coastguard Worker /// Returns a delegate to write a value (unconditionally) to a coded output stream. 688*1b3f573fSAndroid Build Coastguard Worker /// </summary> 689*1b3f573fSAndroid Build Coastguard Worker internal ValueWriter<T> ValueWriter { get; } 690*1b3f573fSAndroid Build Coastguard Worker 691*1b3f573fSAndroid Build Coastguard Worker /// <summary> 692*1b3f573fSAndroid Build Coastguard Worker /// Returns the size calculator for just a value. 693*1b3f573fSAndroid Build Coastguard Worker /// </summary> 694*1b3f573fSAndroid Build Coastguard Worker internal Func<T, int> ValueSizeCalculator { get; } 695*1b3f573fSAndroid Build Coastguard Worker 696*1b3f573fSAndroid Build Coastguard Worker /// <summary> 697*1b3f573fSAndroid Build Coastguard Worker /// Returns a delegate to read a value from a coded input stream. It is assumed that 698*1b3f573fSAndroid Build Coastguard Worker /// the stream is already positioned on the appropriate tag. 699*1b3f573fSAndroid Build Coastguard Worker /// </summary> 700*1b3f573fSAndroid Build Coastguard Worker internal ValueReader<T> ValueReader { get; } 701*1b3f573fSAndroid Build Coastguard Worker 702*1b3f573fSAndroid Build Coastguard Worker /// <summary> 703*1b3f573fSAndroid Build Coastguard Worker /// Returns a delegate to merge a value from a coded input stream. 704*1b3f573fSAndroid Build Coastguard Worker /// It is assumed that the stream is already positioned on the appropriate tag 705*1b3f573fSAndroid Build Coastguard Worker /// </summary> 706*1b3f573fSAndroid Build Coastguard Worker internal InputMerger ValueMerger { get; } 707*1b3f573fSAndroid Build Coastguard Worker 708*1b3f573fSAndroid Build Coastguard Worker /// <summary> 709*1b3f573fSAndroid Build Coastguard Worker /// Returns a delegate to merge two values together. 710*1b3f573fSAndroid Build Coastguard Worker /// </summary> 711*1b3f573fSAndroid Build Coastguard Worker internal ValuesMerger FieldMerger { get; } 712*1b3f573fSAndroid Build Coastguard Worker 713*1b3f573fSAndroid Build Coastguard Worker /// <summary> 714*1b3f573fSAndroid Build Coastguard Worker /// Returns the fixed size for an entry, or 0 if sizes vary. 715*1b3f573fSAndroid Build Coastguard Worker /// </summary> 716*1b3f573fSAndroid Build Coastguard Worker internal int FixedSize { get; } 717*1b3f573fSAndroid Build Coastguard Worker 718*1b3f573fSAndroid Build Coastguard Worker /// <summary> 719*1b3f573fSAndroid Build Coastguard Worker /// Gets the tag of the codec. 720*1b3f573fSAndroid Build Coastguard Worker /// </summary> 721*1b3f573fSAndroid Build Coastguard Worker /// <value> 722*1b3f573fSAndroid Build Coastguard Worker /// The tag of the codec. 723*1b3f573fSAndroid Build Coastguard Worker /// </value> 724*1b3f573fSAndroid Build Coastguard Worker internal uint Tag { get; } 725*1b3f573fSAndroid Build Coastguard Worker 726*1b3f573fSAndroid Build Coastguard Worker /// <summary> 727*1b3f573fSAndroid Build Coastguard Worker /// Gets the end tag of the codec or 0 if there is no end tag 728*1b3f573fSAndroid Build Coastguard Worker /// </summary> 729*1b3f573fSAndroid Build Coastguard Worker /// <value> 730*1b3f573fSAndroid Build Coastguard Worker /// The end tag of the codec. 731*1b3f573fSAndroid Build Coastguard Worker /// </value> 732*1b3f573fSAndroid Build Coastguard Worker internal uint EndTag { get; } 733*1b3f573fSAndroid Build Coastguard Worker 734*1b3f573fSAndroid Build Coastguard Worker /// <summary> 735*1b3f573fSAndroid Build Coastguard Worker /// Default value for this codec. Usually the same for every instance of the same type, but 736*1b3f573fSAndroid Build Coastguard Worker /// for string/ByteString wrapper fields the codec's default value is null, whereas for 737*1b3f573fSAndroid Build Coastguard Worker /// other string/ByteString fields it's "" or ByteString.Empty. 738*1b3f573fSAndroid Build Coastguard Worker /// </summary> 739*1b3f573fSAndroid Build Coastguard Worker /// <value> 740*1b3f573fSAndroid Build Coastguard Worker /// The default value of the codec's type. 741*1b3f573fSAndroid Build Coastguard Worker /// </value> 742*1b3f573fSAndroid Build Coastguard Worker internal T DefaultValue { get; } 743*1b3f573fSAndroid Build Coastguard Worker 744*1b3f573fSAndroid Build Coastguard Worker private readonly int tagSize; 745*1b3f573fSAndroid Build Coastguard Worker 746*1b3f573fSAndroid Build Coastguard Worker internal FieldCodec( 747*1b3f573fSAndroid Build Coastguard Worker ValueReader<T> reader, 748*1b3f573fSAndroid Build Coastguard Worker ValueWriter<T> writer, 749*1b3f573fSAndroid Build Coastguard Worker int fixedSize, 750*1b3f573fSAndroid Build Coastguard Worker uint tag, 751*1b3f573fSAndroid Build Coastguard Worker T defaultValue) : this(reader, writer, _ => fixedSize, tag, defaultValue) 752*1b3f573fSAndroid Build Coastguard Worker { 753*1b3f573fSAndroid Build Coastguard Worker FixedSize = fixedSize; 754*1b3f573fSAndroid Build Coastguard Worker } 755*1b3f573fSAndroid Build Coastguard Worker 756*1b3f573fSAndroid Build Coastguard Worker internal FieldCodec( 757*1b3f573fSAndroid Build Coastguard Worker ValueReader<T> reader, 758*1b3f573fSAndroid Build Coastguard Worker ValueWriter<T> writer, 759*1b3f573fSAndroid Build Coastguard Worker Func<T, int> sizeCalculator, 760*1b3f573fSAndroid Build Coastguard Worker uint tag, 761*1b3f573fSAndroid Build Coastguard Worker T defaultValue) : this(reader, writer, (ref ParseContext ctx, ref T v) => v = reader(ref ctx), (ref T v, T v2) => { v = v2; return true; }, sizeCalculator, tag, 0, defaultValue) 762*1b3f573fSAndroid Build Coastguard Worker { 763*1b3f573fSAndroid Build Coastguard Worker } 764*1b3f573fSAndroid Build Coastguard Worker 765*1b3f573fSAndroid Build Coastguard Worker internal FieldCodec( 766*1b3f573fSAndroid Build Coastguard Worker ValueReader<T> reader, 767*1b3f573fSAndroid Build Coastguard Worker ValueWriter<T> writer, 768*1b3f573fSAndroid Build Coastguard Worker InputMerger inputMerger, 769*1b3f573fSAndroid Build Coastguard Worker ValuesMerger valuesMerger, 770*1b3f573fSAndroid Build Coastguard Worker Func<T, int> sizeCalculator, 771*1b3f573fSAndroid Build Coastguard Worker uint tag, 772*1b3f573fSAndroid Build Coastguard Worker uint endTag = 0) : this(reader, writer, inputMerger, valuesMerger, sizeCalculator, tag, endTag, DefaultDefault) 773*1b3f573fSAndroid Build Coastguard Worker { 774*1b3f573fSAndroid Build Coastguard Worker } 775*1b3f573fSAndroid Build Coastguard Worker 776*1b3f573fSAndroid Build Coastguard Worker internal FieldCodec( 777*1b3f573fSAndroid Build Coastguard Worker ValueReader<T> reader, 778*1b3f573fSAndroid Build Coastguard Worker ValueWriter<T> writer, 779*1b3f573fSAndroid Build Coastguard Worker InputMerger inputMerger, 780*1b3f573fSAndroid Build Coastguard Worker ValuesMerger valuesMerger, 781*1b3f573fSAndroid Build Coastguard Worker Func<T, int> sizeCalculator, 782*1b3f573fSAndroid Build Coastguard Worker uint tag, 783*1b3f573fSAndroid Build Coastguard Worker uint endTag, 784*1b3f573fSAndroid Build Coastguard Worker T defaultValue) 785*1b3f573fSAndroid Build Coastguard Worker { 786*1b3f573fSAndroid Build Coastguard Worker ValueReader = reader; 787*1b3f573fSAndroid Build Coastguard Worker ValueWriter = writer; 788*1b3f573fSAndroid Build Coastguard Worker ValueMerger = inputMerger; 789*1b3f573fSAndroid Build Coastguard Worker FieldMerger = valuesMerger; 790*1b3f573fSAndroid Build Coastguard Worker ValueSizeCalculator = sizeCalculator; 791*1b3f573fSAndroid Build Coastguard Worker FixedSize = 0; 792*1b3f573fSAndroid Build Coastguard Worker Tag = tag; 793*1b3f573fSAndroid Build Coastguard Worker EndTag = endTag; 794*1b3f573fSAndroid Build Coastguard Worker DefaultValue = defaultValue; 795*1b3f573fSAndroid Build Coastguard Worker tagSize = CodedOutputStream.ComputeRawVarint32Size(tag); 796*1b3f573fSAndroid Build Coastguard Worker if (endTag != 0) 797*1b3f573fSAndroid Build Coastguard Worker tagSize += CodedOutputStream.ComputeRawVarint32Size(endTag); 798*1b3f573fSAndroid Build Coastguard Worker // Detect packed-ness once, so we can check for it within RepeatedField<T>. 799*1b3f573fSAndroid Build Coastguard Worker PackedRepeatedField = IsPackedRepeatedField(tag); 800*1b3f573fSAndroid Build Coastguard Worker } 801*1b3f573fSAndroid Build Coastguard Worker 802*1b3f573fSAndroid Build Coastguard Worker /// <summary> 803*1b3f573fSAndroid Build Coastguard Worker /// Write a tag and the given value, *if* the value is not the default. 804*1b3f573fSAndroid Build Coastguard Worker /// </summary> 805*1b3f573fSAndroid Build Coastguard Worker public void WriteTagAndValue(CodedOutputStream output, T value) 806*1b3f573fSAndroid Build Coastguard Worker { 807*1b3f573fSAndroid Build Coastguard Worker WriteContext.Initialize(output, out WriteContext ctx); 808*1b3f573fSAndroid Build Coastguard Worker try 809*1b3f573fSAndroid Build Coastguard Worker { 810*1b3f573fSAndroid Build Coastguard Worker WriteTagAndValue(ref ctx, value); 811*1b3f573fSAndroid Build Coastguard Worker } 812*1b3f573fSAndroid Build Coastguard Worker finally 813*1b3f573fSAndroid Build Coastguard Worker { 814*1b3f573fSAndroid Build Coastguard Worker ctx.CopyStateTo(output); 815*1b3f573fSAndroid Build Coastguard Worker } 816*1b3f573fSAndroid Build Coastguard Worker 817*1b3f573fSAndroid Build Coastguard Worker 818*1b3f573fSAndroid Build Coastguard Worker //if (!IsDefault(value)) 819*1b3f573fSAndroid Build Coastguard Worker //{ 820*1b3f573fSAndroid Build Coastguard Worker // output.WriteTag(Tag); 821*1b3f573fSAndroid Build Coastguard Worker // ValueWriter(output, value); 822*1b3f573fSAndroid Build Coastguard Worker // if (EndTag != 0) 823*1b3f573fSAndroid Build Coastguard Worker // { 824*1b3f573fSAndroid Build Coastguard Worker // output.WriteTag(EndTag); 825*1b3f573fSAndroid Build Coastguard Worker // } 826*1b3f573fSAndroid Build Coastguard Worker //} 827*1b3f573fSAndroid Build Coastguard Worker } 828*1b3f573fSAndroid Build Coastguard Worker 829*1b3f573fSAndroid Build Coastguard Worker /// <summary> 830*1b3f573fSAndroid Build Coastguard Worker /// Write a tag and the given value, *if* the value is not the default. 831*1b3f573fSAndroid Build Coastguard Worker /// </summary> 832*1b3f573fSAndroid Build Coastguard Worker public void WriteTagAndValue(ref WriteContext ctx, T value) 833*1b3f573fSAndroid Build Coastguard Worker { 834*1b3f573fSAndroid Build Coastguard Worker if (!IsDefault(value)) 835*1b3f573fSAndroid Build Coastguard Worker { 836*1b3f573fSAndroid Build Coastguard Worker ctx.WriteTag(Tag); 837*1b3f573fSAndroid Build Coastguard Worker ValueWriter(ref ctx, value); 838*1b3f573fSAndroid Build Coastguard Worker if (EndTag != 0) 839*1b3f573fSAndroid Build Coastguard Worker { 840*1b3f573fSAndroid Build Coastguard Worker ctx.WriteTag(EndTag); 841*1b3f573fSAndroid Build Coastguard Worker } 842*1b3f573fSAndroid Build Coastguard Worker } 843*1b3f573fSAndroid Build Coastguard Worker } 844*1b3f573fSAndroid Build Coastguard Worker 845*1b3f573fSAndroid Build Coastguard Worker /// <summary> 846*1b3f573fSAndroid Build Coastguard Worker /// Reads a value of the codec type from the given <see cref="CodedInputStream"/>. 847*1b3f573fSAndroid Build Coastguard Worker /// </summary> 848*1b3f573fSAndroid Build Coastguard Worker /// <param name="input">The input stream to read from.</param> 849*1b3f573fSAndroid Build Coastguard Worker /// <returns>The value read from the stream.</returns> 850*1b3f573fSAndroid Build Coastguard Worker public T Read(CodedInputStream input) 851*1b3f573fSAndroid Build Coastguard Worker { 852*1b3f573fSAndroid Build Coastguard Worker ParseContext.Initialize(input, out ParseContext ctx); 853*1b3f573fSAndroid Build Coastguard Worker try 854*1b3f573fSAndroid Build Coastguard Worker { 855*1b3f573fSAndroid Build Coastguard Worker return ValueReader(ref ctx); 856*1b3f573fSAndroid Build Coastguard Worker } 857*1b3f573fSAndroid Build Coastguard Worker finally 858*1b3f573fSAndroid Build Coastguard Worker { 859*1b3f573fSAndroid Build Coastguard Worker ctx.CopyStateTo(input); 860*1b3f573fSAndroid Build Coastguard Worker } 861*1b3f573fSAndroid Build Coastguard Worker } 862*1b3f573fSAndroid Build Coastguard Worker 863*1b3f573fSAndroid Build Coastguard Worker /// <summary> 864*1b3f573fSAndroid Build Coastguard Worker /// Reads a value of the codec type from the given <see cref="ParseContext"/>. 865*1b3f573fSAndroid Build Coastguard Worker /// </summary> 866*1b3f573fSAndroid Build Coastguard Worker /// <param name="ctx">The parse context to read from.</param> 867*1b3f573fSAndroid Build Coastguard Worker /// <returns>The value read.</returns> 868*1b3f573fSAndroid Build Coastguard Worker public T Read(ref ParseContext ctx) 869*1b3f573fSAndroid Build Coastguard Worker { 870*1b3f573fSAndroid Build Coastguard Worker return ValueReader(ref ctx); 871*1b3f573fSAndroid Build Coastguard Worker } 872*1b3f573fSAndroid Build Coastguard Worker 873*1b3f573fSAndroid Build Coastguard Worker /// <summary> 874*1b3f573fSAndroid Build Coastguard Worker /// Calculates the size required to write the given value, with a tag, 875*1b3f573fSAndroid Build Coastguard Worker /// if the value is not the default. 876*1b3f573fSAndroid Build Coastguard Worker /// </summary> 877*1b3f573fSAndroid Build Coastguard Worker public int CalculateSizeWithTag(T value) => IsDefault(value) ? 0 : ValueSizeCalculator(value) + tagSize; 878*1b3f573fSAndroid Build Coastguard Worker 879*1b3f573fSAndroid Build Coastguard Worker /// <summary> 880*1b3f573fSAndroid Build Coastguard Worker /// Calculates the size required to write the given value, with a tag, even 881*1b3f573fSAndroid Build Coastguard Worker /// if the value is the default. 882*1b3f573fSAndroid Build Coastguard Worker /// </summary> 883*1b3f573fSAndroid Build Coastguard Worker internal int CalculateUnconditionalSizeWithTag(T value) => ValueSizeCalculator(value) + tagSize; 884*1b3f573fSAndroid Build Coastguard Worker 885*1b3f573fSAndroid Build Coastguard Worker private bool IsDefault(T value) => EqualityComparer.Equals(value, DefaultValue); 886*1b3f573fSAndroid Build Coastguard Worker } 887*1b3f573fSAndroid Build Coastguard Worker } 888