diff --git a/ua/typereg.go b/ua/typereg.go index b31fc73c..bc126d47 100644 --- a/ua/typereg.go +++ b/ua/typereg.go @@ -7,13 +7,18 @@ package ua import ( "fmt" "reflect" + "sync" ) +// TypeRegistry maps numeric ids to Go types. +// The implementation is safe for concurrent use. type TypeRegistry struct { + mu sync.RWMutex types map[uint32]reflect.Type ids map[reflect.Type]uint32 } +// NewTypeRegistry returns a new type registry. func NewTypeRegistry() *TypeRegistry { return &TypeRegistry{ types: make(map[uint32]reflect.Type), @@ -21,7 +26,12 @@ func NewTypeRegistry() *TypeRegistry { } } +// New returns a new instance of the type with the given id. +// If the id is not known the function returns nil. func (r *TypeRegistry) New(id uint32) interface{} { + r.mu.RLock() + defer r.mu.RUnlock() + typ, ok := r.types[id] if !ok { return nil @@ -29,11 +39,21 @@ func (r *TypeRegistry) New(id uint32) interface{} { return reflect.New(typ.Elem()).Interface() } +// Lookup returns the id of the type of v or zero if the +// type is not registered. func (r *TypeRegistry) Lookup(v interface{}) uint32 { + r.mu.RLock() + defer r.mu.RUnlock() + return r.ids[reflect.TypeOf(v)] } +// Register adds a new type to the registry. If either the type +// or the id is already registered the function returns an error. func (r *TypeRegistry) Register(id uint32, v interface{}) error { + r.mu.Lock() + defer r.mu.Unlock() + typ := reflect.TypeOf(v) if r.types[id] != nil {