...
1
2
3
4
5
6
7 package filetype
8
9 import (
10 "reflect"
11
12 "google.golang.org/protobuf/internal/descopts"
13 "google.golang.org/protobuf/internal/filedesc"
14 pimpl "google.golang.org/protobuf/internal/impl"
15 "google.golang.org/protobuf/reflect/protoreflect"
16 "google.golang.org/protobuf/reflect/protoregistry"
17 )
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 type Builder struct {
53
54 File filedesc.Builder
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71 GoTypes []interface{}
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 DependencyIndexes []int32
91
92
93 EnumInfos []pimpl.EnumInfo
94
95
96
97
98
99 MessageInfos []pimpl.MessageInfo
100
101
102
103
104
105 ExtensionInfos []pimpl.ExtensionInfo
106
107
108
109 TypeRegistry interface {
110 RegisterMessage(protoreflect.MessageType) error
111 RegisterEnum(protoreflect.EnumType) error
112 RegisterExtension(protoreflect.ExtensionType) error
113 }
114 }
115
116
117 type Out struct {
118 File protoreflect.FileDescriptor
119 }
120
121 func (tb Builder) Build() (out Out) {
122
123
124 if tb.File.FileRegistry == nil {
125 tb.File.FileRegistry = protoregistry.GlobalFiles
126 }
127 tb.File.FileRegistry = &resolverByIndex{
128 goTypes: tb.GoTypes,
129 depIdxs: tb.DependencyIndexes,
130 fileRegistry: tb.File.FileRegistry,
131 }
132
133
134 if tb.TypeRegistry == nil {
135 tb.TypeRegistry = protoregistry.GlobalTypes
136 }
137
138 fbOut := tb.File.Build()
139 out.File = fbOut.File
140
141
142 enumGoTypes := tb.GoTypes[:len(fbOut.Enums)]
143 if len(tb.EnumInfos) != len(fbOut.Enums) {
144 panic("mismatching enum lengths")
145 }
146 if len(fbOut.Enums) > 0 {
147 for i := range fbOut.Enums {
148 tb.EnumInfos[i] = pimpl.EnumInfo{
149 GoReflectType: reflect.TypeOf(enumGoTypes[i]),
150 Desc: &fbOut.Enums[i],
151 }
152
153 if err := tb.TypeRegistry.RegisterEnum(&tb.EnumInfos[i]); err != nil {
154 panic(err)
155 }
156 }
157 }
158
159
160 messageGoTypes := tb.GoTypes[len(fbOut.Enums):][:len(fbOut.Messages)]
161 if len(tb.MessageInfos) != len(fbOut.Messages) {
162 panic("mismatching message lengths")
163 }
164 if len(fbOut.Messages) > 0 {
165 for i := range fbOut.Messages {
166 if messageGoTypes[i] == nil {
167 continue
168 }
169
170 tb.MessageInfos[i].GoReflectType = reflect.TypeOf(messageGoTypes[i])
171 tb.MessageInfos[i].Desc = &fbOut.Messages[i]
172
173
174 if err := tb.TypeRegistry.RegisterMessage(&tb.MessageInfos[i]); err != nil {
175 panic(err)
176 }
177 }
178
179
180
181 if out.File.Path() == "google/protobuf/descriptor.proto" && out.File.Package() == "google.protobuf" {
182 for i := range fbOut.Messages {
183 switch fbOut.Messages[i].Name() {
184 case "FileOptions":
185 descopts.File = messageGoTypes[i].(protoreflect.ProtoMessage)
186 case "EnumOptions":
187 descopts.Enum = messageGoTypes[i].(protoreflect.ProtoMessage)
188 case "EnumValueOptions":
189 descopts.EnumValue = messageGoTypes[i].(protoreflect.ProtoMessage)
190 case "MessageOptions":
191 descopts.Message = messageGoTypes[i].(protoreflect.ProtoMessage)
192 case "FieldOptions":
193 descopts.Field = messageGoTypes[i].(protoreflect.ProtoMessage)
194 case "OneofOptions":
195 descopts.Oneof = messageGoTypes[i].(protoreflect.ProtoMessage)
196 case "ExtensionRangeOptions":
197 descopts.ExtensionRange = messageGoTypes[i].(protoreflect.ProtoMessage)
198 case "ServiceOptions":
199 descopts.Service = messageGoTypes[i].(protoreflect.ProtoMessage)
200 case "MethodOptions":
201 descopts.Method = messageGoTypes[i].(protoreflect.ProtoMessage)
202 }
203 }
204 }
205 }
206
207
208 if len(tb.ExtensionInfos) != len(fbOut.Extensions) {
209 panic("mismatching extension lengths")
210 }
211 var depIdx int32
212 for i := range fbOut.Extensions {
213
214
215 const listExtDeps = 2
216 var goType reflect.Type
217 switch fbOut.Extensions[i].L1.Kind {
218 case protoreflect.EnumKind:
219 j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
220 goType = reflect.TypeOf(tb.GoTypes[j])
221 depIdx++
222 case protoreflect.MessageKind, protoreflect.GroupKind:
223 j := depIdxs.Get(tb.DependencyIndexes, listExtDeps, depIdx)
224 goType = reflect.TypeOf(tb.GoTypes[j])
225 depIdx++
226 default:
227 goType = goTypeForPBKind[fbOut.Extensions[i].L1.Kind]
228 }
229 if fbOut.Extensions[i].IsList() {
230 goType = reflect.SliceOf(goType)
231 }
232
233 pimpl.InitExtensionInfo(&tb.ExtensionInfos[i], &fbOut.Extensions[i], goType)
234
235
236 if err := tb.TypeRegistry.RegisterExtension(&tb.ExtensionInfos[i]); err != nil {
237 panic(err)
238 }
239 }
240
241 return out
242 }
243
244 var goTypeForPBKind = map[protoreflect.Kind]reflect.Type{
245 protoreflect.BoolKind: reflect.TypeOf(bool(false)),
246 protoreflect.Int32Kind: reflect.TypeOf(int32(0)),
247 protoreflect.Sint32Kind: reflect.TypeOf(int32(0)),
248 protoreflect.Sfixed32Kind: reflect.TypeOf(int32(0)),
249 protoreflect.Int64Kind: reflect.TypeOf(int64(0)),
250 protoreflect.Sint64Kind: reflect.TypeOf(int64(0)),
251 protoreflect.Sfixed64Kind: reflect.TypeOf(int64(0)),
252 protoreflect.Uint32Kind: reflect.TypeOf(uint32(0)),
253 protoreflect.Fixed32Kind: reflect.TypeOf(uint32(0)),
254 protoreflect.Uint64Kind: reflect.TypeOf(uint64(0)),
255 protoreflect.Fixed64Kind: reflect.TypeOf(uint64(0)),
256 protoreflect.FloatKind: reflect.TypeOf(float32(0)),
257 protoreflect.DoubleKind: reflect.TypeOf(float64(0)),
258 protoreflect.StringKind: reflect.TypeOf(string("")),
259 protoreflect.BytesKind: reflect.TypeOf([]byte(nil)),
260 }
261
262 type depIdxs []int32
263
264
265 func (x depIdxs) Get(i, j int32) int32 {
266 return x[x[int32(len(x))-i-1]+j]
267 }
268
269 type (
270 resolverByIndex struct {
271 goTypes []interface{}
272 depIdxs depIdxs
273 fileRegistry
274 }
275 fileRegistry interface {
276 FindFileByPath(string) (protoreflect.FileDescriptor, error)
277 FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
278 RegisterFile(protoreflect.FileDescriptor) error
279 }
280 )
281
282 func (r *resolverByIndex) FindEnumByIndex(i, j int32, es []filedesc.Enum, ms []filedesc.Message) protoreflect.EnumDescriptor {
283 if depIdx := int(r.depIdxs.Get(i, j)); int(depIdx) < len(es)+len(ms) {
284 return &es[depIdx]
285 } else {
286 return pimpl.Export{}.EnumDescriptorOf(r.goTypes[depIdx])
287 }
288 }
289
290 func (r *resolverByIndex) FindMessageByIndex(i, j int32, es []filedesc.Enum, ms []filedesc.Message) protoreflect.MessageDescriptor {
291 if depIdx := int(r.depIdxs.Get(i, j)); depIdx < len(es)+len(ms) {
292 return &ms[depIdx-len(es)]
293 } else {
294 return pimpl.Export{}.MessageDescriptorOf(r.goTypes[depIdx])
295 }
296 }
297
View as plain text