| 784 | } |
| 785 | |
| 786 | func convertRecursively(newVal, tmplVal reflect.Value) (reflect.Value, error) { |
| 787 | // Unwrap any any |
| 788 | if newVal.Kind() == reflect.Interface && !newVal.IsNil() { |
| 789 | newVal = newVal.Elem() |
| 790 | } |
| 791 | if tmplVal.Kind() == reflect.Interface && !tmplVal.IsNil() { |
| 792 | tmplVal = tmplVal.Elem() |
| 793 | } |
| 794 | switch tmplVal.Kind() { |
| 795 | case reflect.Slice: |
| 796 | // Both must be slices and have the same length |
| 797 | if newVal.Kind() != reflect.Slice { |
| 798 | return reflect.Zero(tmplVal.Type()), |
| 799 | fmt.Errorf("expected slice, got %s", newVal.Kind()) |
| 800 | } |
| 801 | out := reflect.MakeSlice(tmplVal.Type(), newVal.Len(), newVal.Len()) |
| 802 | for i := 0; i < newVal.Len(); i++ { |
| 803 | cv, err := convertRecursively(newVal.Index(i), tmplVal.Index(i)) |
| 804 | if err != nil { |
| 805 | return reflect.Zero(tmplVal.Type()), err |
| 806 | } |
| 807 | out.Index(i).Set(cv) |
| 808 | } |
| 809 | return out, nil |
| 810 | |
| 811 | case reflect.Map: |
| 812 | if newVal.Kind() != reflect.Map { |
| 813 | return reflect.Zero(tmplVal.Type()), |
| 814 | fmt.Errorf("expected map, got %s", newVal.Kind()) |
| 815 | } |
| 816 | out := reflect.MakeMapWithSize(tmplVal.Type(), newVal.Len()) |
| 817 | for _, key := range newVal.MapKeys() { |
| 818 | // Get the actual key value for map lookup |
| 819 | // For interface keys, use .Elem() to get the underlying value |
| 820 | // For non-interface keys (string, int, etc.), use key directly |
| 821 | lookupKey := key |
| 822 | if key.Kind() == reflect.Interface && !key.IsNil() { |
| 823 | lookupKey = key.Elem() |
| 824 | } |
| 825 | vNew := newVal.MapIndex(lookupKey) |
| 826 | vTmpl := tmplVal.MapIndex(lookupKey) |
| 827 | if !vTmpl.IsValid() { |
| 828 | return reflect.Zero(tmplVal.Type()), |
| 829 | fmt.Errorf("key %v not found in template map", key) |
| 830 | } |
| 831 | ck, err := convertRecursively(key, key) |
| 832 | if err != nil { |
| 833 | return reflect.Zero(tmplVal.Type()), err |
| 834 | } |
| 835 | cv, err := convertRecursively(vNew, vTmpl) |
| 836 | if err != nil { |
| 837 | return reflect.Zero(tmplVal.Type()), err |
| 838 | } |
| 839 | out.SetMapIndex(ck, cv) |
| 840 | } |
| 841 | return out, nil |
| 842 | case reflect.Ptr: |
| 843 | var innerNewVal reflect.Value |