message.go 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. // 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. package impl
  5. import (
  6. "reflect"
  7. "strconv"
  8. "strings"
  9. pref "github.com/golang/protobuf/v2/reflect/protoreflect"
  10. )
  11. type MessageInfo struct {
  12. // TODO: Split fields into dense and sparse maps similar to the current
  13. // table-driven implementation in v1?
  14. fields map[pref.FieldNumber]*fieldInfo
  15. }
  16. // generateFieldFuncs generates per-field functions for all common operations
  17. // to be performed on each field. It takes in a reflect.Type representing the
  18. // Go struct, and a protoreflect.MessageDescriptor to match with the fields
  19. // in the struct.
  20. //
  21. // This code assumes that the struct is well-formed and panics if there are
  22. // any discrepancies.
  23. func (mi *MessageInfo) generateFieldFuncs(t reflect.Type, md pref.MessageDescriptor) {
  24. // Generate a mapping of field numbers and names to Go struct field or type.
  25. fields := map[pref.FieldNumber]reflect.StructField{}
  26. oneofs := map[pref.Name]reflect.StructField{}
  27. oneofFields := map[pref.FieldNumber]reflect.Type{}
  28. special := map[string]reflect.StructField{}
  29. fieldLoop:
  30. for i := 0; i < t.NumField(); i++ {
  31. f := t.Field(i)
  32. for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
  33. if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
  34. n, _ := strconv.ParseUint(s, 10, 64)
  35. fields[pref.FieldNumber(n)] = f
  36. continue fieldLoop
  37. }
  38. }
  39. if s := f.Tag.Get("protobuf_oneof"); len(s) > 0 {
  40. oneofs[pref.Name(s)] = f
  41. continue fieldLoop
  42. }
  43. switch f.Name {
  44. case "XXX_weak", "XXX_unrecognized", "XXX_sizecache", "XXX_extensions", "XXX_InternalExtensions":
  45. special[f.Name] = f
  46. continue fieldLoop
  47. }
  48. }
  49. if fn, ok := t.MethodByName("XXX_OneofFuncs"); ok {
  50. vs := fn.Func.Call([]reflect.Value{reflect.New(fn.Type.In(0)).Elem()})[3]
  51. oneofLoop:
  52. for _, v := range vs.Interface().([]interface{}) {
  53. tf := reflect.TypeOf(v).Elem()
  54. f := tf.Field(0)
  55. for _, s := range strings.Split(f.Tag.Get("protobuf"), ",") {
  56. if len(s) > 0 && strings.Trim(s, "0123456789") == "" {
  57. n, _ := strconv.ParseUint(s, 10, 64)
  58. oneofFields[pref.FieldNumber(n)] = tf
  59. continue oneofLoop
  60. }
  61. }
  62. }
  63. }
  64. mi.fields = map[pref.FieldNumber]*fieldInfo{}
  65. for i := 0; i < md.Fields().Len(); i++ {
  66. fd := md.Fields().Get(i)
  67. fs := fields[fd.Number()]
  68. var fi fieldInfo
  69. switch {
  70. case fd.IsWeak():
  71. fi = fieldInfoForWeak(fd, special["XXX_weak"])
  72. case fd.OneofType() != nil:
  73. fi = fieldInfoForOneof(fd, oneofs[fd.OneofType().Name()], oneofFields[fd.Number()])
  74. case fd.IsMap():
  75. fi = fieldInfoForMap(fd, fs)
  76. case fd.Cardinality() == pref.Repeated:
  77. fi = fieldInfoForVector(fd, fs)
  78. case fd.Kind() != pref.MessageKind && fd.Kind() != pref.GroupKind:
  79. fi = fieldInfoForScalar(fd, fs)
  80. default:
  81. fi = fieldInfoForMessage(fd, fs)
  82. }
  83. mi.fields[fd.Number()] = &fi
  84. }
  85. }