Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(315)

Side by Side Diff: third_party/protobuf/csharp/src/Google.Protobuf/FieldCodec.cs

Issue 1842653006: Update //third_party/protobuf to version 3. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc. All rights reserved.
4 // https://developers.google.com/protocol-buffers/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 // * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #endregion
32
33 using Google.Protobuf.WellKnownTypes;
34 using System;
35 using System.Collections.Generic;
36
37 namespace Google.Protobuf
38 {
39 /// <summary>
40 /// Factory methods for <see cref="FieldCodec{T}"/>.
41 /// </summary>
42 public static class FieldCodec
43 {
44 // TODO: Avoid the "dual hit" of lambda expressions: create open delegat es instead. (At least test...)
45
46 /// <summary>
47 /// Retrieves a codec suitable for a string field with the given tag.
48 /// </summary>
49 /// <param name="tag">The tag.</param>
50 /// <returns>A codec for the given tag.</returns>
51 public static FieldCodec<string> ForString(uint tag)
52 {
53 return new FieldCodec<string>(input => input.ReadString(), (output, value) => output.WriteString(value), CodedOutputStream.ComputeStringSize, tag);
54 }
55
56 /// <summary>
57 /// Retrieves a codec suitable for a bytes field with the given tag.
58 /// </summary>
59 /// <param name="tag">The tag.</param>
60 /// <returns>A codec for the given tag.</returns>
61 public static FieldCodec<ByteString> ForBytes(uint tag)
62 {
63 return new FieldCodec<ByteString>(input => input.ReadBytes(), (outpu t, value) => output.WriteBytes(value), CodedOutputStream.ComputeBytesSize, tag);
64 }
65
66 /// <summary>
67 /// Retrieves a codec suitable for a bool field with the given tag.
68 /// </summary>
69 /// <param name="tag">The tag.</param>
70 /// <returns>A codec for the given tag.</returns>
71 public static FieldCodec<bool> ForBool(uint tag)
72 {
73 return new FieldCodec<bool>(input => input.ReadBool(), (output, valu e) => output.WriteBool(value), CodedOutputStream.ComputeBoolSize, tag);
74 }
75
76 /// <summary>
77 /// Retrieves a codec suitable for an int32 field with the given tag.
78 /// </summary>
79 /// <param name="tag">The tag.</param>
80 /// <returns>A codec for the given tag.</returns>
81 public static FieldCodec<int> ForInt32(uint tag)
82 {
83 return new FieldCodec<int>(input => input.ReadInt32(), (output, valu e) => output.WriteInt32(value), CodedOutputStream.ComputeInt32Size, tag);
84 }
85
86 /// <summary>
87 /// Retrieves a codec suitable for an sint32 field with the given tag.
88 /// </summary>
89 /// <param name="tag">The tag.</param>
90 /// <returns>A codec for the given tag.</returns>
91 public static FieldCodec<int> ForSInt32(uint tag)
92 {
93 return new FieldCodec<int>(input => input.ReadSInt32(), (output, val ue) => output.WriteSInt32(value), CodedOutputStream.ComputeSInt32Size, tag);
94 }
95
96 /// <summary>
97 /// Retrieves a codec suitable for a fixed32 field with the given tag.
98 /// </summary>
99 /// <param name="tag">The tag.</param>
100 /// <returns>A codec for the given tag.</returns>
101 public static FieldCodec<uint> ForFixed32(uint tag)
102 {
103 return new FieldCodec<uint>(input => input.ReadFixed32(), (output, v alue) => output.WriteFixed32(value), 4, tag);
104 }
105
106 /// <summary>
107 /// Retrieves a codec suitable for an sfixed32 field with the given tag.
108 /// </summary>
109 /// <param name="tag">The tag.</param>
110 /// <returns>A codec for the given tag.</returns>
111 public static FieldCodec<int> ForSFixed32(uint tag)
112 {
113 return new FieldCodec<int>(input => input.ReadSFixed32(), (output, v alue) => output.WriteSFixed32(value), 4, tag);
114 }
115
116 /// <summary>
117 /// Retrieves a codec suitable for a uint32 field with the given tag.
118 /// </summary>
119 /// <param name="tag">The tag.</param>
120 /// <returns>A codec for the given tag.</returns>
121 public static FieldCodec<uint> ForUInt32(uint tag)
122 {
123 return new FieldCodec<uint>(input => input.ReadUInt32(), (output, va lue) => output.WriteUInt32(value), CodedOutputStream.ComputeUInt32Size, tag);
124 }
125
126 /// <summary>
127 /// Retrieves a codec suitable for an int64 field with the given tag.
128 /// </summary>
129 /// <param name="tag">The tag.</param>
130 /// <returns>A codec for the given tag.</returns>
131 public static FieldCodec<long> ForInt64(uint tag)
132 {
133 return new FieldCodec<long>(input => input.ReadInt64(), (output, val ue) => output.WriteInt64(value), CodedOutputStream.ComputeInt64Size, tag);
134 }
135
136 /// <summary>
137 /// Retrieves a codec suitable for an sint64 field with the given tag.
138 /// </summary>
139 /// <param name="tag">The tag.</param>
140 /// <returns>A codec for the given tag.</returns>
141 public static FieldCodec<long> ForSInt64(uint tag)
142 {
143 return new FieldCodec<long>(input => input.ReadSInt64(), (output, va lue) => output.WriteSInt64(value), CodedOutputStream.ComputeSInt64Size, tag);
144 }
145
146 /// <summary>
147 /// Retrieves a codec suitable for a fixed64 field with the given tag.
148 /// </summary>
149 /// <param name="tag">The tag.</param>
150 /// <returns>A codec for the given tag.</returns>
151 public static FieldCodec<ulong> ForFixed64(uint tag)
152 {
153 return new FieldCodec<ulong>(input => input.ReadFixed64(), (output, value) => output.WriteFixed64(value), 8, tag);
154 }
155
156 /// <summary>
157 /// Retrieves a codec suitable for an sfixed64 field with the given tag.
158 /// </summary>
159 /// <param name="tag">The tag.</param>
160 /// <returns>A codec for the given tag.</returns>
161 public static FieldCodec<long> ForSFixed64(uint tag)
162 {
163 return new FieldCodec<long>(input => input.ReadSFixed64(), (output, value) => output.WriteSFixed64(value), 8, tag);
164 }
165
166 /// <summary>
167 /// Retrieves a codec suitable for a uint64 field with the given tag.
168 /// </summary>
169 /// <param name="tag">The tag.</param>
170 /// <returns>A codec for the given tag.</returns>
171 public static FieldCodec<ulong> ForUInt64(uint tag)
172 {
173 return new FieldCodec<ulong>(input => input.ReadUInt64(), (output, v alue) => output.WriteUInt64(value), CodedOutputStream.ComputeUInt64Size, tag);
174 }
175
176 /// <summary>
177 /// Retrieves a codec suitable for a float field with the given tag.
178 /// </summary>
179 /// <param name="tag">The tag.</param>
180 /// <returns>A codec for the given tag.</returns>
181 public static FieldCodec<float> ForFloat(uint tag)
182 {
183 return new FieldCodec<float>(input => input.ReadFloat(), (output, va lue) => output.WriteFloat(value), CodedOutputStream.ComputeFloatSize, tag);
184 }
185
186 /// <summary>
187 /// Retrieves a codec suitable for a double field with the given tag.
188 /// </summary>
189 /// <param name="tag">The tag.</param>
190 /// <returns>A codec for the given tag.</returns>
191 public static FieldCodec<double> ForDouble(uint tag)
192 {
193 return new FieldCodec<double>(input => input.ReadDouble(), (output, value) => output.WriteDouble(value), CodedOutputStream.ComputeDoubleSize, tag);
194 }
195
196 // Enums are tricky. We can probably use expression trees to build these delegates automatically,
197 // but it's easy to generate the code for it.
198
199 /// <summary>
200 /// Retrieves a codec suitable for an enum field with the given tag.
201 /// </summary>
202 /// <param name="tag">The tag.</param>
203 /// <param name="toInt32">A conversion function from <see cref="Int32"/> to the enum type.</param>
204 /// <param name="fromInt32">A conversion function from the enum type to <see cref="Int32"/>.</param>
205 /// <returns>A codec for the given tag.</returns>
206 public static FieldCodec<T> ForEnum<T>(uint tag, Func<T, int> toInt32, F unc<int, T> fromInt32)
207 {
208 return new FieldCodec<T>(input => fromInt32(
209 input.ReadEnum()),
210 (output, value) => output.WriteEnum(toInt32(value)),
211 value => CodedOutputStream.ComputeEnumSize(toInt32(value)), tag) ;
212 }
213
214 /// <summary>
215 /// Retrieves a codec suitable for a message field with the given tag.
216 /// </summary>
217 /// <param name="tag">The tag.</param>
218 /// <param name="parser">A parser to use for the message type.</param>
219 /// <returns>A codec for the given tag.</returns>
220 public static FieldCodec<T> ForMessage<T>(uint tag, MessageParser<T> par ser) where T : IMessage<T>
221 {
222 return new FieldCodec<T>(input => { T message = parser.CreateTemplat e(); input.ReadMessage(message); return message; },
223 (output, value) => output.WriteMessage(value), message => CodedO utputStream.ComputeMessageSize(message), tag);
224 }
225
226 /// <summary>
227 /// Creates a codec for a wrapper type of a class - which must be string or ByteString.
228 /// </summary>
229 public static FieldCodec<T> ForClassWrapper<T>(uint tag) where T : class
230 {
231 var nestedCodec = WrapperCodecs.GetCodec<T>();
232 return new FieldCodec<T>(
233 input => WrapperCodecs.Read<T>(input, nestedCodec),
234 (output, value) => WrapperCodecs.Write<T>(output, value, nestedC odec),
235 value => WrapperCodecs.CalculateSize<T>(value, nestedCodec),
236 tag,
237 null); // Default value for the wrapper
238 }
239
240 /// <summary>
241 /// Creates a codec for a wrapper type of a struct - which must be Int32 , Int64, UInt32, UInt64,
242 /// Bool, Single or Double.
243 /// </summary>
244 public static FieldCodec<T?> ForStructWrapper<T>(uint tag) where T : str uct
245 {
246 var nestedCodec = WrapperCodecs.GetCodec<T>();
247 return new FieldCodec<T?>(
248 input => WrapperCodecs.Read<T>(input, nestedCodec),
249 (output, value) => WrapperCodecs.Write<T>(output, value.Value, n estedCodec),
250 value => value == null ? 0 : WrapperCodecs.CalculateSize<T>(valu e.Value, nestedCodec),
251 tag,
252 null); // Default value for the wrapper
253 }
254
255 /// <summary>
256 /// Helper code to create codecs for wrapper types.
257 /// </summary>
258 /// <remarks>
259 /// Somewhat ugly with all the static methods, but the conversions invol ved to/from nullable types make it
260 /// slightly tricky to improve. So long as we keep the public API (ForCl assWrapper, ForStructWrapper) in place,
261 /// we can refactor later if we come up with something cleaner.
262 /// </remarks>
263 private static class WrapperCodecs
264 {
265 private static readonly Dictionary<System.Type, object> Codecs = new Dictionary<System.Type, object>
266 {
267 { typeof(bool), ForBool(WireFormat.MakeTag(WrappersReflection.Wr apperValueFieldNumber, WireFormat.WireType.Varint)) },
268 { typeof(int), ForInt32(WireFormat.MakeTag(WrappersReflection.Wr apperValueFieldNumber, WireFormat.WireType.Varint)) },
269 { typeof(long), ForInt64(WireFormat.MakeTag(WrappersReflection.W rapperValueFieldNumber, WireFormat.WireType.Varint)) },
270 { typeof(uint), ForUInt32(WireFormat.MakeTag(WrappersReflection. WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
271 { typeof(ulong), ForUInt64(WireFormat.MakeTag(WrappersReflection .WrapperValueFieldNumber, WireFormat.WireType.Varint)) },
272 { typeof(float), ForFloat(WireFormat.MakeTag(WrappersReflection. WrapperValueFieldNumber, WireFormat.WireType.Fixed32)) },
273 { typeof(double), ForDouble(WireFormat.MakeTag(WrappersReflectio n.WrapperValueFieldNumber, WireFormat.WireType.Fixed64)) },
274 { typeof(string), ForString(WireFormat.MakeTag(WrappersReflectio n.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) },
275 { typeof(ByteString), ForBytes(WireFormat.MakeTag(WrappersReflec tion.WrapperValueFieldNumber, WireFormat.WireType.LengthDelimited)) }
276 };
277
278 /// <summary>
279 /// Returns a field codec which effectively wraps a value of type T in a message.
280 ///
281 /// </summary>
282 internal static FieldCodec<T> GetCodec<T>()
283 {
284 object value;
285 if (!Codecs.TryGetValue(typeof(T), out value))
286 {
287 throw new InvalidOperationException("Invalid type argument r equested for wrapper codec: " + typeof(T));
288 }
289 return (FieldCodec<T>) value;
290 }
291
292 internal static T Read<T>(CodedInputStream input, FieldCodec<T> code c)
293 {
294 int length = input.ReadLength();
295 int oldLimit = input.PushLimit(length);
296
297 uint tag;
298 T value = codec.DefaultValue;
299 while ((tag = input.ReadTag()) != 0)
300 {
301 if (tag == codec.Tag)
302 {
303 value = codec.Read(input);
304 }
305 else
306 {
307 input.SkipLastField();
308 }
309
310 }
311 input.CheckReadEndOfStreamTag();
312 input.PopLimit(oldLimit);
313
314 return value;
315 }
316
317 internal static void Write<T>(CodedOutputStream output, T value, Fie ldCodec<T> codec)
318 {
319 output.WriteLength(codec.CalculateSizeWithTag(value));
320 codec.WriteTagAndValue(output, value);
321 }
322
323 internal static int CalculateSize<T>(T value, FieldCodec<T> codec)
324 {
325 int fieldLength = codec.CalculateSizeWithTag(value);
326 return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldL ength;
327 }
328 }
329 }
330
331 /// <summary>
332 /// An encode/decode pair for a single field. This effectively encapsulates
333 /// all the information needed to read or write the field value from/to a co ded
334 /// stream.
335 /// </summary>
336 /// <remarks>
337 /// This never writes default values to the stream, and is not currently des igned
338 /// to play well with packed arrays.
339 /// </remarks>
340 public sealed class FieldCodec<T>
341 {
342 private static readonly T DefaultDefault;
343
344 static FieldCodec()
345 {
346 if (typeof(T) == typeof(string))
347 {
348 DefaultDefault = (T)(object)"";
349 }
350 else if (typeof(T) == typeof(ByteString))
351 {
352 DefaultDefault = (T)(object)ByteString.Empty;
353 }
354 // Otherwise it's the default value of the CLR type
355 }
356
357 private static Func<T, bool> CreateDefaultValueCheck<TTmp>(Func<TTmp, bo ol> check)
358 {
359 return (Func<T, bool>)(object)check;
360 }
361
362 private readonly Func<CodedInputStream, T> reader;
363 private readonly Action<CodedOutputStream, T> writer;
364 private readonly Func<T, int> sizeCalculator;
365 private readonly uint tag;
366 private readonly int tagSize;
367 private readonly int fixedSize;
368 // Default value for this codec. Usually the same for every instance of the same type, but
369 // for string/ByteString wrapper fields the codec's default value is nul l, whereas for
370 // other string/ByteString fields it's "" or ByteString.Empty.
371 private readonly T defaultValue;
372
373 internal FieldCodec(
374 Func<CodedInputStream, T> reader,
375 Action<CodedOutputStream, T> writer,
376 Func<T, int> sizeCalculator,
377 uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault )
378 {
379 }
380
381 internal FieldCodec(
382 Func<CodedInputStream, T> reader,
383 Action<CodedOutputStream, T> writer,
384 Func<T, int> sizeCalculator,
385 uint tag,
386 T defaultValue)
387 {
388 this.reader = reader;
389 this.writer = writer;
390 this.sizeCalculator = sizeCalculator;
391 this.fixedSize = 0;
392 this.tag = tag;
393 this.defaultValue = defaultValue;
394 tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
395 }
396
397 internal FieldCodec(
398 Func<CodedInputStream, T> reader,
399 Action<CodedOutputStream, T> writer,
400 int fixedSize,
401 uint tag)
402 {
403 this.reader = reader;
404 this.writer = writer;
405 this.sizeCalculator = _ => fixedSize;
406 this.fixedSize = fixedSize;
407 this.tag = tag;
408 tagSize = CodedOutputStream.ComputeRawVarint32Size(tag);
409 }
410
411 /// <summary>
412 /// Returns the size calculator for just a value.
413 /// </summary>
414 internal Func<T, int> ValueSizeCalculator { get { return sizeCalculator; } }
415
416 /// <summary>
417 /// Returns a delegate to write a value (unconditionally) to a coded out put stream.
418 /// </summary>
419 internal Action<CodedOutputStream, T> ValueWriter { get { return writer; } }
420
421 /// <summary>
422 /// Returns a delegate to read a value from a coded input stream. It is assumed that
423 /// the stream is already positioned on the appropriate tag.
424 /// </summary>
425 internal Func<CodedInputStream, T> ValueReader { get { return reader; } }
426
427 /// <summary>
428 /// Returns the fixed size for an entry, or 0 if sizes vary.
429 /// </summary>
430 internal int FixedSize { get { return fixedSize; } }
431
432 /// <summary>
433 /// Gets the tag of the codec.
434 /// </summary>
435 /// <value>
436 /// The tag of the codec.
437 /// </value>
438 public uint Tag { get { return tag; } }
439
440 /// <summary>
441 /// Gets the default value of the codec's type.
442 /// </summary>
443 /// <value>
444 /// The default value of the codec's type.
445 /// </value>
446 public T DefaultValue { get { return defaultValue; } }
447
448 /// <summary>
449 /// Write a tag and the given value, *if* the value is not the default.
450 /// </summary>
451 public void WriteTagAndValue(CodedOutputStream output, T value)
452 {
453 if (!IsDefault(value))
454 {
455 output.WriteTag(tag);
456 writer(output, value);
457 }
458 }
459
460 /// <summary>
461 /// Reads a value of the codec type from the given <see cref="CodedInput Stream"/>.
462 /// </summary>
463 /// <param name="input">The input stream to read from.</param>
464 /// <returns>The value read from the stream.</returns>
465 public T Read(CodedInputStream input)
466 {
467 return reader(input);
468 }
469
470 /// <summary>
471 /// Calculates the size required to write the given value, with a tag,
472 /// if the value is not the default.
473 /// </summary>
474 public int CalculateSizeWithTag(T value)
475 {
476 return IsDefault(value) ? 0 : sizeCalculator(value) + tagSize;
477 }
478
479 private bool IsDefault(T value)
480 {
481 return EqualityComparer<T>.Default.Equals(value, defaultValue);
482 }
483 }
484 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698