blob: 3e9a6a2f66c77cdcb18acb3bb56ffa36be9e5a18 [file] [log] [blame]
Damien Neil4686e232019-04-05 13:31:40 -07001// Copyright 2019 The Go Authors. All rights reserved.
Damien Neil0232edc2020-02-20 10:30:38 -08002// Use of this source code is governed by a BSD-style
Damien Neil4686e232019-04-05 13:31:40 -07003// 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"
Joe Tsai0f81b382019-07-10 23:14:31 -07009 "google.golang.org/protobuf/reflect/protoreflect"
Damien Neil466dd772020-02-14 14:49:35 -080010 "google.golang.org/protobuf/runtime/protoiface"
Damien Neil4686e232019-04-05 13:31:40 -070011)
12
Joe Tsaif26a9e72020-02-20 10:05:37 -080013// CheckInitialized returns an error if any required fields in m are not set.
14func CheckInitialized(m Message) error {
Joe Tsai8cfc14f2020-04-17 10:55:19 -070015 // Treat a nil message interface as an "untyped" empty message,
16 // which we assume to have no required fields.
17 if m == nil {
18 return nil
19 }
20
Joe Tsaif26a9e72020-02-20 10:05:37 -080021 return checkInitialized(m.ProtoReflect())
22}
23
24// CheckInitialized returns an error if any required fields in m are not set.
25func checkInitialized(m protoreflect.Message) error {
26 if methods := protoMethods(m); methods != nil && methods.CheckInitialized != nil {
27 _, err := methods.CheckInitialized(protoiface.CheckInitializedInput{
Damien Neil466dd772020-02-14 14:49:35 -080028 Message: m,
29 })
30 return err
Joe Tsai0f81b382019-07-10 23:14:31 -070031 }
Joe Tsaif26a9e72020-02-20 10:05:37 -080032 return checkInitializedSlow(m)
Joe Tsai0f81b382019-07-10 23:14:31 -070033}
34
Joe Tsaif26a9e72020-02-20 10:05:37 -080035func checkInitializedSlow(m protoreflect.Message) error {
Joe Tsai0fc49f82019-05-01 12:29:25 -070036 md := m.Descriptor()
Joe Tsai378c1322019-04-25 23:48:08 -070037 fds := md.Fields()
Damien Neil4686e232019-04-05 13:31:40 -070038 for i, nums := 0, md.RequiredNumbers(); i < nums.Len(); i++ {
Joe Tsai378c1322019-04-25 23:48:08 -070039 fd := fds.ByNumber(nums.Get(i))
40 if !m.Has(fd) {
Damien Neil3d0706a2019-07-09 11:40:49 -070041 return errors.RequiredNotSet(string(fd.FullName()))
Damien Neil4686e232019-04-05 13:31:40 -070042 }
43 }
44 var err error
Joe Tsai0f81b382019-07-10 23:14:31 -070045 m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
Joe Tsai378c1322019-04-25 23:48:08 -070046 switch {
47 case fd.IsList():
48 if fd.Message() == nil {
Damien Neil4686e232019-04-05 13:31:40 -070049 return true
50 }
Joe Tsai378c1322019-04-25 23:48:08 -070051 for i, list := 0, v.List(); i < list.Len() && err == nil; i++ {
Joe Tsaif26a9e72020-02-20 10:05:37 -080052 err = checkInitialized(list.Get(i).Message())
Damien Neil4686e232019-04-05 13:31:40 -070053 }
Joe Tsai378c1322019-04-25 23:48:08 -070054 case fd.IsMap():
55 if fd.MapValue().Message() == nil {
56 return true
57 }
Joe Tsai0f81b382019-07-10 23:14:31 -070058 v.Map().Range(func(key protoreflect.MapKey, v protoreflect.Value) bool {
Joe Tsaif26a9e72020-02-20 10:05:37 -080059 err = checkInitialized(v.Message())
Joe Tsaiac31a352019-05-13 14:32:56 -070060 return err == nil
61 })
Damien Neil4686e232019-04-05 13:31:40 -070062 default:
Joe Tsai378c1322019-04-25 23:48:08 -070063 if fd.Message() == nil {
64 return true
65 }
Joe Tsaif26a9e72020-02-20 10:05:37 -080066 err = checkInitialized(v.Message())
Damien Neil4686e232019-04-05 13:31:40 -070067 }
68 return err == nil
69 })
70 return err
71}