build.go 4.8 KB

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