build.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  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 filetype provides functionality for wrapping descriptors
  5. // with Go type information.
  6. package filetype
  7. import (
  8. "reflect"
  9. "google.golang.org/protobuf/internal/descopts"
  10. fdesc "google.golang.org/protobuf/internal/filedesc"
  11. pimpl "google.golang.org/protobuf/internal/impl"
  12. pref "google.golang.org/protobuf/reflect/protoreflect"
  13. preg "google.golang.org/protobuf/reflect/protoregistry"
  14. ptype "google.golang.org/protobuf/reflect/prototype"
  15. piface "google.golang.org/protobuf/runtime/protoiface"
  16. )
  17. // TypeBuilder constructs type descriptors from a raw file descriptor
  18. // and associated Go types for each enum and message declaration.
  19. //
  20. //
  21. // Flattened Ordering
  22. //
  23. // The protobuf type system represents declarations as a tree. Certain nodes in
  24. // the tree require us to either associate it with a concrete Go type or to
  25. // resolve a dependency, which is information that must be provided separately
  26. // since it cannot be derived from the file descriptor alone.
  27. //
  28. // However, representing a tree as Go literals is difficult to simply do in a
  29. // space and time efficient way. Thus, we store them as a flattened list of
  30. // objects where the serialization order from the tree-based form is important.
  31. //
  32. // The "flattened ordering" is defined as a tree traversal of all enum, message,
  33. // extension, and service declarations using the following algorithm:
  34. //
  35. // def VisitFileDecls(fd):
  36. // for e in fd.Enums: yield e
  37. // for m in fd.Messages: yield m
  38. // for x in fd.Extensions: yield x
  39. // for s in fd.Services: yield s
  40. // for m in fd.Messages: yield from VisitMessageDecls(m)
  41. //
  42. // def VisitMessageDecls(md):
  43. // for e in md.Enums: yield e
  44. // for m in md.Messages: yield m
  45. // for x in md.Extensions: yield x
  46. // for m in md.Messages: yield from VisitMessageDecls(m)
  47. //
  48. // The traversal starts at the root file descriptor and yields each direct
  49. // declaration within each node before traversing into sub-declarations
  50. // that children themselves may have.
  51. type TypeBuilder struct {
  52. // File is the underlying file descriptor builder.
  53. File fdesc.DescBuilder
  54. // GoTypes is a unique set of the Go types for all declarations and
  55. // dependencies. Each type is represented as a zero value of the Go type.
  56. //
  57. // Declarations are Go types generated for enums and messages directly
  58. // declared (not publicly imported) in the proto source file.
  59. // Messages for map entries are accounted for, but represented by nil.
  60. // Enum declarations in "flattened ordering" come first, followed by
  61. // message declarations in "flattened ordering".
  62. //
  63. // Dependencies are Go types for enums or messages referenced by
  64. // message fields (excluding weak fields), for parent extended messages of
  65. // extension fields, for enums or messages referenced by extension fields,
  66. // and for input and output messages referenced by service methods.
  67. // Dependencies must come after declarations, but the ordering of
  68. // dependencies themselves is unspecified.
  69. GoTypes []interface{}
  70. // DependencyIndexes is an ordered list of indexes into GoTypes for the
  71. // dependencies of messages, extensions, or services.
  72. //
  73. // There are 5 sub-lists in "flattened ordering" concatenated back-to-back:
  74. // 0. Message field dependencies: list of the enum or message type
  75. // referred to by every message field.
  76. // 1. Extension field targets: list of the extended parent message of
  77. // every extension.
  78. // 2. Extension field dependencies: list of the enum or message type
  79. // referred to by every extension field.
  80. // 3. Service method inputs: list of the input message type
  81. // referred to by every service method.
  82. // 4. Service method outputs: list of the output message type
  83. // referred to by every service method.
  84. //
  85. // The offset into DependencyIndexes for the start of each sub-list
  86. // is appended to the end in reverse order.
  87. DependencyIndexes []int32
  88. // MessageInfos is a list of message infos in "flattened ordering".
  89. // If provided, the GoType and PBType for each element is populated.
  90. //
  91. // Requirement: len(MessageInfos) == len(Build.Messages)
  92. MessageInfos []pimpl.MessageInfo
  93. // LegacyExtensions is a list of legacy extensions in "flattened ordering".
  94. // If provided, the pointer to the v1 ExtensionDesc will be stored into the
  95. // associated v2 ExtensionType and accessible via a pseudo-internal API.
  96. // Also, the v2 ExtensionType will be stored into each v1 ExtensionDesc.
  97. //
  98. // Requirement: len(LegacyExtensions) == len(Build.Extensions)
  99. LegacyExtensions []piface.ExtensionDescV1
  100. // TypeRegistry is the registry to register each type descriptor.
  101. // If nil, it uses protoregistry.GlobalTypes.
  102. TypeRegistry interface {
  103. Register(...preg.Type) error
  104. }
  105. }
  106. func (tb TypeBuilder) Build() (out struct {
  107. File pref.FileDescriptor
  108. // Enums is all enum types in "flattened ordering".
  109. Enums []Enum
  110. // Messages is all message types in "flattened ordering".
  111. // It includes a stub message type for map entries.
  112. Messages []Message
  113. // Extensions is all extension types in "flattened ordering".
  114. Extensions []Extension
  115. }) {
  116. // Replace the resolver with one that resolves dependencies by index,
  117. // which is faster and more reliable than relying on the global registry.
  118. if tb.File.FileRegistry == nil {
  119. tb.File.FileRegistry = preg.GlobalFiles
  120. }
  121. tb.File.FileRegistry = &resolverByIndex{
  122. goTypes: tb.GoTypes,
  123. depIdxs: tb.DependencyIndexes,
  124. fileRegistry: tb.File.FileRegistry,
  125. }
  126. // Initialize registry if unpopulated.
  127. if tb.TypeRegistry == nil {
  128. tb.TypeRegistry = preg.GlobalTypes
  129. }
  130. fbOut := tb.File.Build()
  131. out.File = fbOut.File
  132. // Process enums.
  133. enumGoTypes := tb.GoTypes[:len(fbOut.Enums)]
  134. if len(fbOut.Enums) > 0 {
  135. out.Enums = make([]Enum, len(fbOut.Enums))
  136. for i := range fbOut.Enums {
  137. out.Enums[i] = Enum{
  138. EnumDescriptor: &fbOut.Enums[i],
  139. NewEnum: enumMaker(reflect.TypeOf(enumGoTypes[i])),
  140. }
  141. // Register enum types.
  142. if err := tb.TypeRegistry.Register(&out.Enums[i]); err != nil {
  143. panic(err)
  144. }
  145. }
  146. }
  147. // Process messages.
  148. messageGoTypes := tb.GoTypes[len(fbOut.Enums):][:len(fbOut.Messages)]
  149. if tb.MessageInfos != nil && len(tb.MessageInfos) != len(fbOut.Messages) {
  150. panic("mismatching message lengths")
  151. }
  152. if len(fbOut.Messages) > 0 {
  153. out.Messages = make([]Message, len(fbOut.Messages))
  154. for i := range fbOut.Messages {
  155. if messageGoTypes[i] == nil {
  156. continue // skip map entry
  157. }
  158. out.Messages[i] = Message{
  159. MessageDescriptor: &fbOut.Messages[i],
  160. NewMessage: messageMaker(reflect.TypeOf(messageGoTypes[i])),
  161. }
  162. if tb.MessageInfos != nil {
  163. tb.MessageInfos[i].GoType = reflect.TypeOf(messageGoTypes[i])
  164. tb.MessageInfos[i].PBType = &out.Messages[i]
  165. }
  166. // Register message types.
  167. if err := tb.TypeRegistry.Register(&out.Messages[i]); err != nil {
  168. panic(err)
  169. }
  170. }
  171. // As a special-case for descriptor.proto,
  172. // locally register concrete message type for the options.
  173. if out.File.Path() == "google/protobuf/descriptor.proto" && out.File.Package() == "google.protobuf" {
  174. for i := range fbOut.Messages {
  175. switch fbOut.Messages[i].Name() {
  176. case "FileOptions":
  177. descopts.File = messageGoTypes[i].(pref.ProtoMessage)
  178. case "EnumOptions":
  179. descopts.Enum = messageGoTypes[i].(pref.ProtoMessage)
  180. case "EnumValueOptions":
  181. descopts.EnumValue = messageGoTypes[i].(pref.ProtoMessage)
  182. case "MessageOptions":
  183. descopts.Message = messageGoTypes[i].(pref.ProtoMessage)
  184. case "FieldOptions":
  185. descopts.Field = messageGoTypes[i].(pref.ProtoMessage)
  186. case "OneofOptions":
  187. descopts.Oneof = messageGoTypes[i].(pref.ProtoMessage)
  188. case "ExtensionRangeOptions":
  189. descopts.ExtensionRange = messageGoTypes[i].(pref.ProtoMessage)
  190. case "ServiceOptions":
  191. descopts.Service = messageGoTypes[i].(pref.ProtoMessage)
  192. case "MethodOptions":
  193. descopts.Method = messageGoTypes[i].(pref.ProtoMessage)
  194. }
  195. }
  196. }
  197. }
  198. // Process extensions.
  199. if tb.LegacyExtensions != nil && len(tb.LegacyExtensions) != len(fbOut.Extensions) {
  200. panic("mismatching extension lengths")
  201. }
  202. if len(fbOut.Extensions) > 0 {
  203. var depIdx int32
  204. out.Extensions = make([]Extension, len(fbOut.Extensions))
  205. for i := range fbOut.Extensions {
  206. out.Extensions[i] = Extension{Extension: ptype.Extension{
  207. ExtensionDescriptor: &fbOut.Extensions[i],
  208. }}
  209. // For enum and message kinds, determine the referent Go type so
  210. // that we can construct their constructors.
  211. const listExtDeps = 2
  212. switch fbOut.Extensions[i].L1.Kind {
  213. case pref.EnumKind:
  214. j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
  215. goType := reflect.TypeOf(tb.GoTypes[j])
  216. out.Extensions[i].NewEnum = enumMaker(goType)
  217. depIdx++
  218. case pref.MessageKind, pref.GroupKind:
  219. j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
  220. goType := reflect.TypeOf(tb.GoTypes[j])
  221. out.Extensions[i].NewMessage = messageMaker(goType)
  222. depIdx++
  223. }
  224. // Keep v1 and v2 extensions in sync.
  225. if tb.LegacyExtensions != nil {
  226. out.Extensions[i].legacyDesc = &tb.LegacyExtensions[i]
  227. tb.LegacyExtensions[i].Type = &out.Extensions[i]
  228. }
  229. // Register extension types.
  230. if err := tb.TypeRegistry.Register(&out.Extensions[i]); err != nil {
  231. panic(err)
  232. }
  233. }
  234. }
  235. return out
  236. }
  237. type depIdxs []int32
  238. // Get retrieves the jth element of the ith sub-list.
  239. func (x depIdxs) Get(i, j int32) int32 {
  240. return x[x[int32(len(x))-i-1]+j]
  241. }
  242. type (
  243. resolverByIndex struct {
  244. goTypes []interface{}
  245. depIdxs depIdxs
  246. fileRegistry
  247. }
  248. fileRegistry interface {
  249. FindFileByPath(string) (pref.FileDescriptor, error)
  250. FindDescriptorByName(pref.FullName) (pref.Descriptor, error)
  251. Register(...pref.FileDescriptor) error
  252. }
  253. )
  254. func (r *resolverByIndex) FindEnumByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.EnumDescriptor {
  255. if depIdx := int(r.depIdxs.Get(i, j)); int(depIdx) < len(es)+len(ms) {
  256. return &es[depIdx]
  257. } else {
  258. return pimpl.Export{}.EnumDescriptorOf(r.goTypes[depIdx])
  259. }
  260. }
  261. func (r *resolverByIndex) FindMessageByIndex(i, j int32, es []fdesc.Enum, ms []fdesc.Message) pref.MessageDescriptor {
  262. if depIdx := int(r.depIdxs.Get(i, j)); depIdx < len(es)+len(ms) {
  263. return &ms[depIdx-len(es)]
  264. } else {
  265. return pimpl.Export{}.MessageDescriptorOf(r.goTypes[depIdx])
  266. }
  267. }
  268. func enumMaker(t reflect.Type) func(pref.EnumNumber) pref.Enum {
  269. return func(n pref.EnumNumber) pref.Enum {
  270. v := reflect.New(t).Elem()
  271. v.SetInt(int64(n))
  272. return v.Interface().(pref.Enum)
  273. }
  274. }
  275. func messageMaker(t reflect.Type) func() pref.Message {
  276. return func() pref.Message {
  277. return reflect.New(t.Elem()).Interface().(pref.ProtoMessage).ProtoReflect()
  278. }
  279. }
  280. type (
  281. Enum = ptype.Enum
  282. Message = ptype.Message
  283. Extension struct {
  284. ptype.Extension
  285. legacyDesc *piface.ExtensionDescV1
  286. }
  287. )
  288. // ProtoLegacyExtensionDesc is a pseudo-internal API for allowing the v1 code
  289. // to be able to retrieve a v1 ExtensionDesc.
  290. //
  291. // WARNING: This method is exempt from the compatibility promise and may be
  292. // removed in the future without warning.
  293. func (x *Extension) ProtoLegacyExtensionDesc() *piface.ExtensionDescV1 {
  294. return x.legacyDesc
  295. }