From 19caaf7a5807077e83d474d00485be046dbcdb07 Mon Sep 17 00:00:00 2001 From: Cedric Cordenier Date: Thu, 19 Sep 2024 21:09:44 +0100 Subject: [PATCH 1/4] [chore] Handle aliases in slices --- pkg/values/bytes_test.go | 10 ++++++++++ pkg/values/value.go | 30 ++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/pkg/values/bytes_test.go b/pkg/values/bytes_test.go index 9dddc2cee..e2031430c 100644 --- a/pkg/values/bytes_test.go +++ b/pkg/values/bytes_test.go @@ -43,3 +43,13 @@ func Test_BytesUnwrapTo(t *testing.T) { require.NoError(t, err) assert.Nil(t, bp) } + +type alias uint8 + +func Test_BytesUnwrapToAlias(t *testing.T) { + bn := &Bytes{Underlying: []byte("hello")} + var bp []alias + err := bn.UnwrapTo(&bp) + require.NoError(t, err) + assert.Nil(t, bp) +} diff --git a/pkg/values/value.go b/pkg/values/value.go index c7787a950..080630553 100644 --- a/pkg/values/value.go +++ b/pkg/values/value.go @@ -278,10 +278,36 @@ func unwrapTo[T any](underlying T, to any) error { rTo := reflect.ValueOf(to) rUnderlying := reflect.ValueOf(underlying) underlyingPtr := reflect.PointerTo(rUnderlying.Type()) - if rTo.Kind() != reflect.Pointer || !rTo.CanConvert(underlyingPtr) { + if rTo.Kind() != reflect.Pointer { return fmt.Errorf("cannot unwrap to value of type: %T", to) } - reflect.Indirect(rTo.Convert(underlyingPtr)).Set(rUnderlying) + + if rTo.CanConvert(underlyingPtr) { + reflect.Indirect(rTo.Convert(underlyingPtr)).Set(rUnderlying) + return nil + } + + rToVal := reflect.Indirect(rTo) + if rToVal.Kind() == reflect.Slice && rUnderlying.Kind() == reflect.Slice { + for i := 0; i < rUnderlying.Len(); i++ { + el := rUnderlying.Index(i) + toEl := reflect.New(rToVal.Type().Elem()) + err := unwrapTo(el.Interface(), toEl.Interface()) + if err != nil { + return err + } + + if rToVal.Len() > i { + rToVal.Index(i).Set(reflect.Indirect(toEl)) + } else { + rToVal = reflect.Append(rToVal, reflect.Indirect(toEl)) + } + } + + return nil + } + + return fmt.Errorf("cannot unwrap to value of type: %T", to) } return nil From 03a35a500bc2c526c515a9143114757787ac5c16 Mon Sep 17 00:00:00 2001 From: Cedric Cordenier Date: Thu, 19 Sep 2024 21:40:51 +0100 Subject: [PATCH 2/4] More aliasing tests --- pkg/values/value_test.go | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/pkg/values/value_test.go b/pkg/values/value_test.go index 0fcdc156a..4cf484214 100644 --- a/pkg/values/value_test.go +++ b/pkg/values/value_test.go @@ -382,3 +382,71 @@ func Test_Copy(t *testing.T) { } } } + +type aliasByte []byte +type aliasString string +type aliasInt int +type aliasMap map[string]any + +func Test_Aliases(t *testing.T) { + testCases := []struct { + name string + val func() any + alias func() any + convert func(any) any + }{ + { + name: "alias to []byte", + val: func() any { return []byte("string") }, + alias: func() any { return aliasByte([]byte{}) }, + }, + { + name: "simple aliases", + val: func() any { return "string" }, + alias: func() any { return aliasByte("") }, + }, + { + name: "int", + val: func() any { return 2 }, + alias: func() any { return aliasInt(0) }, + convert: func(a any) any { return int(a.(int64)) }, + }, + { + name: "[][]byte -> []aliasByte", + val: func() any { return [][]byte{[]byte("hello")} }, + alias: func() any { return []aliasByte{} }, + convert: func(a any) any { + to := [][]byte{} + for _, v := range a.([]interface{}) { + to = append(to, v.([]byte)) + } + + return to + }, + }, + { + name: "aliasMap -> map[string]any", + val: func() any { return map[string]any{} }, + alias: func() any { return aliasMap{} }, + convert: func(a any) any { return map[string]any(a.(aliasMap)) }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(st *testing.T) { + v := tc.val() + wv, err := Wrap(v) + require.NoError(t, err) + + a := tc.alias() + err = wv.UnwrapTo(&a) + require.NoError(t, err) + + if tc.convert != nil { + assert.Equal(t, tc.convert(a), v) + } else { + assert.Equal(t, a, v) + } + }) + } +} From b4c4c9cba7116a0be5a1d0370e4cf488d83a1294 Mon Sep 17 00:00:00 2001 From: Sri Kidambi <1702865+kidambisrinivas@users.noreply.github.com> Date: Fri, 20 Sep 2024 09:47:06 +0100 Subject: [PATCH 3/4] Lint fix --- pkg/values/value_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/pkg/values/value_test.go b/pkg/values/value_test.go index 4cf484214..28e8808ad 100644 --- a/pkg/values/value_test.go +++ b/pkg/values/value_test.go @@ -384,7 +384,6 @@ func Test_Copy(t *testing.T) { } type aliasByte []byte -type aliasString string type aliasInt int type aliasMap map[string]any From 2d32dcce52ff7801b714580055fbd935cb7bb9b1 Mon Sep 17 00:00:00 2001 From: Cedric Cordenier Date: Fri, 20 Sep 2024 11:22:59 +0100 Subject: [PATCH 4/4] Fix test --- pkg/values/bytes_test.go | 12 +++++++++--- pkg/values/value.go | 20 ++++++++++++-------- pkg/values/value_test.go | 14 +++++++++++++- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/pkg/values/bytes_test.go b/pkg/values/bytes_test.go index e2031430c..7b0b2fc29 100644 --- a/pkg/values/bytes_test.go +++ b/pkg/values/bytes_test.go @@ -47,9 +47,15 @@ func Test_BytesUnwrapTo(t *testing.T) { type alias uint8 func Test_BytesUnwrapToAlias(t *testing.T) { - bn := &Bytes{Underlying: []byte("hello")} - var bp []alias + underlying := []byte("hello") + bn := &Bytes{Underlying: underlying} + bp := []alias{} err := bn.UnwrapTo(&bp) require.NoError(t, err) - assert.Nil(t, bp) + + got := []byte{} + for _, b := range bp { + got = append(got, byte(b)) + } + assert.Equal(t, underlying, got) } diff --git a/pkg/values/value.go b/pkg/values/value.go index 080630553..a4a23cc3b 100644 --- a/pkg/values/value.go +++ b/pkg/values/value.go @@ -289,21 +289,25 @@ func unwrapTo[T any](underlying T, to any) error { rToVal := reflect.Indirect(rTo) if rToVal.Kind() == reflect.Slice && rUnderlying.Kind() == reflect.Slice { + newList := reflect.MakeSlice(rToVal.Type(), rUnderlying.Len(), rUnderlying.Len()) for i := 0; i < rUnderlying.Len(); i++ { el := rUnderlying.Index(i) - toEl := reflect.New(rToVal.Type().Elem()) - err := unwrapTo(el.Interface(), toEl.Interface()) - if err != nil { - return err - } + toEl := newList.Index(i) - if rToVal.Len() > i { - rToVal.Index(i).Set(reflect.Indirect(toEl)) + if toEl.Kind() == reflect.Ptr { + err := unwrapTo(el.Interface(), toEl.Interface()) + if err != nil { + return err + } } else { - rToVal = reflect.Append(rToVal, reflect.Indirect(toEl)) + err := unwrapTo(el.Interface(), toEl.Addr().Interface()) + if err != nil { + return err + } } } + rToVal.Set(newList) return nil } diff --git a/pkg/values/value_test.go b/pkg/values/value_test.go index 28e8808ad..affd34406 100644 --- a/pkg/values/value_test.go +++ b/pkg/values/value_test.go @@ -384,8 +384,10 @@ func Test_Copy(t *testing.T) { } type aliasByte []byte +type aliasString string type aliasInt int type aliasMap map[string]any +type aliasSingleByte uint8 func Test_Aliases(t *testing.T) { testCases := []struct { @@ -402,7 +404,17 @@ func Test_Aliases(t *testing.T) { { name: "simple aliases", val: func() any { return "string" }, - alias: func() any { return aliasByte("") }, + alias: func() any { return aliasString("") }, + }, + { + name: "aliasByte -> []byte", + val: func() any { return []byte("string") }, + alias: func() any { return aliasByte([]byte{}) }, + }, + { + name: "[]aliasSingleByte -> []byte", + val: func() any { return []byte("string") }, + alias: func() any { return []aliasSingleByte{} }, }, { name: "int",