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