Skip to content

Commit

Permalink
Merge pull request #41 from ccremer/mutable
Browse files Browse the repository at this point in the history
Rename VariableContext to MutableContext
  • Loading branch information
ccremer committed Apr 13, 2022
2 parents 1ff2a54 + 8811211 commit 7d7af0c
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 27 deletions.
32 changes: 18 additions & 14 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,42 @@ import (

type contextKey struct{}

// VariableContext adds a map to the given context that can be used to store intermediate values in the context.
// MutableContext adds a map to the given context that can be used to store mutable values in the context.
// It uses sync.Map under the hood.
// Repeated calls to MutableContext with the same parent has no effect and returns the same context.
//
// See also AddToContext() and ValueFromContext.
func VariableContext(parent context.Context) context.Context {
return context.WithValue(parent, contextKey{}, &sync.Map{})
// See also StoreInContext and LoadFromContext.
func MutableContext(parent context.Context) context.Context {
if parent.Value(contextKey{}) == nil {
return context.WithValue(parent, contextKey{}, &sync.Map{})
}
return parent
}

// AddToContext adds the given key and value to ctx.
// StoreInContext adds the given key and value to ctx.
// Any keys or values added during pipeline execution is available in the next steps, provided the pipeline runs synchronously.
// In parallel executed pipelines you may encounter race conditions.
// Use ValueFromContext to retrieve values.
// Use LoadFromContext to retrieve values.
//
// Note: This method is thread-safe, but panics if ctx has not been set up with VariableContext first.
func AddToContext(ctx context.Context, key, value interface{}) {
// Note: This method is thread-safe, but panics if ctx has not been set up with MutableContext first.
func StoreInContext(ctx context.Context, key, value interface{}) {
m := ctx.Value(contextKey{})
if m == nil {
panic(errors.New("context was not set up with VariableContext()"))
panic(errors.New("context was not set up with MutableContext()"))
}
m.(*sync.Map).Store(key, value)
}

// ValueFromContext returns the value from the given context with the given key.
// LoadFromContext returns the value from the given context with the given key.
// It returns the value and true, or nil and false if the key doesn't exist.
// It may return nil and true if the key exists, but the value actually is nil.
// Use AddToContext to store values.
// Use StoreInContext to store values.
//
// Note: This method is thread-safe, but panics if the ctx has not been set up with VariableContext first.
func ValueFromContext(ctx context.Context, key interface{}) (interface{}, bool) {
// Note: This method is thread-safe, but panics if the ctx has not been set up with MutableContext first.
func LoadFromContext(ctx context.Context, key interface{}) (interface{}, bool) {
m := ctx.Value(contextKey{})
if m == nil {
panic(errors.New("context was not set up with VariableContext()"))
panic(errors.New("context was not set up with MutableContext()"))
}
mp := m.(*sync.Map)
val, found := mp.Load(key)
Expand Down
34 changes: 21 additions & 13 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,35 +34,43 @@ func TestContext(t *testing.T) {
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
ctx := VariableContext(context.Background())
ctx := MutableContext(context.Background())
if tc.givenKey != nil {
AddToContext(ctx, tc.givenKey, tc.givenValue)
StoreInContext(ctx, tc.givenKey, tc.givenValue)
}
result, found := ValueFromContext(ctx, tc.givenKey)
result, found := LoadFromContext(ctx, tc.givenKey)
assert.Equal(t, tc.expectedValue, result, "value")
assert.Equal(t, tc.expectedFound, found, "value found")
})
}
}

func TestContextPanics(t *testing.T) {
assert.PanicsWithError(t, "context was not set up with VariableContext()", func() {
AddToContext(context.Background(), "key", "value")
}, "AddToContext")
assert.PanicsWithError(t, "context was not set up with VariableContext()", func() {
ValueFromContext(context.Background(), "key")
}, "ValueFromContext")
assert.PanicsWithError(t, "context was not set up with MutableContext()", func() {
StoreInContext(context.Background(), "key", "value")
}, "StoreInContext")
assert.PanicsWithError(t, "context was not set up with MutableContext()", func() {
LoadFromContext(context.Background(), "key")
}, "LoadFromContext")
}

func ExampleVariableContext() {
ctx := VariableContext(context.Background())
func TestMutableContextRepeated(t *testing.T) {
parent := context.Background()
result := MutableContext(parent)
assert.NotEqual(t, parent, result)
repeated := MutableContext(result)
assert.Equal(t, result, repeated)
}

func ExampleMutableContext() {
ctx := MutableContext(context.Background())
p := NewPipeline().WithSteps(
NewStepFromFunc("store value", func(ctx context.Context) error {
AddToContext(ctx, "key", "value")
StoreInContext(ctx, "key", "value")
return nil
}),
NewStepFromFunc("retrieve value", func(ctx context.Context) error {
value, _ := ValueFromContext(ctx, "key")
value, _ := LoadFromContext(ctx, "key")
fmt.Println(value)
return nil
}),
Expand Down

0 comments on commit 7d7af0c

Please sign in to comment.