mctx: GetSetMutableValue. Not sure if I'm really going to use this or not
This commit is contained in:
parent
e349d0fbd8
commit
cb65787f37
71
mctx/ctx.go
71
mctx/ctx.go
@ -131,14 +131,6 @@ func ChildOf(ctx Context, name string) Context {
|
|||||||
// return mlog.DefaultWriteFn(w, msg)
|
// return mlog.DefaultWriteFn(w, msg)
|
||||||
//})
|
//})
|
||||||
|
|
||||||
// copy mutable values
|
|
||||||
if len(s.mutVals) > 0 {
|
|
||||||
childS.mutVals = make(map[interface{}]interface{}, len(s.mutVals))
|
|
||||||
for key, val := range s.mutVals {
|
|
||||||
childS.mutVals[key] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// create child's ctx and store it in parent
|
// create child's ctx and store it in parent
|
||||||
childCtx := withCtxState(ctx, childS)
|
childCtx := withCtxState(ctx, childS)
|
||||||
if s.children == nil {
|
if s.children == nil {
|
||||||
@ -151,19 +143,6 @@ func ChildOf(ctx Context, name string) Context {
|
|||||||
// TODO these might not be worth the effort, they're very subject to
|
// TODO these might not be worth the effort, they're very subject to
|
||||||
// race-conditions
|
// race-conditions
|
||||||
|
|
||||||
// SetMutableValue is like WithMutable, except rather than leaving the original
|
|
||||||
// ctx unaffected it modifies the value in that context. Children of this
|
|
||||||
// context will inherit an independent copy of its immutable values.
|
|
||||||
func SetMutableValue(ctx Context, key, value interface{}) {
|
|
||||||
s := getCtxState(ctx)
|
|
||||||
s.l.Lock()
|
|
||||||
defer s.l.Unlock()
|
|
||||||
if s.mutVals == nil {
|
|
||||||
s.mutVals = map[interface{}]interface{}{}
|
|
||||||
}
|
|
||||||
s.mutVals[key] = value
|
|
||||||
}
|
|
||||||
|
|
||||||
// MutableValue acts like the Value method, except that it only deals with
|
// MutableValue acts like the Value method, except that it only deals with
|
||||||
// keys/values set by SetMutableValue.
|
// keys/values set by SetMutableValue.
|
||||||
func MutableValue(ctx Context, key interface{}) interface{} {
|
func MutableValue(ctx Context, key interface{}) interface{} {
|
||||||
@ -175,3 +154,53 @@ func MutableValue(ctx Context, key interface{}) interface{} {
|
|||||||
}
|
}
|
||||||
return s.mutVals[key]
|
return s.mutVals[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSetMutableValue is used to interact with a mutable value on the context in
|
||||||
|
// a thread-safe way. The key's value is retrieved and passed to the callback.
|
||||||
|
// The value returned from the callback is stored to back into the context as
|
||||||
|
// well as being returned from this function.
|
||||||
|
//
|
||||||
|
// If noCallbackIfSet is set to true, then this function will only return the
|
||||||
|
// value for the key if it's already set and not use the callback at all.
|
||||||
|
//
|
||||||
|
// The callback returning nil is equivalent to unsetting the value.
|
||||||
|
//
|
||||||
|
// Children of this context will _not_ inherit any of its mutable values.
|
||||||
|
func GetSetMutableValue(
|
||||||
|
ctx Context, noCallbackIfSet bool,
|
||||||
|
key interface{}, fn func(interface{}) interface{},
|
||||||
|
) interface{} {
|
||||||
|
s := getCtxState(ctx)
|
||||||
|
|
||||||
|
if noCallbackIfSet {
|
||||||
|
s.l.RLock()
|
||||||
|
if s.mutVals != nil && s.mutVals[key] != nil {
|
||||||
|
defer s.l.RUnlock()
|
||||||
|
return s.mutVals[key]
|
||||||
|
}
|
||||||
|
s.l.RUnlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
s.l.Lock()
|
||||||
|
defer s.l.Unlock()
|
||||||
|
|
||||||
|
if s.mutVals == nil {
|
||||||
|
s.mutVals = map[interface{}]interface{}{}
|
||||||
|
}
|
||||||
|
val := s.mutVals[key]
|
||||||
|
|
||||||
|
// It's possible something happened between the first check inside the
|
||||||
|
// read-lock and now, so double check this case. It's still good to have the
|
||||||
|
// read-lock check there, it'll handle 99% of the cases.
|
||||||
|
if noCallbackIfSet && val != nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
|
||||||
|
val = fn(val)
|
||||||
|
if val == nil {
|
||||||
|
delete(s.mutVals, key)
|
||||||
|
} else {
|
||||||
|
s.mutVals[key] = val
|
||||||
|
}
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
@ -6,15 +6,11 @@ import (
|
|||||||
"github.com/mediocregopher/mediocre-go-lib/mtest/massert"
|
"github.com/mediocregopher/mediocre-go-lib/mtest/massert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestContext(t *T) {
|
func TestInheritance(t *T) {
|
||||||
ctx := New()
|
ctx := New()
|
||||||
SetMutableValue(ctx, "one", 1)
|
|
||||||
|
|
||||||
ctx1 := ChildOf(ctx, "1")
|
ctx1 := ChildOf(ctx, "1")
|
||||||
ctx1a := ChildOf(ctx1, "a")
|
ctx1a := ChildOf(ctx1, "a")
|
||||||
SetMutableValue(ctx1, "one", 2)
|
|
||||||
ctx1b := ChildOf(ctx1, "b")
|
ctx1b := ChildOf(ctx1, "b")
|
||||||
SetMutableValue(ctx1b, "one", 3)
|
|
||||||
ctx2 := ChildOf(ctx, "2")
|
ctx2 := ChildOf(ctx, "2")
|
||||||
|
|
||||||
massert.Fatal(t, massert.All(
|
massert.Fatal(t, massert.All(
|
||||||
@ -47,12 +43,29 @@ func TestContext(t *T) {
|
|||||||
massert.Equal(Parent(ctx1b), ctx1),
|
massert.Equal(Parent(ctx1b), ctx1),
|
||||||
massert.Equal(Parent(ctx2), ctx),
|
massert.Equal(Parent(ctx2), ctx),
|
||||||
))
|
))
|
||||||
|
}
|
||||||
massert.Fatal(t, massert.All(
|
|
||||||
massert.Equal(MutableValue(ctx, "one"), 1),
|
func TestMutableValues(t *T) {
|
||||||
massert.Equal(MutableValue(ctx1, "one"), 2),
|
fn := func(v interface{}) interface{} {
|
||||||
massert.Equal(MutableValue(ctx1a, "one"), 1),
|
if v == nil {
|
||||||
massert.Equal(MutableValue(ctx1b, "one"), 3),
|
return 0
|
||||||
massert.Equal(MutableValue(ctx2, "one"), 1),
|
}
|
||||||
))
|
return v.(int) + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
var aa []massert.Assertion
|
||||||
|
|
||||||
|
ctx := New()
|
||||||
|
aa = append(aa, massert.Equal(GetSetMutableValue(ctx, false, 0, fn), 0))
|
||||||
|
aa = append(aa, massert.Equal(GetSetMutableValue(ctx, false, 0, fn), 1))
|
||||||
|
aa = append(aa, massert.Equal(GetSetMutableValue(ctx, true, 0, fn), 1))
|
||||||
|
|
||||||
|
aa = append(aa, massert.Equal(MutableValue(ctx, 0), 1))
|
||||||
|
|
||||||
|
ctx1 := ChildOf(ctx, "one")
|
||||||
|
aa = append(aa, massert.Equal(GetSetMutableValue(ctx1, true, 0, fn), 0))
|
||||||
|
aa = append(aa, massert.Equal(GetSetMutableValue(ctx1, false, 0, fn), 1))
|
||||||
|
aa = append(aa, massert.Equal(GetSetMutableValue(ctx1, true, 0, fn), 1))
|
||||||
|
|
||||||
|
massert.Fatal(t, massert.All(aa...))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user