| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- // Copyright 2019 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style.
- // license that can be found in the LICENSE file.
- package proto
- import (
- "bytes"
- "fmt"
- "google.golang.org/protobuf/internal/errors"
- pref "google.golang.org/protobuf/reflect/protoreflect"
- )
- // IsInitialized returns an error if any required fields in m are not set.
- func IsInitialized(m Message) error {
- if methods := protoMethods(m); methods != nil && methods.IsInitialized != nil {
- if err := methods.IsInitialized(m); err == nil {
- return nil
- }
- // Fall through to the slow path, since the fast-path
- // implementation doesn't produce nice errors.
- //
- // TODO: Consider producing better errors from the fast path.
- }
- return isInitialized(m.ProtoReflect(), nil)
- }
- // IsInitialized returns an error if any required fields in m are not set.
- func isInitialized(m pref.Message, stack []interface{}) error {
- md := m.Descriptor()
- fds := md.Fields()
- for i, nums := 0, md.RequiredNumbers(); i < nums.Len(); i++ {
- fd := fds.ByNumber(nums.Get(i))
- if !m.Has(fd) {
- stack = append(stack, fd.Name())
- return newRequiredNotSetError(stack)
- }
- }
- var err error
- m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
- // Recurse into fields containing message values.
- stack := append(stack, fd.Name())
- switch {
- case fd.IsList():
- if fd.Message() == nil {
- return true
- }
- for i, list := 0, v.List(); i < list.Len() && err == nil; i++ {
- stack := append(stack, "[", i, "].")
- err = isInitialized(list.Get(i).Message(), stack)
- }
- case fd.IsMap():
- if fd.MapValue().Message() == nil {
- return true
- }
- v.Map().Range(func(key pref.MapKey, v pref.Value) bool {
- stack := append(stack, "[", key, "].")
- err = isInitialized(v.Message(), stack)
- return err == nil
- })
- default:
- if fd.Message() == nil {
- return true
- }
- stack := append(stack, ".")
- err = isInitialized(v.Message(), stack)
- }
- return err == nil
- })
- return err
- }
- func newRequiredNotSetError(stack []interface{}) error {
- var buf bytes.Buffer
- for _, s := range stack {
- fmt.Fprint(&buf, s)
- }
- return errors.RequiredNotSet(buf.String())
- }
|