build.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2019 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package filedesc provides functionality for constructing descriptors.
  5. //
  6. // The types in this package implement interfaces in the protoreflect package
  7. // related to protobuf descripriptors.
  8. package filedesc
  9. import (
  10. "google.golang.org/protobuf/encoding/protowire"
  11. "google.golang.org/protobuf/internal/genid"
  12. "google.golang.org/protobuf/reflect/protoreflect"
  13. "google.golang.org/protobuf/reflect/protoregistry"
  14. )
  15. // Builder construct a protoreflect.FileDescriptor from the raw descriptor.
  16. type Builder struct {
  17. // GoPackagePath is the Go package path that is invoking this builder.
  18. GoPackagePath string
  19. // RawDescriptor is the wire-encoded bytes of FileDescriptorProto
  20. // and must be populated.
  21. RawDescriptor []byte
  22. // NumEnums is the total number of enums declared in the file.
  23. NumEnums int32
  24. // NumMessages is the total number of messages declared in the file.
  25. // It includes the implicit message declarations for map entries.
  26. NumMessages int32
  27. // NumExtensions is the total number of extensions declared in the file.
  28. NumExtensions int32
  29. // NumServices is the total number of services declared in the file.
  30. NumServices int32
  31. // TypeResolver resolves extension field types for descriptor options.
  32. // If nil, it uses protoregistry.GlobalTypes.
  33. TypeResolver interface {
  34. protoregistry.ExtensionTypeResolver
  35. }
  36. // FileRegistry is use to lookup file, enum, and message dependencies.
  37. // Once constructed, the file descriptor is registered here.
  38. // If nil, it uses protoregistry.GlobalFiles.
  39. FileRegistry interface {
  40. FindFileByPath(string) (protoreflect.FileDescriptor, error)
  41. FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
  42. RegisterFile(protoreflect.FileDescriptor) error
  43. }
  44. }
  45. // resolverByIndex is an interface Builder.FileRegistry may implement.
  46. // If so, it permits looking up an enum or message dependency based on the
  47. // sub-list and element index into filetype.Builder.DependencyIndexes.
  48. type resolverByIndex interface {
  49. FindEnumByIndex(int32, int32, []Enum, []Message) protoreflect.EnumDescriptor
  50. FindMessageByIndex(int32, int32, []Enum, []Message) protoreflect.MessageDescriptor
  51. }
  52. // Indexes of each sub-list in filetype.Builder.DependencyIndexes.
  53. const (
  54. listFieldDeps int32 = iota
  55. listExtTargets
  56. listExtDeps
  57. listMethInDeps
  58. listMethOutDeps
  59. )
  60. // Out is the output of the Builder.
  61. type Out struct {
  62. File protoreflect.FileDescriptor
  63. // Enums is all enum descriptors in "flattened ordering".
  64. Enums []Enum
  65. // Messages is all message descriptors in "flattened ordering".
  66. // It includes the implicit message declarations for map entries.
  67. Messages []Message
  68. // Extensions is all extension descriptors in "flattened ordering".
  69. Extensions []Extension
  70. // Service is all service descriptors in "flattened ordering".
  71. Services []Service
  72. }
  73. // Build constructs a FileDescriptor given the parameters set in Builder.
  74. // It assumes that the inputs are well-formed and panics if any inconsistencies
  75. // are encountered.
  76. //
  77. // If NumEnums+NumMessages+NumExtensions+NumServices is zero,
  78. // then Build automatically derives them from the raw descriptor.
  79. func (db Builder) Build() (out Out) {
  80. // Populate the counts if uninitialized.
  81. if db.NumEnums+db.NumMessages+db.NumExtensions+db.NumServices == 0 {
  82. db.unmarshalCounts(db.RawDescriptor, true)
  83. }
  84. // Initialize resolvers and registries if unpopulated.
  85. if db.TypeResolver == nil {
  86. db.TypeResolver = protoregistry.GlobalTypes
  87. }
  88. if db.FileRegistry == nil {
  89. db.FileRegistry = protoregistry.GlobalFiles
  90. }
  91. fd := newRawFile(db)
  92. out.File = fd
  93. out.Enums = fd.allEnums
  94. out.Messages = fd.allMessages
  95. out.Extensions = fd.allExtensions
  96. out.Services = fd.allServices
  97. if err := db.FileRegistry.RegisterFile(fd); err != nil {
  98. panic(err)
  99. }
  100. return out
  101. }
  102. // unmarshalCounts counts the number of enum, message, extension, and service
  103. // declarations in the raw message, which is either a FileDescriptorProto
  104. // or a MessageDescriptorProto depending on whether isFile is set.
  105. func (db *Builder) unmarshalCounts(b []byte, isFile bool) {
  106. for len(b) > 0 {
  107. num, typ, n := protowire.ConsumeTag(b)
  108. b = b[n:]
  109. switch typ {
  110. case protowire.BytesType:
  111. v, m := protowire.ConsumeBytes(b)
  112. b = b[m:]
  113. if isFile {
  114. switch num {
  115. case genid.FileDescriptorProto_EnumType_field_number:
  116. db.NumEnums++
  117. case genid.FileDescriptorProto_MessageType_field_number:
  118. db.unmarshalCounts(v, false)
  119. db.NumMessages++
  120. case genid.FileDescriptorProto_Extension_field_number:
  121. db.NumExtensions++
  122. case genid.FileDescriptorProto_Service_field_number:
  123. db.NumServices++
  124. }
  125. } else {
  126. switch num {
  127. case genid.DescriptorProto_EnumType_field_number:
  128. db.NumEnums++
  129. case genid.DescriptorProto_NestedType_field_number:
  130. db.unmarshalCounts(v, false)
  131. db.NumMessages++
  132. case genid.DescriptorProto_Extension_field_number:
  133. db.NumExtensions++
  134. }
  135. }
  136. default:
  137. m := protowire.ConsumeFieldValue(num, typ, b)
  138. b = b[m:]
  139. }
  140. }
  141. }