@@ -604,7 +604,7 @@ func MergeStructInto(dst, src GoStruct, opts ...MergeOpt) error {
604604 return fmt .Errorf ("cannot merge structs that are not of matching types, %T != %T" , dst , src )
605605 }
606606
607- return copyStruct (reflect .ValueOf (dst ).Elem (), reflect .ValueOf (src ).Elem (), opts ... )
607+ return copyStruct (reflect .ValueOf (dst ).Elem (), reflect .ValueOf (src ).Elem (), "" , opts ... )
608608}
609609
610610// DeepCopy returns a deep copy of the supplied GoStruct. A new copy
@@ -626,7 +626,7 @@ func deepCopy(s GoStruct, keepEmptyMaps bool) (GoStruct, error) {
626626 if keepEmptyMaps {
627627 opts = append (opts , & MergeEmptyMaps {})
628628 }
629- if err := copyStruct (n .Elem (), reflect .ValueOf (s ).Elem (), opts ... ); err != nil {
629+ if err := copyStruct (n .Elem (), reflect .ValueOf (s ).Elem (), "" , opts ... ); err != nil {
630630 return nil , fmt .Errorf ("cannot DeepCopy struct: %v" , err )
631631 }
632632 return n .Interface ().(GoStruct ), nil
@@ -657,7 +657,13 @@ func mergeEmptyMapsEnabled(opts []MergeOpt) bool {
657657}
658658
659659// copyStruct copies the fields of srcVal into the dstVal struct in-place.
660- func copyStruct (dstVal , srcVal reflect.Value , opts ... MergeOpt ) error {
660+ //
661+ // - accessPath is the programmatic access path to the struct. It is used for
662+ // generating a more usable error message. (e.g. Field1.Map2["foo"].Field3)
663+ // When calling at the top level, "" should be used.
664+ //
665+ // It fails-slow: accumulates errors prior to return.
666+ func copyStruct (dstVal , srcVal reflect.Value , accessPath string , opts ... MergeOpt ) error {
661667 if srcVal .Type () != dstVal .Type () {
662668 return fmt .Errorf ("cannot copy %s to %s" , srcVal .Type ().Name (), dstVal .Type ().Name ())
663669 }
@@ -666,27 +672,21 @@ func copyStruct(dstVal, srcVal reflect.Value, opts ...MergeOpt) error {
666672 return fmt .Errorf ("cannot handle non-struct types, src: %v, dst: %v" , srcVal .Type ().Kind (), dstVal .Type ().Kind ())
667673 }
668674
675+ var errs []error
669676 for i := 0 ; i < srcVal .NumField (); i ++ {
670677 srcField := srcVal .Field (i )
671678 dstField := dstVal .Field (i )
679+ accessPath := accessPath + "." + srcVal .Type ().Field (i ).Name
672680
673681 switch srcField .Kind () {
674682 case reflect .Ptr :
675- if err := copyPtrField (dstField , srcField , opts ... ); err != nil {
676- return err
677- }
683+ errs = append (errs , copyPtrField (dstField , srcField , accessPath , opts ... ))
678684 case reflect .Interface :
679- if err := copyInterfaceField (dstField , srcField , opts ... ); err != nil {
680- return err
681- }
685+ errs = append (errs , copyInterfaceField (dstField , srcField , accessPath , opts ... ))
682686 case reflect .Map :
683- if err := copyMapField (dstField , srcField , opts ... ); err != nil {
684- return err
685- }
687+ errs = append (errs , copyMapField (dstField , srcField , accessPath , opts ... ))
686688 case reflect .Slice :
687- if err := copySliceField (dstField , srcField , opts ... ); err != nil {
688- return err
689- }
689+ errs = append (errs , copySliceField (dstField , srcField , accessPath , opts ... ))
690690 case reflect .Int64 :
691691 // In the case of an int64 field, which represents a YANG enumeration
692692 // we should only set the value in the destination if it is not set
@@ -695,7 +695,8 @@ func copyStruct(dstVal, srcVal reflect.Value, opts ...MergeOpt) error {
695695 switch {
696696 case vSrc != 0 && vDst != 0 && vSrc != vDst :
697697 if ! fieldOverwriteEnabled (opts ) {
698- return fmt .Errorf ("destination and source values were set when merging enum field, dst: %d, src: %d" , vSrc , vDst )
698+ errs = append (errs , fmt .Errorf ("%s: destination and source values were set when merging enum field, dst: %d, src: %d" , accessPath , vSrc , vDst ))
699+ break
699700 }
700701 dstField .Set (srcField )
701702 case vSrc != 0 && vDst == 0 :
@@ -705,7 +706,7 @@ func copyStruct(dstVal, srcVal reflect.Value, opts ...MergeOpt) error {
705706 dstField .Set (srcField )
706707 }
707708 }
708- return nil
709+ return joinErrors ( errs ... )
709710}
710711
711712// copyPtrField copies srcField to dstField. srcField and dstField must be
@@ -715,7 +716,7 @@ func copyStruct(dstVal, srcVal reflect.Value, opts ...MergeOpt) error {
715716// is returned. If the source and destination both have a pointer field, which is
716717// populated then an error is returned unless the value of the field is
717718// equal in both structs.
718- func copyPtrField (dstField , srcField reflect.Value , opts ... MergeOpt ) error {
719+ func copyPtrField (dstField , srcField reflect.Value , accessPath string , opts ... MergeOpt ) error {
719720
720721 if util .IsNilOrInvalidValue (srcField ) {
721722 return nil
@@ -738,7 +739,7 @@ func copyPtrField(dstField, srcField reflect.Value, opts ...MergeOpt) error {
738739 d = dstField
739740 }
740741
741- if err := copyStruct (d .Elem (), srcField .Elem (), opts ... ); err != nil {
742+ if err := copyStruct (d .Elem (), srcField .Elem (), accessPath , opts ... ); err != nil {
742743 return err
743744 }
744745 dstField .Set (d )
@@ -748,7 +749,7 @@ func copyPtrField(dstField, srcField reflect.Value, opts ...MergeOpt) error {
748749 if ! util .IsNilOrInvalidValue (dstField ) {
749750 s , d := srcField .Elem ().Interface (), dstField .Elem ().Interface ()
750751 if ! fieldOverwriteEnabled (opts ) && ! reflect .DeepEqual (s , d ) {
751- return fmt .Errorf ("destination value was set, but was not equal to source value when merging ptr field, src: %v, dst: %v" , s , d )
752+ return fmt .Errorf ("%s: destination value was set, but was not equal to source value when merging ptr field, src: %v, dst: %v" , accessPath , s , d )
752753 }
753754 }
754755
@@ -760,7 +761,7 @@ func copyPtrField(dstField, srcField reflect.Value, opts ...MergeOpt) error {
760761
761762// copyInterfaceField copies srcField into dstField. Both srcField and dstField
762763// are reflect.Value structs which contain an interface value.
763- func copyInterfaceField (dstField , srcField reflect.Value , opts ... MergeOpt ) error {
764+ func copyInterfaceField (dstField , srcField reflect.Value , accessPath string , opts ... MergeOpt ) error {
764765 if util .IsNilOrInvalidValue (srcField ) {
765766 return nil
766767 }
@@ -776,12 +777,12 @@ func copyInterfaceField(dstField, srcField reflect.Value, opts ...MergeOpt) erro
776777 if ! util .IsNilOrInvalidValue (dstField ) {
777778 dV := dstField .Elem ().Elem () // Dereference dst to a struct.
778779 if ! fieldOverwriteEnabled (opts ) && ! reflect .DeepEqual (s .Interface (), dV .Interface ()) {
779- return fmt .Errorf ("interface field was set in both src and dst and was not equal, src: %v, dst: %v" , s .Interface (), dV .Interface ())
780+ return fmt .Errorf ("%s: interface field was set in both src and dst and was not equal, src: %v, dst: %v" , accessPath , s .Interface (), dV .Interface ())
780781 }
781782 }
782783
783784 d := reflect .New (s .Type ())
784- if err := copyStruct (d .Elem (), s , opts ... ); err != nil {
785+ if err := copyStruct (d .Elem (), s , accessPath , opts ... ); err != nil {
785786 return err
786787 }
787788 dstField .Set (d )
@@ -790,7 +791,7 @@ func copyInterfaceField(dstField, srcField reflect.Value, opts ...MergeOpt) erro
790791 if ! util .IsNilOrInvalidValue (dstField ) {
791792 s , d := srcField .Interface (), dstField .Interface ()
792793 if ! fieldOverwriteEnabled (opts ) && ! reflect .DeepEqual (s , d ) {
793- return fmt .Errorf ("interface field was set in both src and dst and was not equal, src: %v, dst: %v" , s , d )
794+ return fmt .Errorf ("%s: interface field was set in both src and dst and was not equal, src: %v, dst: %v" , accessPath , s , d )
794795 }
795796 }
796797
@@ -805,7 +806,7 @@ func copyInterfaceField(dstField, srcField reflect.Value, opts ...MergeOpt) erro
805806 if ! util .IsNilOrInvalidValue (dstField ) {
806807 s , d := srcField .Interface (), dstField .Interface ()
807808 if ! fieldOverwriteEnabled (opts ) && ! reflect .DeepEqual (s , d ) {
808- return fmt .Errorf ("interface field was set in both src and dst and was not equal, src: %v, dst: %v" , s , d )
809+ return fmt .Errorf ("%s: interface field was set in both src and dst and was not equal, src: %v, dst: %v" , accessPath , s , d )
809810 }
810811 }
811812 dstField .Set (srcField )
@@ -819,7 +820,7 @@ func copyInterfaceField(dstField, srcField reflect.Value, opts ...MergeOpt) erro
819820// are populated, and have non-overlapping keys, they are merged. If the same
820821// key is populated in srcField and dstField, their contents are merged if they
821822// do not overlap, otherwise an error is returned.
822- func copyMapField (dstField , srcField reflect.Value , opts ... MergeOpt ) error {
823+ func copyMapField (dstField , srcField reflect.Value , accessPath string , opts ... MergeOpt ) error {
823824 if ! util .IsValueMap (srcField ) {
824825 return fmt .Errorf ("received a non-map type in src map field: %v" , srcField .Kind ())
825826 }
@@ -850,18 +851,20 @@ func copyMapField(dstField, srcField reflect.Value, opts ...MergeOpt) error {
850851 dstKeys [k .Interface ()] = true
851852 }
852853
854+ var errs []error
853855 for _ , k := range srcField .MapKeys () {
854856 v := srcField .MapIndex (k )
855857 d := reflect .New (v .Elem ().Type ())
856858 if _ , ok := dstKeys [k .Interface ()]; ok {
857859 d = dstField .MapIndex (k )
858860 }
859- if err := copyStruct (d .Elem (), v .Elem (), opts ... ); err != nil {
860- return err
861+ if err := copyStruct (d .Elem (), v .Elem (), fmt .Sprintf ("%s[%#v]" , accessPath , k .Interface ()), opts ... ); err != nil {
862+ errs = append (errs , err )
863+ continue
861864 }
862865 dstField .SetMapIndex (k , d )
863866 }
864- return nil
867+ return joinErrors ( errs ... )
865868}
866869
867870// mapTypes provides a specification of a map.
@@ -903,7 +906,7 @@ func validateMap(srcField, dstField reflect.Value) (*mapType, error) {
903906// copySliceField copies srcField into dstField. Both srcField and dstField
904907// must have a kind of reflect.Slice kind and contain pointers to structs. If
905908// the slice in dstField is populated an error is returned.
906- func copySliceField (dstField , srcField reflect.Value , opts ... MergeOpt ) error {
909+ func copySliceField (dstField , srcField reflect.Value , accessPath string , opts ... MergeOpt ) error {
907910 if dstField .Len () == 0 && srcField .Len () == 0 {
908911 return nil
909912 }
@@ -920,7 +923,7 @@ func copySliceField(dstField, srcField reflect.Value, opts ...MergeOpt) error {
920923
921924 if ! unique {
922925 // YANG lists and leaf-lists must be unique.
923- return fmt .Errorf ("source and destination lists must be unique, got src: %v, dst: %v" , srcField , dstField )
926+ return fmt .Errorf ("%s: source and destination lists must be unique, got src: %v, dst: %v" , accessPath , srcField , dstField )
924927 }
925928 }
926929
@@ -932,15 +935,17 @@ func copySliceField(dstField, srcField reflect.Value, opts ...MergeOpt) error {
932935 return nil
933936 }
934937
938+ var errs []error
935939 for i := 0 ; i < srcField .Len (); i ++ {
936940 v := srcField .Index (i )
937941 d := reflect .New (v .Type ().Elem ())
938- if err := copyStruct (d .Elem (), v .Elem (), opts ... ); err != nil {
939- return err
942+ if err := copyStruct (d .Elem (), v .Elem (), fmt .Sprintf ("%s[%v]" , accessPath , i ), opts ... ); err != nil {
943+ errs = append (errs , err )
944+ continue
940945 }
941946 dstField .Set (reflect .Append (dstField , v ))
942947 }
943- return nil
948+ return joinErrors ( errs ... )
944949}
945950
946951// uniqueSlices takes two reflect.Values which must represent slices, and determines
0 commit comments