From 58d4ec615f7e4f77051bc6547f9afeb646fd3da3 Mon Sep 17 00:00:00 2001 From: Aditya Date: Wed, 19 Mar 2025 01:04:23 +0530 Subject: [PATCH] Fix panic when the decoding pointer type with custom decoding function --- .gitignore | 16 +++++++++++++- decoder.go | 10 ++++++++- decoder_test.go | 55 +++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index aa19ee2..67572eb 100644 --- a/.gitignore +++ b/.gitignore @@ -25,4 +25,18 @@ _testmain.go old.txt new.txt -/.idea \ No newline at end of file +/.idea# Devenv +.devenv* +devenv.local.nix + +# direnv +.direnv + +# pre-commit +.pre-commit-config.yaml + +# devenv nix files +devenv.nix +devenv.yaml +devenv.lock +.envrc \ No newline at end of file diff --git a/decoder.go b/decoder.go index e212422..576efc8 100644 --- a/decoder.go +++ b/decoder.go @@ -193,7 +193,15 @@ func (d *decoder) setFieldByType(current reflect.Value, namespace []byte, idx in return } - v.Set(reflect.ValueOf(val)) + if kind == reflect.Ptr { + newVal := reflect.New(v.Type().Elem()) + if set = d.setFieldByType(newVal.Elem(), namespace, idx); set { + v.Set(newVal) + } + } else { + v.Set(reflect.ValueOf(val)) + } + set = true return } diff --git a/decoder_test.go b/decoder_test.go index 99897ed..020e51d 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -830,21 +830,57 @@ func TestDecoderStruct(t *testing.T) { func TestDecoderNativeTime(t *testing.T) { + type TType time.Time + type TTypePtr *time.Time + type TTypePtrWithCustomDecoder *time.Time + type TestError struct { - Time time.Time - TimeNoValue time.Time - TimePtr *time.Time + Time time.Time + TimeNoValue time.Time + TimePtr *time.Time + TimeType TType + TimeTypeNoValue TType + TimeTypePtr TTypePtr + TimeTypePtrNoValue TTypePtr + TimeTypePtrWithCustomDecoder TTypePtrWithCustomDecoder + TimeTypePtrWithCustomDecoderNoValue TTypePtrWithCustomDecoder } values := url.Values{ - "Time": []string{"2006-01-02T15:04:05Z"}, - "TimeNoValue": []string{""}, - "TimePtr": []string{"2006-01-02T15:04:05Z"}, + "Time": []string{"2006-01-02T15:04:05Z"}, + "TimeNoValue": []string{""}, + "TimePtr": []string{"2006-01-02T15:04:05Z"}, + "TimeType": []string{"2006-01-02T15:04:05Z"}, + "TimeTypeNoValue": []string{""}, + "TimeTypePtr": []string{"2006-01-02T15:04:05Z"}, + "TimeTypePtrNoValue": []string{""}, + "TimeTypePtrWithCustomDecoder": []string{"2006-01-02T15:04:05Z"}, + "TimeTypePtrWithCustomDecoderNoValue": []string{""}, } var test TestError decoder := NewDecoder() + decoder.RegisterCustomTypeFunc(func(s []string) (interface{}, error) { + if s[0] == "" { + return TType{}, nil + } + parsed, err := time.Parse(time.RFC3339, s[0]) + if err != nil { + return nil, err + } + return TType(parsed), nil + }, TType{}) + decoder.RegisterCustomTypeFunc(func(s []string) (interface{}, error) { + if s[0] == "" { + return nil, nil + } + parsed, err := time.Parse(time.RFC3339, s[0]) + if err != nil { + return nil, err + } + return TTypePtrWithCustomDecoder(&parsed), nil + }, TTypePtrWithCustomDecoder(nil)) errs := decoder.Decode(&test, values) Equal(t, errs, nil) @@ -852,6 +888,13 @@ func TestDecoderNativeTime(t *testing.T) { tm, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05Z") Equal(t, test.Time.Equal(tm), true) Equal(t, test.TimeNoValue.Equal(tm), false) + Equal(t, tm.Equal(time.Time(test.TimeType)), true) + Equal(t, time.Time(test.TimeTypeNoValue).Equal(tm), false) + Equal(t, time.Time(test.TimeTypeNoValue).IsZero(), true) + Equal(t, (*time.Time)(test.TimeTypePtr).Equal(tm), true) + Equal(t, test.TimeTypePtrNoValue, nil) + Equal(t, (*time.Time)(test.TimeTypePtrWithCustomDecoder).Equal(tm), true) + Equal(t, test.TimeTypePtrWithCustomDecoderNoValue, nil) NotEqual(t, test.TimePtr, nil) Equal(t, (*test.TimePtr).Equal(tm), true)