// Copyright 2015-2018 trivago N.V. // // 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 treflect import ( "fmt" "reflect" "strings" ) // TypeRegistry is a name to type registry used to create objects by name. type TypeRegistry struct { namedType map[string]reflect.Type } // NewTypeRegistry creates a new TypeRegistry. Note that there is a global type // registry available in the main tgo package (tgo.TypeRegistry). func NewTypeRegistry() TypeRegistry { return TypeRegistry{ namedType: make(map[string]reflect.Type), } } // Register a plugin to the TypeRegistry by passing an uninitialized object. func (registry TypeRegistry) Register(typeInstance interface{}) { registry.RegisterWithDepth(typeInstance, 1) } // RegisterWithDepth to register a plugin to the TypeRegistry by passing an uninitialized object. func (registry TypeRegistry) RegisterWithDepth(typeInstance interface{}, depth int) { structType := reflect.TypeOf(typeInstance) packageName := structType.PkgPath() typeName := structType.Name() pathTokens := strings.Split(packageName, "/") maxDepth := 3 if len(pathTokens) < maxDepth { maxDepth = len(pathTokens) } for n := depth; n <= maxDepth; n++ { shortTypeName := strings.Join(pathTokens[len(pathTokens)-n:], ".") + "." + typeName registry.namedType[shortTypeName] = structType } } // New creates an uninitialized object by class name. // The class name has to be "package.class" or "package/subpackage.class". // The gollum package is omitted from the package path. func (registry TypeRegistry) New(typeName string) (interface{}, error) { structType, exists := registry.namedType[typeName] if exists { return reflect.New(structType).Interface(), nil } return nil, fmt.Errorf("Unknown class: %s", typeName) } // GetTypeOf returns only the type asscociated with the given name. // If the name is not registered, nil is returned. // The type returned will be a pointer type. func (registry TypeRegistry) GetTypeOf(typeName string) reflect.Type { if structType, exists := registry.namedType[typeName]; exists { return reflect.PtrTo(structType) } return nil } // IsTypeRegistered returns true if a type is registered to this registry. // Note that GetTypeOf can do the same thing by checking for nil but also // returns the type, so in many cases you will want to call this function. func (registry TypeRegistry) IsTypeRegistered(typeName string) bool { _, exists := registry.namedType[typeName] return exists } // GetRegistered returns the names of all registered types for a given package func (registry TypeRegistry) GetRegistered(packageName string) []string { var result []string for key := range registry.namedType { if strings.HasPrefix(key, packageName) { result = append(result, key) } } return result }