| // 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 ( | |
| "google.golang.org/protobuf/internal/errors" | |
| "google.golang.org/protobuf/reflect/protoreflect" | |
| "google.golang.org/protobuf/runtime/protoiface" | |
| ) | |
| // CheckInitialized returns an error if any required fields in m are not set. | |
| func CheckInitialized(m Message) error { | |
| // Treat a nil message interface as an "untyped" empty message, | |
| // which we assume to have no required fields. | |
| if m == nil { | |
| return nil | |
| } | |
| return checkInitialized(m.ProtoReflect()) | |
| } | |
| // CheckInitialized returns an error if any required fields in m are not set. | |
| func checkInitialized(m protoreflect.Message) error { | |
| if methods := protoMethods(m); methods != nil && methods.CheckInitialized != nil { | |
| _, err := methods.CheckInitialized(protoiface.CheckInitializedInput{ | |
| Message: m, | |
| }) | |
| return err | |
| } | |
| return checkInitializedSlow(m) | |
| } | |
| func checkInitializedSlow(m protoreflect.Message) 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) { | |
| return errors.RequiredNotSet(string(fd.FullName())) | |
| } | |
| } | |
| var err error | |
| m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { | |
| switch { | |
| case fd.IsList(): | |
| if fd.Message() == nil { | |
| return true | |
| } | |
| for i, list := 0, v.List(); i < list.Len() && err == nil; i++ { | |
| err = checkInitialized(list.Get(i).Message()) | |
| } | |
| case fd.IsMap(): | |
| if fd.MapValue().Message() == nil { | |
| return true | |
| } | |
| v.Map().Range(func(key protoreflect.MapKey, v protoreflect.Value) bool { | |
| err = checkInitialized(v.Message()) | |
| return err == nil | |
| }) | |
| default: | |
| if fd.Message() == nil { | |
| return true | |
| } | |
| err = checkInitialized(v.Message()) | |
| } | |
| return err == nil | |
| }) | |
| return err | |
| } |