@@ -164,16 +164,23 @@ func decoderConfig(result interface{}) *mapstructure.DecoderConfig {
164
164
TagName : "mapstructure" ,
165
165
WeaklyTypedInput : true ,
166
166
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 ,
173
172
),
174
173
}
175
174
}
176
175
176
+ var (
177
+ stringToSliceHookFunc = mapstructure .StringToSliceHookFunc ("," )
178
+ stringToTimeDurationHookFunc = mapstructure .StringToTimeDurationHookFunc ()
179
+ textUnmarshallerHookFunc = mapstructure .TextUnmarshallerHookFunc ()
180
+
181
+ componentIDType = reflect .TypeOf (NewComponentID ("foo" ))
182
+ )
183
+
177
184
// In cases where a config has a mapping of something to a struct pointers
178
185
// we want nil values to resolve to a pointer to the zero value of the
179
186
// underlying struct just as we want nil values of a mapping of something
@@ -188,78 +195,51 @@ func decoderConfig(result interface{}) *mapstructure.DecoderConfig {
188
195
//
189
196
// we want an unmarshaled Config to be equivalent to
190
197
// 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 )
208
213
}
209
214
}
210
215
}
211
- return from .Interface (), nil
212
216
}
217
+ return from .Interface (), nil
213
218
}
214
219
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
+ }
234
228
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
247
231
}
248
- }
249
232
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
259
238
}
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 )
262
241
}
263
- return NewComponentIDFromString ( data .( string ))
242
+ m [ id ] = v
264
243
}
244
+ return m , nil
265
245
}
0 commit comments