From c163d6cc431824526175f5e6567ca81dd053eaa7 Mon Sep 17 00:00:00 2001 From: Morgan Pittkin Date: Thu, 29 Aug 2024 12:38:05 -0400 Subject: [PATCH] If 'from' is a struct and 'to' is an empty interface with a nil value, simply copy the value This avoids a panic when attempting to examine the type of 'from' --- copier.go | 6 ++++++ copier_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/copier.go b/copier.go index 175ad82..7fb2116 100644 --- a/copier.go +++ b/copier.go @@ -139,6 +139,12 @@ func copier(toValue interface{}, fromValue interface{}, opt Option) (err error) return ErrInvalidCopyFrom } + // If the target is an empty interface with value nil, simply copy the value + if from.Kind() == reflect.Struct && from.Type().AssignableTo(to.Type()) && reflect.TypeOf(to.Interface()) == nil { + to.Set(from) + return + } + fromType, isPtrFrom := indirectType(from.Type()) toType, _ := indirectType(to.Type()) diff --git a/copier_test.go b/copier_test.go index 1441df5..1d9e712 100644 --- a/copier_test.go +++ b/copier_test.go @@ -1774,3 +1774,35 @@ func TestNestedNilPointerStruct(t *testing.T) { t.Errorf("to (%v) value should equal from (%v) value", to.Title, from.Title) } } + +type testStruct struct { + Prop string +} + +type testHolder struct { + Data interface{} +} + +func newHolder(data interface{}) testHolder { + h := testHolder{} + copier.Copy(&(h.Data), data) + return h +} + +func getDataFromHolder(holder testHolder, data interface{}) { + copier.Copy(data, holder.Data) +} + +func TestCopyToNilEmptyInterface(t *testing.T) { + expected := testStruct{Prop: "expected"} + + holder := newHolder(&expected) + + actual := testStruct{} + + getDataFromHolder(holder, &actual) + + if expected.Prop != actual.Prop { + t.Fatalf("wanted %s got %s", expected.Prop, actual.Prop) + } +}