xref: /aosp_15_r20/external/protobuf/csharp/src/Google.Protobuf/FieldCodec.cs (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
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