@@ -173,9 +173,9 @@ type Options struct {
173
173
func (opts * Options ) getRawEnv (s string ) string {
174
174
val := opts .rawEnvVars [s ]
175
175
if val == "" {
176
- return opts .Environment [s ]
176
+ val = opts .Environment [s ]
177
177
}
178
- return val
178
+ return os . Expand ( val , opts . getRawEnv )
179
179
}
180
180
181
181
func defaultOptions () Options {
@@ -189,32 +189,45 @@ func defaultOptions() Options {
189
189
}
190
190
}
191
191
192
- func customOptions (opt Options ) Options {
193
- defOpts := defaultOptions ()
194
- if opt .TagName == "" {
195
- opt .TagName = defOpts .TagName
196
- }
197
- if opt .PrefixTagName == "" {
198
- opt .PrefixTagName = defOpts .PrefixTagName
199
- }
200
- if opt .DefaultValueTagName == "" {
201
- opt .DefaultValueTagName = defOpts .DefaultValueTagName
202
- }
203
- if opt .Environment == nil {
204
- opt .Environment = defOpts .Environment
205
- }
206
- if opt .FuncMap == nil {
207
- opt .FuncMap = map [reflect.Type ]ParserFunc {}
208
- }
209
- if opt .rawEnvVars == nil {
210
- opt .rawEnvVars = defOpts .rawEnvVars
211
- }
212
- for k , v := range defOpts .FuncMap {
213
- if _ , exists := opt .FuncMap [k ]; ! exists {
214
- opt .FuncMap [k ] = v
192
+ func mergeOptions [T any ](target , source * T ) {
193
+ targetPtr := reflect .ValueOf (target ).Elem ()
194
+ sourcePtr := reflect .ValueOf (source ).Elem ()
195
+
196
+ targetType := targetPtr .Type ()
197
+ for i := 0 ; i < targetPtr .NumField (); i ++ {
198
+ targetField := targetPtr .Field (i )
199
+ sourceField := sourcePtr .FieldByName (targetType .Field (i ).Name )
200
+
201
+ if targetField .CanSet () && ! isZero (sourceField ) {
202
+ switch targetField .Kind () {
203
+ case reflect .Map :
204
+ if ! sourceField .IsZero () {
205
+ iter := sourceField .MapRange ()
206
+ for iter .Next () {
207
+ targetField .SetMapIndex (iter .Key (), iter .Value ())
208
+ }
209
+ }
210
+ default :
211
+ targetField .Set (sourceField )
212
+ }
215
213
}
216
214
}
217
- return opt
215
+ }
216
+
217
+ func isZero (v reflect.Value ) bool {
218
+ switch v .Kind () {
219
+ case reflect .Func , reflect .Map , reflect .Slice :
220
+ return v .IsNil ()
221
+ default :
222
+ zero := reflect .Zero (v .Type ())
223
+ return v .Interface () == zero .Interface ()
224
+ }
225
+ }
226
+
227
+ func customOptions (opts Options ) Options {
228
+ defOpts := defaultOptions ()
229
+ mergeOptions (& defOpts , & opts )
230
+ return defOpts
218
231
}
219
232
220
233
func optionsWithSliceEnvPrefix (opts Options , index int ) Options {
@@ -386,43 +399,30 @@ func doParseField(
386
399
return doParse (refField , processField , optionsWithEnvPrefix (refTypeField , opts ))
387
400
}
388
401
389
- if isSliceOfStructs (refTypeField , opts ) {
402
+ if isSliceOfStructs (refTypeField ) {
390
403
return doParseSlice (refField , processField , optionsWithEnvPrefix (refTypeField , opts ))
391
404
}
392
405
393
406
return nil
394
407
}
395
408
396
- func isSliceOfStructs (refTypeField reflect.StructField , opts Options ) bool {
409
+ func isSliceOfStructs (refTypeField reflect.StructField ) bool {
397
410
field := refTypeField .Type
398
- if field .Kind () == reflect .Ptr {
399
- field = field .Elem ()
400
- }
401
-
402
- if field .Kind () != reflect .Slice {
403
- return false
404
- }
405
-
406
- field = field .Elem ()
407
411
412
+ // *[]struct
408
413
if field .Kind () == reflect .Ptr {
409
414
field = field .Elem ()
415
+ if field .Kind () == reflect .Slice && field .Elem ().Kind () == reflect .Struct {
416
+ return true
417
+ }
410
418
}
411
419
412
- _ , ignore := defaultBuiltInParsers [field .Kind ()]
413
-
414
- if ! ignore {
415
- _ , ignore = opts .FuncMap [field ]
416
- }
417
-
418
- if ! ignore {
419
- _ , ignore = reflect .New (field ).Interface ().(encoding.TextUnmarshaler )
420
+ // []struct{}
421
+ if field .Kind () == reflect .Slice && field .Elem ().Kind () == reflect .Struct {
422
+ return true
420
423
}
421
424
422
- if ! ignore {
423
- ignore = field .Kind () != reflect .Struct
424
- }
425
- return ! ignore
425
+ return false
426
426
}
427
427
428
428
func doParseSlice (ref reflect.Value , processField processFieldFn , opts Options ) error {
0 commit comments