FileDescriptor.cs 7.9 KB

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