package impl
import (
"sync"
"google.golang.org/protobuf/internal/errors"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/runtime/protoiface"
)
func (mi *MessageInfo ) checkInitialized (in protoiface .CheckInitializedInput ) (protoiface .CheckInitializedOutput , error ) {
var p pointer
if ms , ok := in .Message .(*messageState ); ok {
p = ms .pointer ()
} else {
p = in .Message .(*messageReflectWrapper ).pointer ()
}
return protoiface .CheckInitializedOutput {}, mi .checkInitializedPointer (p )
}
func (mi *MessageInfo ) checkInitializedPointer (p pointer ) error {
mi .init ()
if !mi .needsInitCheck {
return nil
}
if p .IsNil () {
for _ , f := range mi .orderedCoderFields {
if f .isRequired {
return errors .RequiredNotSet (string (mi .Desc .Fields ().ByNumber (f .num ).FullName ()))
}
}
return nil
}
var presence presence
if mi .presenceOffset .IsValid () {
presence = p .Apply (mi .presenceOffset ).PresenceInfo ()
}
if mi .extensionOffset .IsValid () {
e := p .Apply (mi .extensionOffset ).Extensions ()
if err := mi .isInitExtensions (e ); err != nil {
return err
}
}
for _ , f := range mi .orderedCoderFields {
if !f .isRequired && f .funcs .isInit == nil {
continue
}
if f .presenceIndex != noPresence {
if !presence .Present (f .presenceIndex ) {
if f .isRequired {
return errors .RequiredNotSet (string (mi .Desc .Fields ().ByNumber (f .num ).FullName ()))
}
continue
}
if f .funcs .isInit != nil {
f .mi .init ()
if f .mi .needsInitCheck {
if f .isLazy && p .Apply (f .offset ).AtomicGetPointer ().IsNil () {
lazy := *p .Apply (mi .lazyOffset ).LazyInfoPtr ()
if !lazy .AllowedPartial () {
continue
}
mi .lazyUnmarshal (p , f .num )
}
if err := f .funcs .isInit (p .Apply (f .offset ), f ); err != nil {
return err
}
}
}
continue
}
fptr := p .Apply (f .offset )
if f .isPointer && fptr .Elem ().IsNil () {
if f .isRequired {
return errors .RequiredNotSet (string (mi .Desc .Fields ().ByNumber (f .num ).FullName ()))
}
continue
}
if f .funcs .isInit == nil {
continue
}
if err := f .funcs .isInit (fptr , f ); err != nil {
return err
}
}
return nil
}
func (mi *MessageInfo ) isInitExtensions (ext *map [int32 ]ExtensionField ) error {
if ext == nil {
return nil
}
for _ , x := range *ext {
ei := getExtensionFieldInfo (x .Type ())
if ei .funcs .isInit == nil || x .isUnexpandedLazy () {
continue
}
v := x .Value ()
if !v .IsValid () {
continue
}
if err := ei .funcs .isInit (v ); err != nil {
return err
}
}
return nil
}
var (
needsInitCheckMu sync .Mutex
needsInitCheckMap sync .Map
)
func needsInitCheck(md protoreflect .MessageDescriptor ) bool {
if v , ok := needsInitCheckMap .Load (md ); ok {
if has , ok := v .(bool ); ok {
return has
}
}
needsInitCheckMu .Lock ()
defer needsInitCheckMu .Unlock ()
return needsInitCheckLocked (md )
}
func needsInitCheckLocked(md protoreflect .MessageDescriptor ) (has bool ) {
if v , ok := needsInitCheckMap .Load (md ); ok {
has , ok := v .(bool )
return ok && has
}
needsInitCheckMap .Store (md , struct {}{})
defer func () {
needsInitCheckMap .Store (md , has )
}()
if md .RequiredNumbers ().Len () > 0 {
return true
}
if md .ExtensionRanges ().Len () > 0 {
return true
}
for i := 0 ; i < md .Fields ().Len (); i ++ {
fd := md .Fields ().Get (i )
if fd .IsMap () {
fd = fd .MapValue ()
}
fmd := fd .Message ()
if fmd != nil && needsInitCheckLocked (fmd ) {
return true
}
}
return false
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .