Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

142 řádky
3.5 KiB

  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 impl
  5. import (
  6. "sync"
  7. "google.golang.org/protobuf/internal/errors"
  8. "google.golang.org/protobuf/reflect/protoreflect"
  9. "google.golang.org/protobuf/runtime/protoiface"
  10. )
  11. func (mi *MessageInfo) checkInitialized(in protoiface.CheckInitializedInput) (protoiface.CheckInitializedOutput, error) {
  12. var p pointer
  13. if ms, ok := in.Message.(*messageState); ok {
  14. p = ms.pointer()
  15. } else {
  16. p = in.Message.(*messageReflectWrapper).pointer()
  17. }
  18. return protoiface.CheckInitializedOutput{}, mi.checkInitializedPointer(p)
  19. }
  20. func (mi *MessageInfo) checkInitializedPointer(p pointer) error {
  21. mi.init()
  22. if !mi.needsInitCheck {
  23. return nil
  24. }
  25. if p.IsNil() {
  26. for _, f := range mi.orderedCoderFields {
  27. if f.isRequired {
  28. return errors.RequiredNotSet(string(mi.Desc.Fields().ByNumber(f.num).FullName()))
  29. }
  30. }
  31. return nil
  32. }
  33. if mi.extensionOffset.IsValid() {
  34. e := p.Apply(mi.extensionOffset).Extensions()
  35. if err := mi.isInitExtensions(e); err != nil {
  36. return err
  37. }
  38. }
  39. for _, f := range mi.orderedCoderFields {
  40. if !f.isRequired && f.funcs.isInit == nil {
  41. continue
  42. }
  43. fptr := p.Apply(f.offset)
  44. if f.isPointer && fptr.Elem().IsNil() {
  45. if f.isRequired {
  46. return errors.RequiredNotSet(string(mi.Desc.Fields().ByNumber(f.num).FullName()))
  47. }
  48. continue
  49. }
  50. if f.funcs.isInit == nil {
  51. continue
  52. }
  53. if err := f.funcs.isInit(fptr, f); err != nil {
  54. return err
  55. }
  56. }
  57. return nil
  58. }
  59. func (mi *MessageInfo) isInitExtensions(ext *map[int32]ExtensionField) error {
  60. if ext == nil {
  61. return nil
  62. }
  63. for _, x := range *ext {
  64. ei := getExtensionFieldInfo(x.Type())
  65. if ei.funcs.isInit == nil {
  66. continue
  67. }
  68. v := x.Value()
  69. if !v.IsValid() {
  70. continue
  71. }
  72. if err := ei.funcs.isInit(v); err != nil {
  73. return err
  74. }
  75. }
  76. return nil
  77. }
  78. var (
  79. needsInitCheckMu sync.Mutex
  80. needsInitCheckMap sync.Map
  81. )
  82. // needsInitCheck reports whether a message needs to be checked for partial initialization.
  83. //
  84. // It returns true if the message transitively includes any required or extension fields.
  85. func needsInitCheck(md protoreflect.MessageDescriptor) bool {
  86. if v, ok := needsInitCheckMap.Load(md); ok {
  87. if has, ok := v.(bool); ok {
  88. return has
  89. }
  90. }
  91. needsInitCheckMu.Lock()
  92. defer needsInitCheckMu.Unlock()
  93. return needsInitCheckLocked(md)
  94. }
  95. func needsInitCheckLocked(md protoreflect.MessageDescriptor) (has bool) {
  96. if v, ok := needsInitCheckMap.Load(md); ok {
  97. // If has is true, we've previously determined that this message
  98. // needs init checks.
  99. //
  100. // If has is false, we've previously determined that it can never
  101. // be uninitialized.
  102. //
  103. // If has is not a bool, we've just encountered a cycle in the
  104. // message graph. In this case, it is safe to return false: If
  105. // the message does have required fields, we'll detect them later
  106. // in the graph traversal.
  107. has, ok := v.(bool)
  108. return ok && has
  109. }
  110. needsInitCheckMap.Store(md, struct{}{}) // avoid cycles while descending into this message
  111. defer func() {
  112. needsInitCheckMap.Store(md, has)
  113. }()
  114. if md.RequiredNumbers().Len() > 0 {
  115. return true
  116. }
  117. if md.ExtensionRanges().Len() > 0 {
  118. return true
  119. }
  120. for i := 0; i < md.Fields().Len(); i++ {
  121. fd := md.Fields().Get(i)
  122. // Map keys are never messages, so just consider the map value.
  123. if fd.IsMap() {
  124. fd = fd.MapValue()
  125. }
  126. fmd := fd.Message()
  127. if fmd != nil && needsInitCheckLocked(fmd) {
  128. return true
  129. }
  130. }
  131. return false
  132. }