mediocre-go-lib/m/ctx.go

74 lines
1.9 KiB
Go

package m
import (
"context"
"sync"
)
type ctxKey int
const (
ctxStateKey ctxKey = iota
)
type ctxState struct {
path []string
l sync.RWMutex
children map[string]context.Context
}
func newCtxState() *ctxState {
return &ctxState{
children: map[string]context.Context{},
}
}
// Ctx returns a new context which can be used as the root context for all
// purposes in this framework.
func Ctx() context.Context {
return context.WithValue(context.Background(), ctxStateKey, newCtxState())
}
func getCtxState(ctx context.Context) *ctxState {
s, _ := ctx.Value(ctxStateKey).(*ctxState)
if s == nil {
panic("non-conforming context used")
}
return s
}
// Path returns the sequence of names which were used to produce this context
// via the ChildOf function.
func Path(ctx context.Context) []string {
return getCtxState(ctx).path
}
// Children returns all children of this context which have been created by
// ChildOf, mapped by their name.
func Children(ctx context.Context) map[string]context.Context {
s := getCtxState(ctx)
out := map[string]context.Context{}
s.l.RLock()
defer s.l.RUnlock()
for name, childCtx := range s.children {
out[name] = childCtx
}
return out
}
// ChildOf creates a child of the given context with the given name and returns
// it. The Path of the returned context will be the path of the parent with its
// name appended to it. The Children function can be called on the parent to
// retrieve all children which have been made using this function.
func ChildOf(ctx context.Context, name string) context.Context {
s, childS := getCtxState(ctx), newCtxState()
s.l.Lock()
defer s.l.Unlock()
childS.path = make([]string, 0, len(s.path)+1)
childS.path = append(childS.path, s.path...)
childS.path = append(childS.path, name)
childCtx := context.WithValue(ctx, ctxStateKey, childS)
s.children[name] = childCtx
return childCtx
}