blob: d7c99235ecfe71f8dbc58a4deb1f0dc997bc1fed [file] [log] [blame]
kesavand2cde6582020-06-22 04:56:23 -04001// 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
5package proto
6
7import (
8 "google.golang.org/protobuf/internal/errors"
9 "google.golang.org/protobuf/reflect/protoreflect"
10 "google.golang.org/protobuf/runtime/protoiface"
11)
12
13// CheckInitialized returns an error if any required fields in m are not set.
14func CheckInitialized(m Message) error {
15 return checkInitialized(m.ProtoReflect())
16}
17
18// CheckInitialized returns an error if any required fields in m are not set.
19func checkInitialized(m protoreflect.Message) error {
20 if methods := protoMethods(m); methods != nil && methods.CheckInitialized != nil {
21 _, err := methods.CheckInitialized(protoiface.CheckInitializedInput{
22 Message: m,
23 })
24 return err
25 }
26 return checkInitializedSlow(m)
27}
28
29func checkInitializedSlow(m protoreflect.Message) error {
30 md := m.Descriptor()
31 fds := md.Fields()
32 for i, nums := 0, md.RequiredNumbers(); i < nums.Len(); i++ {
33 fd := fds.ByNumber(nums.Get(i))
34 if !m.Has(fd) {
35 return errors.RequiredNotSet(string(fd.FullName()))
36 }
37 }
38 var err error
39 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
40 switch {
41 case fd.IsList():
42 if fd.Message() == nil {
43 return true
44 }
45 for i, list := 0, v.List(); i < list.Len() && err == nil; i++ {
46 err = checkInitialized(list.Get(i).Message())
47 }
48 case fd.IsMap():
49 if fd.MapValue().Message() == nil {
50 return true
51 }
52 v.Map().Range(func(key protoreflect.MapKey, v protoreflect.Value) bool {
53 err = checkInitialized(v.Message())
54 return err == nil
55 })
56 default:
57 if fd.Message() == nil {
58 return true
59 }
60 err = checkInitialized(v.Message())
61 }
62 return err == nil
63 })
64 return err
65}