| OLD | NEW |
| 1 #region Copyright notice and license | 1 #region Copyright notice and license |
| 2 // Protocol Buffers - Google's data interchange format | 2 // Protocol Buffers - Google's data interchange format |
| 3 // Copyright 2015 Google Inc. All rights reserved. | 3 // Copyright 2015 Google Inc. All rights reserved. |
| 4 // https://developers.google.com/protocol-buffers/ | 4 // https://developers.google.com/protocol-buffers/ |
| 5 // | 5 // |
| 6 // Redistribution and use in source and binary forms, with or without | 6 // Redistribution and use in source and binary forms, with or without |
| 7 // modification, are permitted provided that the following conditions are | 7 // modification, are permitted provided that the following conditions are |
| 8 // met: | 8 // met: |
| 9 // | 9 // |
| 10 // * Redistributions of source code must retain the above copyright | 10 // * Redistributions of source code must retain the above copyright |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 #endregion | 31 #endregion |
| 32 | 32 |
| 33 using Google.Protobuf.Compatibility; |
| 33 using Google.Protobuf.WellKnownTypes; | 34 using Google.Protobuf.WellKnownTypes; |
| 34 using System; | 35 using System; |
| 35 using System.Collections.Generic; | 36 using System.Collections.Generic; |
| 36 | 37 |
| 37 namespace Google.Protobuf | 38 namespace Google.Protobuf |
| 38 { | 39 { |
| 39 /// <summary> | 40 /// <summary> |
| 40 /// Factory methods for <see cref="FieldCodec{T}"/>. | 41 /// Factory methods for <see cref="FieldCodec{T}"/>. |
| 41 /// </summary> | 42 /// </summary> |
| 42 public static class FieldCodec | 43 public static class FieldCodec |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 322 | 323 |
| 323 internal static int CalculateSize<T>(T value, FieldCodec<T> codec) | 324 internal static int CalculateSize<T>(T value, FieldCodec<T> codec) |
| 324 { | 325 { |
| 325 int fieldLength = codec.CalculateSizeWithTag(value); | 326 int fieldLength = codec.CalculateSizeWithTag(value); |
| 326 return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldL
ength; | 327 return CodedOutputStream.ComputeLengthSize(fieldLength) + fieldL
ength; |
| 327 } | 328 } |
| 328 } | 329 } |
| 329 } | 330 } |
| 330 | 331 |
| 331 /// <summary> | 332 /// <summary> |
| 333 /// <para> |
| 332 /// An encode/decode pair for a single field. This effectively encapsulates | 334 /// 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 | 335 /// all the information needed to read or write the field value from/to a co
ded |
| 334 /// stream. | 336 /// stream. |
| 337 /// </para> |
| 338 /// <para> |
| 339 /// This class is public and has to be as it is used by generated code, but
its public |
| 340 /// API is very limited - just what the generated code needs to call directl
y. |
| 341 /// </para> |
| 335 /// </summary> | 342 /// </summary> |
| 336 /// <remarks> | 343 /// <remarks> |
| 337 /// This never writes default values to the stream, and is not currently des
igned | 344 /// This never writes default values to the stream, and does not address "pa
ckedness" |
| 338 /// to play well with packed arrays. | 345 /// in repeated fields itself, other than to know whether or not the field *
should* be packed. |
| 339 /// </remarks> | 346 /// </remarks> |
| 340 public sealed class FieldCodec<T> | 347 public sealed class FieldCodec<T> |
| 341 { | 348 { |
| 342 private static readonly T DefaultDefault; | 349 private static readonly T DefaultDefault; |
| 350 private static readonly bool TypeSupportsPacking = typeof(T).IsValueType
() && Nullable.GetUnderlyingType(typeof(T)) == null; |
| 343 | 351 |
| 344 static FieldCodec() | 352 static FieldCodec() |
| 345 { | 353 { |
| 346 if (typeof(T) == typeof(string)) | 354 if (typeof(T) == typeof(string)) |
| 347 { | 355 { |
| 348 DefaultDefault = (T)(object)""; | 356 DefaultDefault = (T)(object)""; |
| 349 } | 357 } |
| 350 else if (typeof(T) == typeof(ByteString)) | 358 else if (typeof(T) == typeof(ByteString)) |
| 351 { | 359 { |
| 352 DefaultDefault = (T)(object)ByteString.Empty; | 360 DefaultDefault = (T)(object)ByteString.Empty; |
| 353 } | 361 } |
| 354 // Otherwise it's the default value of the CLR type | 362 // Otherwise it's the default value of the CLR type |
| 355 } | 363 } |
| 356 | 364 |
| 357 private static Func<T, bool> CreateDefaultValueCheck<TTmp>(Func<TTmp, bo
ol> check) | 365 internal static bool IsPackedRepeatedField(uint tag) => |
| 358 { | 366 TypeSupportsPacking && WireFormat.GetTagWireType(tag) == WireFormat.
WireType.LengthDelimited; |
| 359 return (Func<T, bool>)(object)check; | |
| 360 } | |
| 361 | 367 |
| 362 private readonly Func<CodedInputStream, T> reader; | 368 internal bool PackedRepeatedField { get; } |
| 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 | 369 |
| 373 internal FieldCodec( | 370 /// <summary> |
| 374 Func<CodedInputStream, T> reader, | 371 /// Returns a delegate to write a value (unconditionally) to a coded out
put stream. |
| 375 Action<CodedOutputStream, T> writer, | 372 /// </summary> |
| 376 Func<T, int> sizeCalculator, | 373 internal Action<CodedOutputStream, T> ValueWriter { get; } |
| 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 | 374 |
| 411 /// <summary> | 375 /// <summary> |
| 412 /// Returns the size calculator for just a value. | 376 /// Returns the size calculator for just a value. |
| 413 /// </summary> | 377 /// </summary> |
| 414 internal Func<T, int> ValueSizeCalculator { get { return sizeCalculator;
} } | 378 internal Func<T, int> ValueSizeCalculator { get; } |
| 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 | 379 |
| 421 /// <summary> | 380 /// <summary> |
| 422 /// Returns a delegate to read a value from a coded input stream. It is
assumed that | 381 /// 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. | 382 /// the stream is already positioned on the appropriate tag. |
| 424 /// </summary> | 383 /// </summary> |
| 425 internal Func<CodedInputStream, T> ValueReader { get { return reader; }
} | 384 internal Func<CodedInputStream, T> ValueReader { get; } |
| 426 | 385 |
| 427 /// <summary> | 386 /// <summary> |
| 428 /// Returns the fixed size for an entry, or 0 if sizes vary. | 387 /// Returns the fixed size for an entry, or 0 if sizes vary. |
| 429 /// </summary> | 388 /// </summary> |
| 430 internal int FixedSize { get { return fixedSize; } } | 389 internal int FixedSize { get; } |
| 431 | 390 |
| 432 /// <summary> | 391 /// <summary> |
| 433 /// Gets the tag of the codec. | 392 /// Gets the tag of the codec. |
| 434 /// </summary> | 393 /// </summary> |
| 435 /// <value> | 394 /// <value> |
| 436 /// The tag of the codec. | 395 /// The tag of the codec. |
| 437 /// </value> | 396 /// </value> |
| 438 public uint Tag { get { return tag; } } | 397 internal uint Tag { get; } |
| 439 | 398 |
| 440 /// <summary> | 399 /// <summary> |
| 441 /// Gets the default value of the codec's type. | 400 /// Default value for this codec. Usually the same for every instance of
the same type, but |
| 401 /// for string/ByteString wrapper fields the codec's default value is nu
ll, whereas for |
| 402 /// other string/ByteString fields it's "" or ByteString.Empty. |
| 442 /// </summary> | 403 /// </summary> |
| 443 /// <value> | 404 /// <value> |
| 444 /// The default value of the codec's type. | 405 /// The default value of the codec's type. |
| 445 /// </value> | 406 /// </value> |
| 446 public T DefaultValue { get { return defaultValue; } } | 407 internal T DefaultValue { get; } |
| 408 |
| 409 private readonly int tagSize; |
| 410 |
| 411 internal FieldCodec( |
| 412 Func<CodedInputStream, T> reader, |
| 413 Action<CodedOutputStream, T> writer, |
| 414 int fixedSize, |
| 415 uint tag) : this(reader, writer, _ => fixedSize, tag) |
| 416 { |
| 417 FixedSize = fixedSize; |
| 418 } |
| 419 |
| 420 internal FieldCodec( |
| 421 Func<CodedInputStream, T> reader, |
| 422 Action<CodedOutputStream, T> writer, |
| 423 Func<T, int> sizeCalculator, |
| 424 uint tag) : this(reader, writer, sizeCalculator, tag, DefaultDefault
) |
| 425 { |
| 426 } |
| 427 |
| 428 internal FieldCodec( |
| 429 Func<CodedInputStream, T> reader, |
| 430 Action<CodedOutputStream, T> writer, |
| 431 Func<T, int> sizeCalculator, |
| 432 uint tag, |
| 433 T defaultValue) |
| 434 { |
| 435 ValueReader = reader; |
| 436 ValueWriter = writer; |
| 437 ValueSizeCalculator = sizeCalculator; |
| 438 FixedSize = 0; |
| 439 Tag = tag; |
| 440 DefaultValue = defaultValue; |
| 441 tagSize = CodedOutputStream.ComputeRawVarint32Size(tag); |
| 442 // Detect packed-ness once, so we can check for it within RepeatedFi
eld<T>. |
| 443 PackedRepeatedField = IsPackedRepeatedField(tag); |
| 444 } |
| 447 | 445 |
| 448 /// <summary> | 446 /// <summary> |
| 449 /// Write a tag and the given value, *if* the value is not the default. | 447 /// Write a tag and the given value, *if* the value is not the default. |
| 450 /// </summary> | 448 /// </summary> |
| 451 public void WriteTagAndValue(CodedOutputStream output, T value) | 449 public void WriteTagAndValue(CodedOutputStream output, T value) |
| 452 { | 450 { |
| 453 if (!IsDefault(value)) | 451 if (!IsDefault(value)) |
| 454 { | 452 { |
| 455 output.WriteTag(tag); | 453 output.WriteTag(Tag); |
| 456 writer(output, value); | 454 ValueWriter(output, value); |
| 457 } | 455 } |
| 458 } | 456 } |
| 459 | 457 |
| 460 /// <summary> | 458 /// <summary> |
| 461 /// Reads a value of the codec type from the given <see cref="CodedInput
Stream"/>. | 459 /// Reads a value of the codec type from the given <see cref="CodedInput
Stream"/>. |
| 462 /// </summary> | 460 /// </summary> |
| 463 /// <param name="input">The input stream to read from.</param> | 461 /// <param name="input">The input stream to read from.</param> |
| 464 /// <returns>The value read from the stream.</returns> | 462 /// <returns>The value read from the stream.</returns> |
| 465 public T Read(CodedInputStream input) | 463 public T Read(CodedInputStream input) => ValueReader(input); |
| 466 { | |
| 467 return reader(input); | |
| 468 } | |
| 469 | 464 |
| 470 /// <summary> | 465 /// <summary> |
| 471 /// Calculates the size required to write the given value, with a tag, | 466 /// Calculates the size required to write the given value, with a tag, |
| 472 /// if the value is not the default. | 467 /// if the value is not the default. |
| 473 /// </summary> | 468 /// </summary> |
| 474 public int CalculateSizeWithTag(T value) | 469 public int CalculateSizeWithTag(T value) => IsDefault(value) ? 0 : Value
SizeCalculator(value) + tagSize; |
| 475 { | |
| 476 return IsDefault(value) ? 0 : sizeCalculator(value) + tagSize; | |
| 477 } | |
| 478 | 470 |
| 479 private bool IsDefault(T value) | 471 private bool IsDefault(T value) => EqualityComparer<T>.Default.Equals(va
lue, DefaultValue); |
| 480 { | |
| 481 return EqualityComparer<T>.Default.Equals(value, defaultValue); | |
| 482 } | |
| 483 } | 472 } |
| 484 } | 473 } |
| OLD | NEW |