1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage proto 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "google.golang.org/protobuf/internal/errors" 9*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 10*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoiface" 11*1c12ee1eSDan Willemsen) 12*1c12ee1eSDan Willemsen 13*1c12ee1eSDan Willemsen// CheckInitialized returns an error if any required fields in m are not set. 14*1c12ee1eSDan Willemsenfunc CheckInitialized(m Message) error { 15*1c12ee1eSDan Willemsen // Treat a nil message interface as an "untyped" empty message, 16*1c12ee1eSDan Willemsen // which we assume to have no required fields. 17*1c12ee1eSDan Willemsen if m == nil { 18*1c12ee1eSDan Willemsen return nil 19*1c12ee1eSDan Willemsen } 20*1c12ee1eSDan Willemsen 21*1c12ee1eSDan Willemsen return checkInitialized(m.ProtoReflect()) 22*1c12ee1eSDan Willemsen} 23*1c12ee1eSDan Willemsen 24*1c12ee1eSDan Willemsen// CheckInitialized returns an error if any required fields in m are not set. 25*1c12ee1eSDan Willemsenfunc checkInitialized(m protoreflect.Message) error { 26*1c12ee1eSDan Willemsen if methods := protoMethods(m); methods != nil && methods.CheckInitialized != nil { 27*1c12ee1eSDan Willemsen _, err := methods.CheckInitialized(protoiface.CheckInitializedInput{ 28*1c12ee1eSDan Willemsen Message: m, 29*1c12ee1eSDan Willemsen }) 30*1c12ee1eSDan Willemsen return err 31*1c12ee1eSDan Willemsen } 32*1c12ee1eSDan Willemsen return checkInitializedSlow(m) 33*1c12ee1eSDan Willemsen} 34*1c12ee1eSDan Willemsen 35*1c12ee1eSDan Willemsenfunc checkInitializedSlow(m protoreflect.Message) error { 36*1c12ee1eSDan Willemsen md := m.Descriptor() 37*1c12ee1eSDan Willemsen fds := md.Fields() 38*1c12ee1eSDan Willemsen for i, nums := 0, md.RequiredNumbers(); i < nums.Len(); i++ { 39*1c12ee1eSDan Willemsen fd := fds.ByNumber(nums.Get(i)) 40*1c12ee1eSDan Willemsen if !m.Has(fd) { 41*1c12ee1eSDan Willemsen return errors.RequiredNotSet(string(fd.FullName())) 42*1c12ee1eSDan Willemsen } 43*1c12ee1eSDan Willemsen } 44*1c12ee1eSDan Willemsen var err error 45*1c12ee1eSDan Willemsen m.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { 46*1c12ee1eSDan Willemsen switch { 47*1c12ee1eSDan Willemsen case fd.IsList(): 48*1c12ee1eSDan Willemsen if fd.Message() == nil { 49*1c12ee1eSDan Willemsen return true 50*1c12ee1eSDan Willemsen } 51*1c12ee1eSDan Willemsen for i, list := 0, v.List(); i < list.Len() && err == nil; i++ { 52*1c12ee1eSDan Willemsen err = checkInitialized(list.Get(i).Message()) 53*1c12ee1eSDan Willemsen } 54*1c12ee1eSDan Willemsen case fd.IsMap(): 55*1c12ee1eSDan Willemsen if fd.MapValue().Message() == nil { 56*1c12ee1eSDan Willemsen return true 57*1c12ee1eSDan Willemsen } 58*1c12ee1eSDan Willemsen v.Map().Range(func(key protoreflect.MapKey, v protoreflect.Value) bool { 59*1c12ee1eSDan Willemsen err = checkInitialized(v.Message()) 60*1c12ee1eSDan Willemsen return err == nil 61*1c12ee1eSDan Willemsen }) 62*1c12ee1eSDan Willemsen default: 63*1c12ee1eSDan Willemsen if fd.Message() == nil { 64*1c12ee1eSDan Willemsen return true 65*1c12ee1eSDan Willemsen } 66*1c12ee1eSDan Willemsen err = checkInitialized(v.Message()) 67*1c12ee1eSDan Willemsen } 68*1c12ee1eSDan Willemsen return err == nil 69*1c12ee1eSDan Willemsen }) 70*1c12ee1eSDan Willemsen return err 71*1c12ee1eSDan Willemsen} 72