1
// Copyright 2014 Canonical Ltd.
2
// Licensed under the LGPLv3, see LICENCE file for details.
11
"github.com/juju/errors"
14
// TypedNameVersion is a registry that will allow you to register objects based
15
// on a name and version pair. The objects must be convertible to the Type
16
// defined when the registry was created. It will be cast during Register so
17
// you can be sure all objects returned from Get() are safe to TypeAssert to
19
type TypedNameVersion struct {
20
requiredType reflect.Type
21
versions map[string]Versions
24
// NewTypedNameVersion creates a place to register your objects
25
func NewTypedNameVersion(requiredType reflect.Type) *TypedNameVersion {
26
return &TypedNameVersion{
27
requiredType: requiredType,
28
versions: make(map[string]Versions),
32
// Description gives the name and available versions in a registry.
33
type Description struct {
38
// Versions maps concrete versions of the objects.
39
type Versions map[int]interface{}
41
// Register records the factory that can be used to produce an instance of the
42
// facade at the supplied version.
43
// If the object being registered doesn't Implement the required Type, then an
45
// An error is also returned if an object is already registered with the given
47
func (r *TypedNameVersion) Register(name string, version int, obj interface{}) error {
48
if !reflect.TypeOf(obj).ConvertibleTo(r.requiredType) {
49
return fmt.Errorf("object of type %T cannot be converted to type %s.%s", obj, r.requiredType.PkgPath(), r.requiredType.Name())
51
obj = reflect.ValueOf(obj).Convert(r.requiredType).Interface()
52
if r.versions == nil {
53
r.versions = make(map[string]Versions, 1)
55
if versions, ok := r.versions[name]; ok {
56
if _, ok := versions[version]; ok {
57
fullname := fmt.Sprintf("%s(%d)", name, version)
58
return fmt.Errorf("object %q already registered", fullname)
60
versions[version] = obj
62
r.versions[name] = Versions{version: obj}
67
// descriptionFromVersions aggregates the information in a Versions map into a
68
// more friendly form for List()
69
func descriptionFromVersions(name string, versions Versions) Description {
70
intVersions := make([]int, 0, len(versions))
71
for version := range versions {
72
intVersions = append(intVersions, version)
74
sort.Ints(intVersions)
77
Versions: intVersions,
81
// List returns a slice describing each of the registered Facades.
82
func (r *TypedNameVersion) List() []Description {
83
names := make([]string, 0, len(r.versions))
84
for name := range r.versions {
85
names = append(names, name)
88
descriptions := make([]Description, len(r.versions))
89
for i, name := range names {
90
versions := r.versions[name]
91
descriptions[i] = descriptionFromVersions(name, versions)
96
// Get returns the object for a single name and version. If the requested
97
// facade is not found, it returns error.NotFound
98
func (r *TypedNameVersion) Get(name string, version int) (interface{}, error) {
99
if versions, ok := r.versions[name]; ok {
100
if factory, ok := versions[version]; ok {
104
return nil, errors.NotFoundf("%s(%d)", name, version)