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

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

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

Powered by Google App Engine
This is Rietveld 408576698