|  | // 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 | 
|  | } |