-
Notifications
You must be signed in to change notification settings - Fork 18
/
registry.go
139 lines (117 loc) · 4.05 KB
/
registry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
// Copyright 2023 The Witness Contributors
//
// 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"
"time"
)
// Registry is a way for the library to expose details about available configuration options
// for a collection of Entities at run time. This is useful to do things such as expose attestor
// configuration options to Witness CLI. This lets the CLI create flags for all the available
// options at run time.
type Registry[T any] struct {
entriesByName map[string]Entry[T]
}
// FactoryFunc is a function that will create an instantiation of an Entity
type FactoryFunc[T any] func() T
// Entry contains information about each of the Entities in the Registry including the factory
// function, name, and configurable options
type Entry[T any] struct {
Factory FactoryFunc[T]
Name string
Options []Configurer
}
// New returns a new instance of a Registry
func New[T any]() Registry[T] {
reg := Registry[T]{
entriesByName: make(map[string]Entry[T]),
}
return reg
}
// Register adds an Entry to the Registry for an Entity
func (r Registry[T]) Register(name string, factoryFunc FactoryFunc[T], opts ...Configurer) Entry[T] {
entry := Entry[T]{
Name: name,
Factory: factoryFunc,
Options: opts,
}
r.entriesByName[name] = entry
return entry
}
// Options returns all of the available options an Entity with the provided name. If an Entity with the
// provided name cannot be found in the Registry the boolean return value will be false.
func (r Registry[T]) Options(name string) ([]Configurer, bool) {
entry, ok := r.entriesByName[name]
return entry.Options, ok
}
// Entry returns the Registry Entry for an Entity with the provided name. If an entity with the
// provided name cannot be found in the Registry, the boolean return value will be false.
func (r Registry[T]) Entry(name string) (Entry[T], bool) {
entry, ok := r.entriesByName[name]
return entry, ok
}
// AllEntries returns every Entry in the Registry
func (r Registry[T]) AllEntries() []Entry[T] {
results := make([]Entry[T], 0, len(r.entriesByName))
for _, registration := range r.entriesByName {
results = append(results, registration)
}
return results
}
// NewEntity creates a new entity with the the default options set
func (r Registry[T]) NewEntity(name string, optSetters ...func(T) (T, error)) (T, error) {
var result T
entry, ok := r.Entry(name)
if !ok {
return result, fmt.Errorf("could not find entry with name %v", name)
}
result, err := r.SetDefaultVals(entry.Factory(), entry.Options)
if err != nil {
return result, err
}
return SetOptions(result, optSetters...)
}
func SetOptions[T any](entity T, optSetters ...func(T) (T, error)) (T, error) {
var err error
result := entity
for _, setter := range optSetters {
result, err = setter(result)
if err != nil {
return result, err
}
}
return result, err
}
// SetDefaultVals will take an Entity and call Setter for every option with that option's defaultVal.
func (r Registry[T]) SetDefaultVals(entity T, opts []Configurer) (T, error) {
var err error
for _, opt := range opts {
switch o := opt.(type) {
case *ConfigOption[T, int]:
entity, err = o.Setter()(entity, o.DefaultVal())
case *ConfigOption[T, string]:
entity, err = o.Setter()(entity, o.DefaultVal())
case *ConfigOption[T, []string]:
entity, err = o.Setter()(entity, o.DefaultVal())
case *ConfigOption[T, bool]:
entity, err = o.Setter()(entity, o.DefaultVal())
case *ConfigOption[T, time.Duration]:
entity, err = o.Setter()(entity, o.DefaultVal())
}
if err != nil {
return entity, err
}
}
return entity, nil
}