blob: e0fd947be10d268caa031aaebb7a59df9e79b91c [file] [log] [blame]
Damien Neil4686e232019-04-05 13:31:40 -07001// 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 (
Damien Neile89e6242019-05-13 23:55:40 -07008 "google.golang.org/protobuf/internal/errors"
9 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neil4686e232019-04-05 13:31:40 -070010)
11
12// IsInitialized returns an error if any required fields in m are not set.
13func IsInitialized(m Message) error {
14 if methods := protoMethods(m); methods != nil && methods.IsInitialized != nil {
Damien Neil3d0706a2019-07-09 11:40:49 -070015 return methods.IsInitialized(m)
Damien Neil4686e232019-04-05 13:31:40 -070016 }
Damien Neil3d0706a2019-07-09 11:40:49 -070017 return isInitialized(m.ProtoReflect())
Damien Neil4686e232019-04-05 13:31:40 -070018}
19
20// IsInitialized returns an error if any required fields in m are not set.
Damien Neil3d0706a2019-07-09 11:40:49 -070021func isInitialized(m pref.Message) error {
Joe Tsai0fc49f82019-05-01 12:29:25 -070022 md := m.Descriptor()
Joe Tsai378c1322019-04-25 23:48:08 -070023 fds := md.Fields()
Damien Neil4686e232019-04-05 13:31:40 -070024 for i, nums := 0, md.RequiredNumbers(); i < nums.Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070025 fd := fds.ByNumber(nums.Get(i))
26 if !m.Has(fd) {
Damien Neil3d0706a2019-07-09 11:40:49 -070027 return errors.RequiredNotSet(string(fd.FullName()))
Damien Neil4686e232019-04-05 13:31:40 -070028 }
29 }
30 var err error
Joe Tsai378c1322019-04-25 23:48:08 -070031 m.Range(func(fd pref.FieldDescriptor, v pref.Value) bool {
Joe Tsai378c1322019-04-25 23:48:08 -070032 switch {
33 case fd.IsList():
34 if fd.Message() == nil {
Damien Neil4686e232019-04-05 13:31:40 -070035 return true
36 }
Joe Tsai378c1322019-04-25 23:48:08 -070037 for i, list := 0, v.List(); i < list.Len() && err == nil; i++ {
Damien Neil3d0706a2019-07-09 11:40:49 -070038 err = IsInitialized(list.Get(i).Message().Interface())
Damien Neil4686e232019-04-05 13:31:40 -070039 }
Joe Tsai378c1322019-04-25 23:48:08 -070040 case fd.IsMap():
41 if fd.MapValue().Message() == nil {
42 return true
43 }
Joe Tsaiac31a352019-05-13 14:32:56 -070044 v.Map().Range(func(key pref.MapKey, v pref.Value) bool {
Damien Neil3d0706a2019-07-09 11:40:49 -070045 err = IsInitialized(v.Message().Interface())
Joe Tsaiac31a352019-05-13 14:32:56 -070046 return err == nil
47 })
Damien Neil4686e232019-04-05 13:31:40 -070048 default:
Joe Tsai378c1322019-04-25 23:48:08 -070049 if fd.Message() == nil {
50 return true
51 }
Damien Neil3d0706a2019-07-09 11:40:49 -070052 err = IsInitialized(v.Message().Interface())
Damien Neil4686e232019-04-05 13:31:40 -070053 }
54 return err == nil
55 })
56 return err
57}