ExtensionRegistry.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc.
  3. // http://code.google.com/p/protobuf/
  4. //
  5. // Licensed under the Apache License, Version 2.0 (the "License");
  6. // you may not use this file except in compliance with the License.
  7. // You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing, software
  12. // distributed under the License is distributed on an "AS IS" BASIS,
  13. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. // See the License for the specific language governing permissions and
  15. // limitations under the License.
  16. using System.Collections.Generic;
  17. using Google.ProtocolBuffers.Descriptors;
  18. using System;
  19. namespace Google.ProtocolBuffers {
  20. /// <summary>
  21. /// TODO(jonskeet): Copy docs from Java
  22. /// </summary>
  23. public sealed class ExtensionRegistry {
  24. private static readonly ExtensionRegistry empty = new ExtensionRegistry(
  25. new Dictionary<string, ExtensionInfo>(),
  26. new Dictionary<DescriptorIntPair, ExtensionInfo>(),
  27. true);
  28. private readonly IDictionary<string, ExtensionInfo> extensionsByName;
  29. private readonly IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
  30. private readonly bool readOnly;
  31. private ExtensionRegistry(IDictionary<String, ExtensionInfo> extensionsByName,
  32. IDictionary<DescriptorIntPair, ExtensionInfo> extensionsByNumber,
  33. bool readOnly) {
  34. this.extensionsByName = extensionsByName;
  35. this.extensionsByNumber = extensionsByNumber;
  36. this.readOnly = readOnly;
  37. }
  38. /// <summary>
  39. /// Construct a new, empty instance.
  40. /// </summary>
  41. public static ExtensionRegistry CreateInstance() {
  42. return new ExtensionRegistry(new Dictionary<string, ExtensionInfo>(),
  43. new Dictionary<DescriptorIntPair, ExtensionInfo>(), false);
  44. }
  45. /// <summary>
  46. /// Get the unmodifiable singleton empty instance.
  47. /// </summary>
  48. public static ExtensionRegistry Empty {
  49. get { return empty; }
  50. }
  51. public ExtensionRegistry AsReadOnly() {
  52. return new ExtensionRegistry(extensionsByName, extensionsByNumber, true);
  53. }
  54. /// <summary>
  55. /// Finds an extension by fully-qualified field name, in the
  56. /// proto namespace, i.e. result.Descriptor.FullName will match
  57. /// <paramref name="fullName"/> if a match is found. A null
  58. /// reference is returned if the extension can't be found.
  59. /// </summary>
  60. public ExtensionInfo this[string fullName] {
  61. get {
  62. ExtensionInfo ret;
  63. extensionsByName.TryGetValue(fullName, out ret);
  64. return ret;
  65. }
  66. }
  67. /// <summary>
  68. /// Finds an extension by containing type and field number.
  69. /// A null reference is returned if the extension can't be found.
  70. /// </summary>
  71. public ExtensionInfo this[MessageDescriptor containingType, int fieldNumber] {
  72. get {
  73. ExtensionInfo ret;
  74. extensionsByNumber.TryGetValue(new DescriptorIntPair(containingType, fieldNumber), out ret);
  75. return ret;
  76. }
  77. }
  78. /// <summary>
  79. /// Add an extension from a generated file to the registry.
  80. /// </summary>
  81. public void Add<TContainer, TExtension> (GeneratedExtension<TContainer, TExtension> extension)
  82. where TContainer : IMessage<TContainer> {
  83. if (extension.Descriptor.MappedType == MappedType.Message) {
  84. Add(new ExtensionInfo(extension.Descriptor, extension.MessageDefaultInstance));
  85. } else {
  86. Add(new ExtensionInfo(extension.Descriptor, null));
  87. }
  88. }
  89. /// <summary>
  90. /// Adds a non-message-type extension to the registry by descriptor.
  91. /// </summary>
  92. /// <param name="type"></param>
  93. public void Add(FieldDescriptor type) {
  94. if (type.MappedType == MappedType.Message) {
  95. throw new ArgumentException("ExtensionRegistry.Add() must be provided a default instance "
  96. + "when adding an embedded message extension.");
  97. }
  98. Add(new ExtensionInfo(type, null));
  99. }
  100. /// <summary>
  101. /// Adds a message-type-extension to the registry by descriptor.
  102. /// </summary>
  103. /// <param name="type"></param>
  104. /// <param name="defaultInstance"></param>
  105. public void Add(FieldDescriptor type, IMessage defaultInstance) {
  106. if (type.MappedType != MappedType.Message) {
  107. throw new ArgumentException("ExtensionRegistry.Add() provided a default instance for a "
  108. + "non-message extension.");
  109. }
  110. Add(new ExtensionInfo(type, defaultInstance));
  111. }
  112. private void Add(ExtensionInfo extension) {
  113. if (readOnly) {
  114. throw new InvalidOperationException("Cannot add entries to a read-only extension registry");
  115. }
  116. if (!extension.Descriptor.IsExtension) {
  117. throw new ArgumentException("ExtensionRegistry.add() was given a FieldDescriptor for a "
  118. + "regular (non-extension) field.");
  119. }
  120. extensionsByName[extension.Descriptor.FullName] = extension;
  121. extensionsByNumber[new DescriptorIntPair(extension.Descriptor.ContainingType,
  122. extension.Descriptor.FieldNumber)] = extension;
  123. FieldDescriptor field = extension.Descriptor;
  124. if (field.ContainingType.Options.MessageSetWireFormat
  125. && field.FieldType == FieldType.Message
  126. && field.IsOptional
  127. && field.ExtensionScope == field.MessageType) {
  128. // This is an extension of a MessageSet type defined within the extension
  129. // type's own scope. For backwards-compatibility, allow it to be looked
  130. // up by type name.
  131. extensionsByName[field.MessageType.FullName] = extension;
  132. }
  133. }
  134. /// <summary>
  135. /// Nested type just used to represent a pair of MessageDescriptor and int, as
  136. /// the key into the "by number" map.
  137. /// </summary>
  138. private struct DescriptorIntPair : IEquatable<DescriptorIntPair> {
  139. readonly MessageDescriptor descriptor;
  140. readonly int number;
  141. internal DescriptorIntPair(MessageDescriptor descriptor, int number) {
  142. this.descriptor = descriptor;
  143. this.number = number;
  144. }
  145. public override int GetHashCode() {
  146. return descriptor.GetHashCode() * ((1 << 16) - 1) + number;
  147. }
  148. public override bool Equals(object obj) {
  149. if (!(obj is DescriptorIntPair)) {
  150. return false;
  151. }
  152. return Equals((DescriptorIntPair)obj);
  153. }
  154. public bool Equals(DescriptorIntPair other) {
  155. return descriptor == other.descriptor && number == other.number;
  156. }
  157. }
  158. }
  159. }