blob: 343cf872197f76f7c1a40c4eff2b2f14c93792d3 [file] [log] [blame]
David K. Bainbridgee05cf0c2021-08-19 03:16:50 +00001// Copyright 2018 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
5package impl
6
7import (
8 "fmt"
9 "math"
10 "reflect"
11 "sync"
12
13 "google.golang.org/protobuf/internal/flags"
14 pref "google.golang.org/protobuf/reflect/protoreflect"
15 preg "google.golang.org/protobuf/reflect/protoregistry"
16)
17
18type fieldInfo struct {
19 fieldDesc pref.FieldDescriptor
20
21 // These fields are used for protobuf reflection support.
22 has func(pointer) bool
23 clear func(pointer)
24 get func(pointer) pref.Value
25 set func(pointer, pref.Value)
26 mutable func(pointer) pref.Value
27 newMessage func() pref.Message
28 newField func() pref.Value
29}
30
31func fieldInfoForMissing(fd pref.FieldDescriptor) fieldInfo {
32 // This never occurs for generated message types.
33 // It implies that a hand-crafted type has missing Go fields
34 // for specific protobuf message fields.
35 return fieldInfo{
36 fieldDesc: fd,
37 has: func(p pointer) bool {
38 return false
39 },
40 clear: func(p pointer) {
41 panic("missing Go struct field for " + string(fd.FullName()))
42 },
43 get: func(p pointer) pref.Value {
44 return fd.Default()
45 },
46 set: func(p pointer, v pref.Value) {
47 panic("missing Go struct field for " + string(fd.FullName()))
48 },
49 mutable: func(p pointer) pref.Value {
50 panic("missing Go struct field for " + string(fd.FullName()))
51 },
52 newMessage: func() pref.Message {
53 panic("missing Go struct field for " + string(fd.FullName()))
54 },
55 newField: func() pref.Value {
56 if v := fd.Default(); v.IsValid() {
57 return v
58 }
59 panic("missing Go struct field for " + string(fd.FullName()))
60 },
61 }
62}
63
64func fieldInfoForOneof(fd pref.FieldDescriptor, fs reflect.StructField, x exporter, ot reflect.Type) fieldInfo {
65 ft := fs.Type
66 if ft.Kind() != reflect.Interface {
67 panic(fmt.Sprintf("field %v has invalid type: got %v, want interface kind", fd.FullName(), ft))
68 }
69 if ot.Kind() != reflect.Struct {
70 panic(fmt.Sprintf("field %v has invalid type: got %v, want struct kind", fd.FullName(), ot))
71 }
72 if !reflect.PtrTo(ot).Implements(ft) {
73 panic(fmt.Sprintf("field %v has invalid type: %v does not implement %v", fd.FullName(), ot, ft))
74 }
75 conv := NewConverter(ot.Field(0).Type, fd)
76 isMessage := fd.Message() != nil
77
78 // TODO: Implement unsafe fast path?
79 fieldOffset := offsetOf(fs, x)
80 return fieldInfo{
81 // NOTE: The logic below intentionally assumes that oneof fields are
82 // well-formatted. That is, the oneof interface never contains a
83 // typed nil pointer to one of the wrapper structs.
84
85 fieldDesc: fd,
86 has: func(p pointer) bool {
87 if p.IsNil() {
88 return false
89 }
90 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
91 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
92 return false
93 }
94 return true
95 },
96 clear: func(p pointer) {
97 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
98 if rv.IsNil() || rv.Elem().Type().Elem() != ot {
99 // NOTE: We intentionally don't check for rv.Elem().IsNil()
100 // so that (*OneofWrapperType)(nil) gets cleared to nil.
101 return
102 }
103 rv.Set(reflect.Zero(rv.Type()))
104 },
105 get: func(p pointer) pref.Value {
106 if p.IsNil() {
107 return conv.Zero()
108 }
109 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
110 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
111 return conv.Zero()
112 }
113 rv = rv.Elem().Elem().Field(0)
114 return conv.PBValueOf(rv)
115 },
116 set: func(p pointer, v pref.Value) {
117 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
118 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
119 rv.Set(reflect.New(ot))
120 }
121 rv = rv.Elem().Elem().Field(0)
122 rv.Set(conv.GoValueOf(v))
123 },
124 mutable: func(p pointer) pref.Value {
125 if !isMessage {
126 panic(fmt.Sprintf("field %v with invalid Mutable call on field with non-composite type", fd.FullName()))
127 }
128 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
129 if rv.IsNil() || rv.Elem().Type().Elem() != ot || rv.Elem().IsNil() {
130 rv.Set(reflect.New(ot))
131 }
132 rv = rv.Elem().Elem().Field(0)
133 if rv.Kind() == reflect.Ptr && rv.IsNil() {
134 rv.Set(conv.GoValueOf(pref.ValueOfMessage(conv.New().Message())))
135 }
136 return conv.PBValueOf(rv)
137 },
138 newMessage: func() pref.Message {
139 return conv.New().Message()
140 },
141 newField: func() pref.Value {
142 return conv.New()
143 },
144 }
145}
146
147func fieldInfoForMap(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
148 ft := fs.Type
149 if ft.Kind() != reflect.Map {
150 panic(fmt.Sprintf("field %v has invalid type: got %v, want map kind", fd.FullName(), ft))
151 }
152 conv := NewConverter(ft, fd)
153
154 // TODO: Implement unsafe fast path?
155 fieldOffset := offsetOf(fs, x)
156 return fieldInfo{
157 fieldDesc: fd,
158 has: func(p pointer) bool {
159 if p.IsNil() {
160 return false
161 }
162 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
163 return rv.Len() > 0
164 },
165 clear: func(p pointer) {
166 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
167 rv.Set(reflect.Zero(rv.Type()))
168 },
169 get: func(p pointer) pref.Value {
170 if p.IsNil() {
171 return conv.Zero()
172 }
173 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
174 if rv.Len() == 0 {
175 return conv.Zero()
176 }
177 return conv.PBValueOf(rv)
178 },
179 set: func(p pointer, v pref.Value) {
180 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
181 pv := conv.GoValueOf(v)
182 if pv.IsNil() {
183 panic(fmt.Sprintf("map field %v cannot be set with read-only value", fd.FullName()))
184 }
185 rv.Set(pv)
186 },
187 mutable: func(p pointer) pref.Value {
188 v := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
189 if v.IsNil() {
190 v.Set(reflect.MakeMap(fs.Type))
191 }
192 return conv.PBValueOf(v)
193 },
194 newField: func() pref.Value {
195 return conv.New()
196 },
197 }
198}
199
200func fieldInfoForList(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
201 ft := fs.Type
202 if ft.Kind() != reflect.Slice {
203 panic(fmt.Sprintf("field %v has invalid type: got %v, want slice kind", fd.FullName(), ft))
204 }
205 conv := NewConverter(reflect.PtrTo(ft), fd)
206
207 // TODO: Implement unsafe fast path?
208 fieldOffset := offsetOf(fs, x)
209 return fieldInfo{
210 fieldDesc: fd,
211 has: func(p pointer) bool {
212 if p.IsNil() {
213 return false
214 }
215 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
216 return rv.Len() > 0
217 },
218 clear: func(p pointer) {
219 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
220 rv.Set(reflect.Zero(rv.Type()))
221 },
222 get: func(p pointer) pref.Value {
223 if p.IsNil() {
224 return conv.Zero()
225 }
226 rv := p.Apply(fieldOffset).AsValueOf(fs.Type)
227 if rv.Elem().Len() == 0 {
228 return conv.Zero()
229 }
230 return conv.PBValueOf(rv)
231 },
232 set: func(p pointer, v pref.Value) {
233 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
234 pv := conv.GoValueOf(v)
235 if pv.IsNil() {
236 panic(fmt.Sprintf("list field %v cannot be set with read-only value", fd.FullName()))
237 }
238 rv.Set(pv.Elem())
239 },
240 mutable: func(p pointer) pref.Value {
241 v := p.Apply(fieldOffset).AsValueOf(fs.Type)
242 return conv.PBValueOf(v)
243 },
244 newField: func() pref.Value {
245 return conv.New()
246 },
247 }
248}
249
250var (
251 nilBytes = reflect.ValueOf([]byte(nil))
252 emptyBytes = reflect.ValueOf([]byte{})
253)
254
255func fieldInfoForScalar(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
256 ft := fs.Type
257 nullable := fd.HasPresence()
258 isBytes := ft.Kind() == reflect.Slice && ft.Elem().Kind() == reflect.Uint8
259 if nullable {
260 if ft.Kind() != reflect.Ptr && ft.Kind() != reflect.Slice {
261 // This never occurs for generated message types.
262 // Despite the protobuf type system specifying presence,
263 // the Go field type cannot represent it.
264 nullable = false
265 }
266 if ft.Kind() == reflect.Ptr {
267 ft = ft.Elem()
268 }
269 }
270 conv := NewConverter(ft, fd)
271
272 // TODO: Implement unsafe fast path?
273 fieldOffset := offsetOf(fs, x)
274 return fieldInfo{
275 fieldDesc: fd,
276 has: func(p pointer) bool {
277 if p.IsNil() {
278 return false
279 }
280 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
281 if nullable {
282 return !rv.IsNil()
283 }
284 switch rv.Kind() {
285 case reflect.Bool:
286 return rv.Bool()
287 case reflect.Int32, reflect.Int64:
288 return rv.Int() != 0
289 case reflect.Uint32, reflect.Uint64:
290 return rv.Uint() != 0
291 case reflect.Float32, reflect.Float64:
292 return rv.Float() != 0 || math.Signbit(rv.Float())
293 case reflect.String, reflect.Slice:
294 return rv.Len() > 0
295 default:
296 panic(fmt.Sprintf("field %v has invalid type: %v", fd.FullName(), rv.Type())) // should never happen
297 }
298 },
299 clear: func(p pointer) {
300 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
301 rv.Set(reflect.Zero(rv.Type()))
302 },
303 get: func(p pointer) pref.Value {
304 if p.IsNil() {
305 return conv.Zero()
306 }
307 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
308 if nullable {
309 if rv.IsNil() {
310 return conv.Zero()
311 }
312 if rv.Kind() == reflect.Ptr {
313 rv = rv.Elem()
314 }
315 }
316 return conv.PBValueOf(rv)
317 },
318 set: func(p pointer, v pref.Value) {
319 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
320 if nullable && rv.Kind() == reflect.Ptr {
321 if rv.IsNil() {
322 rv.Set(reflect.New(ft))
323 }
324 rv = rv.Elem()
325 }
326 rv.Set(conv.GoValueOf(v))
327 if isBytes && rv.Len() == 0 {
328 if nullable {
329 rv.Set(emptyBytes) // preserve presence
330 } else {
331 rv.Set(nilBytes) // do not preserve presence
332 }
333 }
334 },
335 newField: func() pref.Value {
336 return conv.New()
337 },
338 }
339}
340
341func fieldInfoForWeakMessage(fd pref.FieldDescriptor, weakOffset offset) fieldInfo {
342 if !flags.ProtoLegacy {
343 panic("no support for proto1 weak fields")
344 }
345
346 var once sync.Once
347 var messageType pref.MessageType
348 lazyInit := func() {
349 once.Do(func() {
350 messageName := fd.Message().FullName()
351 messageType, _ = preg.GlobalTypes.FindMessageByName(messageName)
352 if messageType == nil {
353 panic(fmt.Sprintf("weak message %v for field %v is not linked in", messageName, fd.FullName()))
354 }
355 })
356 }
357
358 num := fd.Number()
359 return fieldInfo{
360 fieldDesc: fd,
361 has: func(p pointer) bool {
362 if p.IsNil() {
363 return false
364 }
365 _, ok := p.Apply(weakOffset).WeakFields().get(num)
366 return ok
367 },
368 clear: func(p pointer) {
369 p.Apply(weakOffset).WeakFields().clear(num)
370 },
371 get: func(p pointer) pref.Value {
372 lazyInit()
373 if p.IsNil() {
374 return pref.ValueOfMessage(messageType.Zero())
375 }
376 m, ok := p.Apply(weakOffset).WeakFields().get(num)
377 if !ok {
378 return pref.ValueOfMessage(messageType.Zero())
379 }
380 return pref.ValueOfMessage(m.ProtoReflect())
381 },
382 set: func(p pointer, v pref.Value) {
383 lazyInit()
384 m := v.Message()
385 if m.Descriptor() != messageType.Descriptor() {
386 if got, want := m.Descriptor().FullName(), messageType.Descriptor().FullName(); got != want {
387 panic(fmt.Sprintf("field %v has mismatching message descriptor: got %v, want %v", fd.FullName(), got, want))
388 }
389 panic(fmt.Sprintf("field %v has mismatching message descriptor: %v", fd.FullName(), m.Descriptor().FullName()))
390 }
391 p.Apply(weakOffset).WeakFields().set(num, m.Interface())
392 },
393 mutable: func(p pointer) pref.Value {
394 lazyInit()
395 fs := p.Apply(weakOffset).WeakFields()
396 m, ok := fs.get(num)
397 if !ok {
398 m = messageType.New().Interface()
399 fs.set(num, m)
400 }
401 return pref.ValueOfMessage(m.ProtoReflect())
402 },
403 newMessage: func() pref.Message {
404 lazyInit()
405 return messageType.New()
406 },
407 newField: func() pref.Value {
408 lazyInit()
409 return pref.ValueOfMessage(messageType.New())
410 },
411 }
412}
413
414func fieldInfoForMessage(fd pref.FieldDescriptor, fs reflect.StructField, x exporter) fieldInfo {
415 ft := fs.Type
416 conv := NewConverter(ft, fd)
417
418 // TODO: Implement unsafe fast path?
419 fieldOffset := offsetOf(fs, x)
420 return fieldInfo{
421 fieldDesc: fd,
422 has: func(p pointer) bool {
423 if p.IsNil() {
424 return false
425 }
426 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
427 if fs.Type.Kind() != reflect.Ptr {
428 return !isZero(rv)
429 }
430 return !rv.IsNil()
431 },
432 clear: func(p pointer) {
433 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
434 rv.Set(reflect.Zero(rv.Type()))
435 },
436 get: func(p pointer) pref.Value {
437 if p.IsNil() {
438 return conv.Zero()
439 }
440 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
441 return conv.PBValueOf(rv)
442 },
443 set: func(p pointer, v pref.Value) {
444 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
445 rv.Set(conv.GoValueOf(v))
446 if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
447 panic(fmt.Sprintf("field %v has invalid nil pointer", fd.FullName()))
448 }
449 },
450 mutable: func(p pointer) pref.Value {
451 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
452 if fs.Type.Kind() == reflect.Ptr && rv.IsNil() {
453 rv.Set(conv.GoValueOf(conv.New()))
454 }
455 return conv.PBValueOf(rv)
456 },
457 newMessage: func() pref.Message {
458 return conv.New().Message()
459 },
460 newField: func() pref.Value {
461 return conv.New()
462 },
463 }
464}
465
466type oneofInfo struct {
467 oneofDesc pref.OneofDescriptor
468 which func(pointer) pref.FieldNumber
469}
470
471func makeOneofInfo(od pref.OneofDescriptor, si structInfo, x exporter) *oneofInfo {
472 oi := &oneofInfo{oneofDesc: od}
473 if od.IsSynthetic() {
474 fs := si.fieldsByNumber[od.Fields().Get(0).Number()]
475 fieldOffset := offsetOf(fs, x)
476 oi.which = func(p pointer) pref.FieldNumber {
477 if p.IsNil() {
478 return 0
479 }
480 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
481 if rv.IsNil() { // valid on either *T or []byte
482 return 0
483 }
484 return od.Fields().Get(0).Number()
485 }
486 } else {
487 fs := si.oneofsByName[od.Name()]
488 fieldOffset := offsetOf(fs, x)
489 oi.which = func(p pointer) pref.FieldNumber {
490 if p.IsNil() {
491 return 0
492 }
493 rv := p.Apply(fieldOffset).AsValueOf(fs.Type).Elem()
494 if rv.IsNil() {
495 return 0
496 }
497 rv = rv.Elem()
498 if rv.IsNil() {
499 return 0
500 }
501 return si.oneofWrappersByType[rv.Type().Elem()]
502 }
503 }
504 return oi
505}
506
507// isZero is identical to reflect.Value.IsZero.
508// TODO: Remove this when Go1.13 is the minimally supported Go version.
509func isZero(v reflect.Value) bool {
510 switch v.Kind() {
511 case reflect.Bool:
512 return !v.Bool()
513 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
514 return v.Int() == 0
515 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
516 return v.Uint() == 0
517 case reflect.Float32, reflect.Float64:
518 return math.Float64bits(v.Float()) == 0
519 case reflect.Complex64, reflect.Complex128:
520 c := v.Complex()
521 return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
522 case reflect.Array:
523 for i := 0; i < v.Len(); i++ {
524 if !isZero(v.Index(i)) {
525 return false
526 }
527 }
528 return true
529 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
530 return v.IsNil()
531 case reflect.String:
532 return v.Len() == 0
533 case reflect.Struct:
534 for i := 0; i < v.NumField(); i++ {
535 if !isZero(v.Field(i)) {
536 return false
537 }
538 }
539 return true
540 default:
541 panic(&reflect.ValueError{"reflect.Value.IsZero", v.Kind()})
542 }
543}