Skip to content

Commit

Permalink
Merge pull request #10 from ishank011/ctx
Browse files Browse the repository at this point in the history
Use reflection to manipulate valueCtx objects
  • Loading branch information
jimil749 authored Aug 3, 2021
2 parents eaa3683 + dff1379 commit 07dde32
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 37 deletions.
60 changes: 33 additions & 27 deletions pkg/appctx/ctxmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,44 +20,50 @@ package appctx

import (
"context"
"reflect"
"unsafe"
)

type emptyCtx int

type valueCtx struct {
context.Context
key, val interface{}
}

type iface struct {
itab, data uintptr //nolint
// PutKeyValuesToCtx puts all the key-value pairs from the provided map to a background context.
func PutKeyValuesToCtx(m map[interface{}]interface{}) context.Context {
ctx := context.Background()
for key, value := range m {
ctx = context.WithValue(ctx, key, value)
}
return ctx
}

// GetKeyValues retrieves all the key-value pairs from the provided context.
func GetKeyValues(ctx context.Context) map[interface{}]interface{} {
// GetKeyValuesFromCtx retrieves all the key-value pairs from the provided context.
func GetKeyValuesFromCtx(ctx context.Context) map[interface{}]interface{} {
m := make(map[interface{}]interface{})
getKeyValue(ctx, m)
return m
}

// PutKeyValues puts
func PutKeyValues(m map[interface{}]interface{}) context.Context {
ctx := context.Background()
for key, value := range m {
ctx = context.WithValue(ctx, key, value)
func getKeyValue(ctx context.Context, m map[interface{}]interface{}) {
ctxVals := reflect.ValueOf(ctx).Elem()
ctxType := reflect.TypeOf(ctx).Elem()

if ctxType.Kind() == reflect.Struct {
for i := 0; i < ctxVals.NumField(); i++ {
currField, currIf := extractField(ctxVals, ctxType, i)
switch currField {
case "Context":
getKeyValue(currIf.(context.Context), m)
case "key":
nextField, nextIf := extractField(ctxVals, ctxType, i+1)
if nextField == "val" {
m[currIf] = nextIf
i++
}
}
}
}
return ctx
}

func getKeyValue(ctx context.Context, m map[interface{}]interface{}) {
ictx := *(*iface)(unsafe.Pointer(&ctx))
if ictx.data == 0 || int(*(*emptyCtx)(unsafe.Pointer(ictx.data))) == 0 {
return
}
valCtx := (*valueCtx)(unsafe.Pointer(ictx.data))
if valCtx != nil && valCtx.key != nil {
m[valCtx.key] = valCtx.val
}
getKeyValue(valCtx.Context, m)
func extractField(vals reflect.Value, fieldType reflect.Type, pos int) (string, interface{}) {
currVal := vals.Field(pos)
currVal = reflect.NewAt(currVal.Type(), unsafe.Pointer(currVal.UnsafeAddr())).Elem()
currField := fieldType.Field(pos)
return currField.Name, currVal.Interface()
}
32 changes: 22 additions & 10 deletions pkg/appctx/ctxmap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ import (
"context"
"testing"

userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/stretchr/testify/assert"
)

type ctxStringKey string
type ctxIntKey int

func TestGetKeyValues(t *testing.T) {
tests := []struct {
name string
Expand All @@ -38,24 +42,32 @@ func TestGetKeyValues(t *testing.T) {
},
{
"Context with Values",
context.WithValue(context.Background(), "key", "value"), //nolint
context.WithValue(context.Background(), ctxStringKey("key"), "value"),
map[interface{}]interface{}{
ctxStringKey("key"): "value",
},
},
{
"Context with user object",
context.WithValue(context.WithValue(context.Background(), ctxStringKey("key"), "value"), ctxStringKey("user"), &userpb.User{Username: "einstein"}),
map[interface{}]interface{}{
"key": "value",
ctxStringKey("key"): "value",
ctxStringKey("user"): &userpb.User{Username: "einstein"},
},
},
{
"Nested Context with Values",
context.WithValue(context.WithValue(context.Background(), "key", "value"), "key2", "value2"), //nolint
"Nested Context with Values of different types",
context.WithValue(context.WithValue(context.Background(), ctxStringKey("key"), "value"), ctxIntKey(123), "value2"),
map[interface{}]interface{}{
"key": "value",
"key2": "value2",
ctxStringKey("key"): "value",
ctxIntKey(123): "value2",
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
kvMap := GetKeyValues(tt.ctx)
kvMap := GetKeyValuesFromCtx(tt.ctx)
assert.Equal(t, tt.m, kvMap)
})
}
Expand All @@ -75,15 +87,15 @@ func TestPutKeyValues(t *testing.T) {
{
"single kv pair",
map[interface{}]interface{}{
"key": "value",
ctxStringKey("key"): "value",
},
context.WithValue(context.Background(), "key", "value"), //nolint
context.WithValue(context.Background(), ctxStringKey("key"), "value"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := PutKeyValues(tt.m)
ctx := PutKeyValuesToCtx(tt.m)
assert.Equal(t, tt.ctx, ctx)
})
}
Expand Down

0 comments on commit 07dde32

Please sign in to comment.