package context import ( "reflect" "sync" ) type ContextKey string func (c ContextKey) String() string { return string(c) } func NewContext(parent Context) Context { c := &defaultContext{ Context: parent, } c.attributes = make(map[interface{}]interface{}) return c } type Context interface { Parent() Context SetAttribute(key interface{}, value interface{}) GetAttribute(key interface{}) (value interface{}) RemoveAttribute(key interface{}) ContainsAttribute(key interface{}) (exist bool) } type defaultContext struct { Context attributes map[interface{}]interface{} mtx sync.RWMutex } func (dc *defaultContext) Parent() Context { return dc.Context } func (dc *defaultContext) SetAttribute(key interface{}, value interface{}) { dc.checkInitialized() if key == nil { panic("nil key") } if !reflect.TypeOf(key).Comparable() { panic("key is not comparable") } dc.mtx.Lock() defer dc.mtx.Unlock() dc.attributes[key] = value } func (dc *defaultContext) GetAttribute(key interface{}) (value interface{}) { dc.checkInitialized() dc.mtx.RLock() defer dc.mtx.RUnlock() if _, ok := dc.attributes[key]; ok { return dc.attributes[key] } if nil == dc.Context { return nil } return dc.Context.GetAttribute(key) } func (dc *defaultContext) RemoveAttribute(key interface{}) { dc.checkInitialized() dc.mtx.Lock() defer dc.mtx.Unlock() if _, ok := dc.attributes[key]; ok { delete(dc.attributes, key) return } if nil == dc.Context { return } dc.Context.RemoveAttribute(key) } func (dc *defaultContext) ContainsAttribute(key interface{}) (exist bool) { dc.checkInitialized() dc.mtx.RLock() defer dc.mtx.RUnlock() if _, ok := dc.attributes[key]; ok { return true } if nil == dc.Context { return false } return dc.Context.ContainsAttribute(key) } func (dc *defaultContext) checkInitialized() { if nil == dc.attributes { panic("Attribute Manager: must be initialized") } }