FileDescriptor.cs 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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;
  17. using System.Collections.Generic;
  18. using System.Collections.ObjectModel;
  19. using Google.ProtocolBuffers.DescriptorProtos;
  20. namespace Google.ProtocolBuffers.Descriptors {
  21. /// <summary>
  22. /// Describes a .proto file, including everything defined within.
  23. /// IDescriptor is implemented such that the File property returns this descriptor,
  24. /// and the FullName is the same as the Name.
  25. /// </summary>
  26. public sealed class FileDescriptor : IDescriptor<FileDescriptorProto> {
  27. private readonly FileDescriptorProto proto;
  28. private readonly IList<MessageDescriptor> messageTypes;
  29. private readonly IList<EnumDescriptor> enumTypes;
  30. private readonly IList<ServiceDescriptor> services;
  31. private readonly IList<FieldDescriptor> extensions;
  32. private readonly IList<FileDescriptor> dependencies;
  33. private readonly DescriptorPool pool;
  34. private FileDescriptor(FileDescriptorProto proto, FileDescriptor[] dependencies, DescriptorPool pool) {
  35. this.pool = pool;
  36. this.proto = proto;
  37. this.dependencies = new ReadOnlyCollection<FileDescriptor>((FileDescriptor[]) dependencies.Clone());
  38. pool.AddPackage(Package, this);
  39. messageTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.MessageTypeList,
  40. (message, index) => new MessageDescriptor(message, this, null, index));
  41. enumTypes = DescriptorUtil.ConvertAndMakeReadOnly(proto.EnumTypeList,
  42. (enumType, index) => new EnumDescriptor(enumType, this, null, index));
  43. services = DescriptorUtil.ConvertAndMakeReadOnly(proto.ServiceList,
  44. (service, index) => new ServiceDescriptor(service, this, index));
  45. extensions = DescriptorUtil.ConvertAndMakeReadOnly(proto.ExtensionList,
  46. (field, index) => new FieldDescriptor(field, this, null, index, true));
  47. }
  48. /// <value>
  49. /// The descriptor in its protocol message representation.
  50. /// </value>
  51. public FileDescriptorProto Proto {
  52. get { return proto; }
  53. }
  54. /// <value>
  55. /// The <see cref="FileOptions" /> defined in <c>descriptor.proto</c>.
  56. /// </value>
  57. public FileOptions Options {
  58. get { return proto.Options; }
  59. }
  60. /// <value>
  61. /// The file name.
  62. /// </value>
  63. public string Name {
  64. get { return proto.Name; }
  65. }
  66. /// <summary>
  67. /// The package as declared in the .proto file. This may or may not
  68. /// be equivalent to the .NET namespace of the generated classes.
  69. /// </summary>
  70. public string Package {
  71. get { return proto.Package; }
  72. }
  73. /// <value>
  74. /// Unmodifiable list of top-level message types declared in this file.
  75. /// </value>
  76. public IList<MessageDescriptor> MessageTypes {
  77. get { return messageTypes; }
  78. }
  79. /// <value>
  80. /// Unmodifiable list of top-level enum types declared in this file.
  81. /// </value>
  82. public IList<EnumDescriptor> EnumTypes {
  83. get { return enumTypes; }
  84. }
  85. /// <value>
  86. /// Unmodifiable list of top-level services declared in this file.
  87. /// </value>
  88. public IList<ServiceDescriptor> Services {
  89. get { return services; }
  90. }
  91. /// <value>
  92. /// Unmodifiable list of top-level extensions declared in this file.
  93. /// </value>
  94. public IList<FieldDescriptor> Extensions {
  95. get { return extensions; }
  96. }
  97. /// <value>
  98. /// Unmodifiable list of this file's dependencies (imports).
  99. /// </value>
  100. public IList<FileDescriptor> Dependencies {
  101. get { return dependencies; }
  102. }
  103. /// <value>
  104. /// Implementation of IDescriptor.FullName - just returns the same as Name.
  105. /// </value>
  106. string IDescriptor.FullName {
  107. get { return Name; }
  108. }
  109. /// <value>
  110. /// Implementation of IDescriptor.File - just returns this descriptor.
  111. /// </value>
  112. FileDescriptor IDescriptor.File {
  113. get { return this; }
  114. }
  115. /// <value>
  116. /// Protocol buffer describing this descriptor.
  117. /// </value>
  118. IMessage IDescriptor.Proto {
  119. get { return Proto; }
  120. }
  121. /// <value>
  122. /// Pool containing symbol descriptors.
  123. /// </value>
  124. internal DescriptorPool DescriptorPool {
  125. get { return pool; }
  126. }
  127. /// <summary>
  128. /// Finds a type (message, enum, service or extension) in the file by name. Does not find nested types.
  129. /// </summary>
  130. /// <param name="name">The unqualified type name to look for.</param>
  131. /// <typeparam name="T">The type of descriptor to look for (or ITypeDescriptor for any)</typeparam>
  132. /// <returns>The type's descriptor, or null if not found.</returns>
  133. public T FindTypeByName<T>(String name)
  134. where T : class, IDescriptor {
  135. // Don't allow looking up nested types. This will make optimization
  136. // easier later.
  137. if (name.IndexOf('.') != -1) {
  138. return null;
  139. }
  140. if (Package.Length > 0) {
  141. name = Package + "." + name;
  142. }
  143. T result = pool.FindSymbol<T>(name);
  144. if (result != null && result.File == this) {
  145. return result;
  146. }
  147. return null;
  148. }
  149. /// <summary>
  150. /// Builds a FileDescriptor from its protocol buffer representation.
  151. /// </summary>
  152. /// <param name="proto">The protocol message form of the FileDescriptor.</param>
  153. /// <param name="dependencies">FileDescriptors corresponding to all of the
  154. /// file's dependencies, in the exact order listed in the .proto file. May be null,
  155. /// in which case it is treated as an empty array.</param>
  156. /// <exception cref="DescriptorValidationException">If <paramref name="proto"/> is not
  157. /// a valid descriptor. This can occur for a number of reasons, such as a field
  158. /// having an undefined type or because two messages were defined with the same name.</exception>
  159. public static FileDescriptor BuildFrom(FileDescriptorProto proto, FileDescriptor[] dependencies) {
  160. // Building descriptors involves two steps: translating and linking.
  161. // In the translation step (implemented by FileDescriptor's
  162. // constructor), we build an object tree mirroring the
  163. // FileDescriptorProto's tree and put all of the descriptors into the
  164. // DescriptorPool's lookup tables. In the linking step, we look up all
  165. // type references in the DescriptorPool, so that, for example, a
  166. // FieldDescriptor for an embedded message contains a pointer directly
  167. // to the Descriptor for that message's type. We also detect undefined
  168. // types in the linking step.
  169. if (dependencies == null) {
  170. dependencies = new FileDescriptor[0];
  171. }
  172. DescriptorPool pool = new DescriptorPool(dependencies);
  173. FileDescriptor result = new FileDescriptor(proto, dependencies, pool);
  174. if (dependencies.Length != proto.DependencyCount) {
  175. throw new DescriptorValidationException(result,
  176. "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
  177. "those listed in the FileDescriptorProto.");
  178. }
  179. for (int i = 0; i < proto.DependencyCount; i++) {
  180. if (dependencies[i].Name != proto.DependencyList[i]) {
  181. /*throw new DescriptorValidationException(result,
  182. "Dependencies passed to FileDescriptor.BuildFrom() don't match " +
  183. "those listed in the FileDescriptorProto.");*/
  184. }
  185. }
  186. result.CrossLink();
  187. return result;
  188. }
  189. private void CrossLink() {
  190. foreach (MessageDescriptor message in messageTypes) {
  191. message.CrossLink();
  192. }
  193. foreach (ServiceDescriptor service in services) {
  194. service.CrossLink();
  195. }
  196. foreach (FieldDescriptor extension in extensions) {
  197. extension.CrossLink();
  198. }
  199. foreach (MessageDescriptor message in messageTypes) {
  200. message.CheckRequiredFields();
  201. }
  202. }
  203. /// <summary>
  204. /// This method is to be called by generated code only. It is equivalent
  205. /// to BuilderFrom except that the FileDescriptorProto is encoded in
  206. /// protocol buffer wire format.
  207. /// </summary>
  208. public static FileDescriptor InternalBuildGeneratedFileFrom(byte[] descriptorData,
  209. FileDescriptor[] dependencies) {
  210. FileDescriptorProto proto = FileDescriptorProto.ParseFrom(descriptorData);
  211. return BuildFrom(proto, dependencies);
  212. }
  213. }
  214. }