load/registry/registry.go
// Copyright © 2016 Asteris, LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package registry
import (
"fmt"
"reflect"
)
// Registry for importable types
type Registry struct {
forward map[string]reflect.Type
reverse map[reflect.Type]string
}
// New creates a new Registry
func New() *Registry {
return &Registry{
map[string]reflect.Type{},
map[reflect.Type]string{},
}
}
// Register a new type by import name
func (r *Registry) Register(name string, i interface{}, reverse ...interface{}) error {
if _, present := r.forward[name]; present {
return fmt.Errorf("%q already registered", name)
}
r.forward[name] = reflect.TypeOf(i)
var err error
for _, rev := range append(reverse, i) {
if err = r.RegisterReverse(rev, name); err != nil {
break
}
}
return err
}
// RegisterReverse registers a name in reverse
func (r *Registry) RegisterReverse(i interface{}, name string) error {
t := reflect.TypeOf(i)
if _, present := r.reverse[t]; present {
return nil
}
r.reverse[t] = name
return nil
}
// NewByName creates a new value by the name it was registered under. If no
// type was registered at the given name, the second value will be false
func (r *Registry) NewByName(name string) (interface{}, bool) {
t, present := r.forward[name]
if !present {
return nil, false
}
var val reflect.Value
if t.Kind() == reflect.Ptr {
val = reflect.New(t.Elem())
} else {
val = reflect.New(t)
}
// send the interface...
if val.CanInterface() {
return val.Interface(), true
}
// ...but if we can't, return false
return nil, false
}
// NameForType retrieves the name registered for a type. If no name was
// registered for the given type, the second value will be false
func (r *Registry) NameForType(i interface{}) (string, bool) {
name, present := r.reverse[reflect.TypeOf(i)]
return name, present
}
// package-global API
var registry *Registry
// Register a type in the global registry
func Register(name string, i interface{}, reverse ...interface{}) {
if err := registry.Register(name, i, reverse...); err != nil {
panic(err)
}
}
// RegisterReverse registers a name in the global registry
func RegisterReverse(i interface{}, name string) {
if err := registry.RegisterReverse(i, name); err != nil {
panic(err)
}
}
// NewByName creates a new value by the name it was registered under. If no
// type was registered at the given name, the second value will be false
func NewByName(name string) (interface{}, bool) {
return registry.NewByName(name)
}
// NameForType retrieves the name registered for a type. If no name was
// registered for the given type, the second value will be false
func NameForType(i interface{}) (string, bool) {
return registry.NameForType(i)
}
func init() {
registry = New()
}