ExtendableMessage.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using Google.ProtocolBuffers.Descriptors;
  5. using Google.ProtocolBuffers.Collections;
  6. namespace Google.ProtocolBuffers {
  7. public abstract class ExtendableMessage<TMessage, TBuilder> : GeneratedMessage<TMessage, TBuilder>
  8. where TMessage : GeneratedMessage<TMessage, TBuilder>
  9. where TBuilder : GeneratedBuilder<TMessage, TBuilder> {
  10. protected ExtendableMessage() {}
  11. private readonly FieldSet extensions = FieldSet.CreateFieldSet();
  12. /// <summary>
  13. /// Access for the builder.
  14. /// </summary>
  15. internal FieldSet Extensions {
  16. get { return extensions; }
  17. }
  18. /// <summary>
  19. /// Checks if a singular extension is present.
  20. /// </summary>
  21. public bool HasExtension<TExtension>(GeneratedExtensionBase<TExtension> extension) {
  22. return extensions.HasField(extension.Descriptor);
  23. }
  24. /// <summary>
  25. /// Returns the number of elements in a repeated extension.
  26. /// </summary>
  27. public int GetExtensionCount<TExtension>(GeneratedExtensionBase<IList<TExtension>> extension) {
  28. return extensions.GetRepeatedFieldCount(extension.Descriptor);
  29. }
  30. /// <summary>
  31. /// Returns the value of an extension.
  32. /// </summary>
  33. public TExtension GetExtension<TExtension>(GeneratedExtensionBase<TExtension> extension) {
  34. object value = extensions[extension.Descriptor];
  35. if (value == null) {
  36. return (TExtension) extension.MessageDefaultInstance;
  37. } else {
  38. return (TExtension) extension.FromReflectionType(value);
  39. }
  40. }
  41. /// <summary>
  42. /// Returns one element of a repeated extension.
  43. /// </summary>
  44. public TExtension GetExtension<TExtension>(GeneratedExtensionBase<IList<TExtension>> extension, int index) {
  45. return (TExtension) extension.SingularFromReflectionType(extensions[extension.Descriptor, index]);
  46. }
  47. /// <summary>
  48. /// Called by subclasses to check if all extensions are initialized.
  49. /// </summary>
  50. protected bool ExtensionsAreInitialized {
  51. get { return extensions.IsInitialized; }
  52. }
  53. #region Reflection
  54. public override IDictionary<FieldDescriptor, object> AllFields {
  55. get {
  56. IDictionary<FieldDescriptor, object> result = GetMutableFieldMap();
  57. foreach(KeyValuePair<FieldDescriptor, object> entry in extensions.AllFields) {
  58. result[entry.Key] = entry.Value;
  59. }
  60. return Dictionaries.AsReadOnly(result);
  61. }
  62. }
  63. public override bool HasField(FieldDescriptor field) {
  64. if (field.IsExtension) {
  65. VerifyContainingType(field);
  66. return extensions.HasField(field);
  67. } else {
  68. return base.HasField(field);
  69. }
  70. }
  71. public override object this[FieldDescriptor field] {
  72. get {
  73. if (field.IsExtension) {
  74. VerifyContainingType(field);
  75. object value = extensions[field];
  76. if (value == null) {
  77. // Lacking an ExtensionRegistry, we have no way to determine the
  78. // extension's real type, so we return a DynamicMessage.
  79. // TODO(jonskeet): Work out what this means
  80. return DynamicMessage.GetDefaultInstance(field.MessageType);
  81. } else {
  82. return value;
  83. }
  84. } else {
  85. return base[field];
  86. }
  87. }
  88. }
  89. public override int GetRepeatedFieldCount(FieldDescriptor field) {
  90. if (field.IsExtension) {
  91. VerifyContainingType(field);
  92. return extensions.GetRepeatedFieldCount(field);
  93. } else {
  94. return base.GetRepeatedFieldCount(field);
  95. }
  96. }
  97. public override object this[FieldDescriptor field, int index] {
  98. get {
  99. if (field.IsExtension) {
  100. VerifyContainingType(field);
  101. return extensions[field, index];
  102. } else {
  103. return base[field, index];
  104. }
  105. }
  106. }
  107. internal void VerifyContainingType(FieldDescriptor field) {
  108. if (field.ContainingType != DescriptorForType) {
  109. throw new ArgumentException("FieldDescriptor does not match message type.");
  110. }
  111. }
  112. #endregion
  113. /// <summary>
  114. /// Used by subclasses to serialize extensions. Extension ranges may be
  115. /// interleaves with field numbers, but we must write them in canonical
  116. /// (sorted by field number) order. This class helps us to write individual
  117. /// ranges of extensions at once.
  118. ///
  119. /// TODO(jonskeet): See if we can improve this in terms of readability.
  120. /// </summary>
  121. protected class ExtensionWriter {
  122. readonly IEnumerator<KeyValuePair<FieldDescriptor, object>> iterator;
  123. readonly FieldSet extensions;
  124. KeyValuePair<FieldDescriptor, object>? next = null;
  125. internal ExtensionWriter(ExtendableMessage<TMessage, TBuilder> message) {
  126. extensions = message.extensions;
  127. iterator = message.extensions.GetEnumerator();
  128. if (iterator.MoveNext()) {
  129. next = iterator.Current;
  130. }
  131. }
  132. public void WriteUntil(int end, CodedOutputStream output) {
  133. while (next != null && next.Value.Key.FieldNumber < end) {
  134. extensions.WriteField(next.Value.Key, next.Value.Value, output);
  135. if (iterator.MoveNext()) {
  136. next = iterator.Current;
  137. } else {
  138. next = null;
  139. }
  140. }
  141. }
  142. }
  143. protected ExtensionWriter CreateExtensionWriter(ExtendableMessage<TMessage, TBuilder> message) {
  144. return new ExtensionWriter(message);
  145. }
  146. /// <summary>
  147. /// Called by subclasses to compute the size of extensions.
  148. /// </summary>
  149. protected int ExtensionsSerializedSize {
  150. get { return extensions.SerializedSize; }
  151. }
  152. internal void VerifyExtensionContainingType<TExtension>(GeneratedExtensionBase<TExtension> extension) {
  153. if (extension.Descriptor.ContainingType != DescriptorForType) {
  154. // This can only happen if someone uses unchecked operations.
  155. throw new ArgumentException("Extension is for type \"" + extension.Descriptor.ContainingType.FullName
  156. + "\" which does not match message type \"" + DescriptorForType.FullName + "\".");
  157. }
  158. }
  159. }
  160. }