Skip to content

Commit 5d822f7

Browse files
committed
Fix review comments
Signed-off-by: Bogdan Drutu <[email protected]>
1 parent 1d55976 commit 5d822f7

File tree

2 files changed

+67
-83
lines changed

2 files changed

+67
-83
lines changed

config/configmap.go

+48-68
Original file line numberDiff line numberDiff line change
@@ -164,16 +164,23 @@ func decoderConfig(result interface{}) *mapstructure.DecoderConfig {
164164
TagName: "mapstructure",
165165
WeaklyTypedInput: true,
166166
DecodeHook: mapstructure.ComposeDecodeHookFunc(
167-
expandNilStructPointers(),
168-
mapstructure.StringToSliceHookFunc(","),
169-
mapStringToMapComponentIDHookFunc(),
170-
stringToComponentIDHookFunc(),
171-
mapstructure.StringToTimeDurationHookFunc(),
172-
mapstructure.TextUnmarshallerHookFunc(),
167+
expandNilStructPointersFunc,
168+
stringToSliceHookFunc,
169+
mapStringToMapComponentIDHookFunc,
170+
stringToTimeDurationHookFunc,
171+
textUnmarshallerHookFunc,
173172
),
174173
}
175174
}
176175

176+
var (
177+
stringToSliceHookFunc = mapstructure.StringToSliceHookFunc(",")
178+
stringToTimeDurationHookFunc = mapstructure.StringToTimeDurationHookFunc()
179+
textUnmarshallerHookFunc = mapstructure.TextUnmarshallerHookFunc()
180+
181+
componentIDType = reflect.TypeOf(NewComponentID("foo"))
182+
)
183+
177184
// In cases where a config has a mapping of something to a struct pointers
178185
// we want nil values to resolve to a pointer to the zero value of the
179186
// underlying struct just as we want nil values of a mapping of something
@@ -188,78 +195,51 @@ func decoderConfig(result interface{}) *mapstructure.DecoderConfig {
188195
//
189196
// we want an unmarshaled Config to be equivalent to
190197
// Config{Thing: &SomeStruct{}} instead of Config{Thing: nil}
191-
func expandNilStructPointers() mapstructure.DecodeHookFunc {
192-
return func(from reflect.Value, to reflect.Value) (interface{}, error) {
193-
// ensure we are dealing with map to map comparison
194-
if from.Kind() == reflect.Map && to.Kind() == reflect.Map {
195-
toElem := to.Type().Elem()
196-
// ensure that map values are pointers to a struct
197-
// (that may be nil and require manual setting w/ zero value)
198-
if toElem.Kind() == reflect.Ptr && toElem.Elem().Kind() == reflect.Struct {
199-
fromRange := from.MapRange()
200-
for fromRange.Next() {
201-
fromKey := fromRange.Key()
202-
fromValue := fromRange.Value()
203-
// ensure that we've run into a nil pointer instance
204-
if fromValue.IsNil() {
205-
newFromValue := reflect.New(toElem.Elem())
206-
from.SetMapIndex(fromKey, newFromValue)
207-
}
198+
var expandNilStructPointersFunc = func(from reflect.Value, to reflect.Value) (interface{}, error) {
199+
// ensure we are dealing with map to map comparison
200+
if from.Kind() == reflect.Map && to.Kind() == reflect.Map {
201+
toElem := to.Type().Elem()
202+
// ensure that map values are pointers to a struct
203+
// (that may be nil and require manual setting w/ zero value)
204+
if toElem.Kind() == reflect.Ptr && toElem.Elem().Kind() == reflect.Struct {
205+
fromRange := from.MapRange()
206+
for fromRange.Next() {
207+
fromKey := fromRange.Key()
208+
fromValue := fromRange.Value()
209+
// ensure that we've run into a nil pointer instance
210+
if fromValue.IsNil() {
211+
newFromValue := reflect.New(toElem.Elem())
212+
from.SetMapIndex(fromKey, newFromValue)
208213
}
209214
}
210215
}
211-
return from.Interface(), nil
212216
}
217+
return from.Interface(), nil
213218
}
214219

215-
var componentIDType = reflect.TypeOf(NewComponentID("foo"))
216-
217-
// mapStringToMapComponentIDHookFunc returns a DecodeHookFunc that converts a map[string]interface{} to map[ComponentID]{}.
218-
// This is needed in combination with stringToComponentIDHookFunc since the NewComponentIDFromString may produce
219-
// equal IDs for different strings, and an error needs to be returned in that case, otherwise the last equivalent ID
220-
// overwrites the previous one.
221-
func mapStringToMapComponentIDHookFunc() mapstructure.DecodeHookFunc {
222-
return func(
223-
f reflect.Type,
224-
t reflect.Type,
225-
data interface{}) (interface{}, error) {
226-
227-
if f.Kind() != reflect.Map || f.Key().Kind() != reflect.String {
228-
return data, nil
229-
}
230-
231-
if t.Kind() != reflect.Map || t.Key() != componentIDType {
232-
return data, nil
233-
}
220+
// mapStringToMapComponentIDHookFunc returns a DecodeHookFunc that converts a map[string]interface{} to
221+
// map[ComponentID]interface{}.
222+
// This is needed in combination since the ComponentID.UnmarshalText may produce equal IDs for different strings,
223+
// and an error needs to be returned in that case, otherwise the last equivalent ID overwrites the previous one.
224+
var mapStringToMapComponentIDHookFunc = func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
225+
if f.Kind() != reflect.Map || f.Key().Kind() != reflect.String {
226+
return data, nil
227+
}
234228

235-
m := make(map[ComponentID]interface{})
236-
for k, v := range data.(map[string]interface{}) {
237-
id, err := NewComponentIDFromString(k)
238-
if err != nil {
239-
return nil, err
240-
}
241-
if _, ok := m[id]; ok {
242-
return nil, fmt.Errorf("duplicate name %q after trimming spaces %v", k, id)
243-
}
244-
m[id] = v
245-
}
246-
return m, nil
229+
if t.Kind() != reflect.Map || t.Key() != componentIDType {
230+
return data, nil
247231
}
248-
}
249232

250-
// stringToComponentIDHookFunc returns a DecodeHookFunc that converts strings to ComponentID.
251-
// TODO: Consider to implement encoding.TextUnmarshaler interface on the ID. Does it make it non immutable?
252-
func stringToComponentIDHookFunc() mapstructure.DecodeHookFunc {
253-
return func(
254-
f reflect.Type,
255-
t reflect.Type,
256-
data interface{}) (interface{}, error) {
257-
if f.Kind() != reflect.String {
258-
return data, nil
233+
m := make(map[ComponentID]interface{})
234+
for k, v := range data.(map[string]interface{}) {
235+
id, err := NewComponentIDFromString(k)
236+
if err != nil {
237+
return nil, err
259238
}
260-
if t != componentIDType {
261-
return data, nil
239+
if _, ok := m[id]; ok {
240+
return nil, fmt.Errorf("duplicate name %q after trimming spaces %v", k, id)
262241
}
263-
return NewComponentIDFromString(data.(string))
242+
m[id] = v
264243
}
244+
return m, nil
265245
}

config/identifiable.go

+19-15
Original file line numberDiff line numberDiff line change
@@ -54,36 +54,40 @@ func NewComponentIDWithName(typeVal Type, nameVal string) ComponentID {
5454
// the forward slash and "name" are optional.
5555
// The returned ComponentID will be invalid if err is not-nil.
5656
func NewComponentIDFromString(idStr string) (ComponentID, error) {
57-
items := strings.SplitN(idStr, typeAndNameSeparator, 2)
58-
5957
id := ComponentID{}
58+
return id, id.UnmarshalText([]byte(idStr))
59+
}
60+
61+
// Type returns the type of the component.
62+
func (id ComponentID) Type() Type {
63+
return id.typeVal
64+
}
65+
66+
// Name returns the custom name of the component.
67+
func (id ComponentID) Name() string {
68+
return id.nameVal
69+
}
70+
71+
func (id *ComponentID) UnmarshalText(text []byte) error {
72+
idStr := string(text)
73+
items := strings.SplitN(idStr, typeAndNameSeparator, 2)
6074
if len(items) >= 1 {
6175
id.typeVal = Type(strings.TrimSpace(items[0]))
6276
}
6377

6478
if len(items) == 0 || id.typeVal == "" {
65-
return id, errors.New("idStr must have non empty type")
79+
return errors.New("idStr must have non empty type")
6680
}
6781

6882
if len(items) > 1 {
6983
// "name" part is present.
7084
id.nameVal = strings.TrimSpace(items[1])
7185
if id.nameVal == "" {
72-
return id, errors.New("name part must be specified after " + typeAndNameSeparator + " in type/name key")
86+
return errors.New("name part must be specified after " + typeAndNameSeparator + " in type/name key")
7387
}
7488
}
7589

76-
return id, nil
77-
}
78-
79-
// Type returns the type of the component.
80-
func (id ComponentID) Type() Type {
81-
return id.typeVal
82-
}
83-
84-
// Name returns the custom name of the component.
85-
func (id ComponentID) Name() string {
86-
return id.nameVal
90+
return nil
8791
}
8892

8993
// String returns the ComponentID string representation as "type[/name]" format.

0 commit comments

Comments
 (0)