@@ -442,21 +442,26 @@ func (d *Decoder) Decode(input interface{}) error {
442
442
return err
443
443
}
444
444
445
+ // isNil returns true if the input is nil or a typed nil pointer.
446
+ func isNil (input interface {}) bool {
447
+ if input == nil {
448
+ return true
449
+ }
450
+ val := reflect .ValueOf (input )
451
+ return val .Kind () == reflect .Ptr && val .IsNil ()
452
+ }
453
+
445
454
// Decodes an unknown data type into a specific reflection value.
446
455
func (d * Decoder ) decode (name string , input interface {}, outVal reflect.Value ) error {
447
- var inputVal reflect.Value
448
- if input != nil {
449
- inputVal = reflect .ValueOf (input )
450
-
451
- // We need to check here if input is a typed nil. Typed nils won't
452
- // match the "input == nil" below so we check that here.
453
- if inputVal .Kind () == reflect .Ptr && inputVal .IsNil () {
454
- input = nil
455
- }
456
+ var (
457
+ inputVal = reflect .ValueOf (input )
458
+ outputKind = getKind (outVal )
459
+ decodeNil = d .config .DecodeNil && d .cachedDecodeHook != nil
460
+ )
461
+ if isNil (input ) {
462
+ // Typed nils won't match the "input == nil" below, so reset input.
463
+ input = nil
456
464
}
457
-
458
- decodeNil := d .config .DecodeNil && d .config .DecodeHook != nil
459
-
460
465
if input == nil {
461
466
// If the data is nil, then we don't set anything, unless ZeroFields is set
462
467
// to true.
@@ -467,12 +472,10 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
467
472
d .config .Metadata .Keys = append (d .config .Metadata .Keys , name )
468
473
}
469
474
}
470
-
471
475
if ! decodeNil {
472
476
return nil
473
477
}
474
478
}
475
-
476
479
if ! inputVal .IsValid () {
477
480
if ! decodeNil {
478
481
// If the input value is invalid, then we just set the value
@@ -483,11 +486,17 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
483
486
}
484
487
return nil
485
488
}
486
-
487
- // If we get here, we have an untyped nil so the type of the input is assumed.
488
- // We do this because all subsequent code requires a valid value for inputVal.
489
- var mapVal map [string ]interface {}
490
- inputVal = reflect .MakeMap (reflect .TypeOf (mapVal ))
489
+ // Hooks need a valid inputVal, so reset it to zero value of outVal type.
490
+ switch outputKind {
491
+ case reflect .Struct , reflect .Map :
492
+ var mapVal map [string ]interface {}
493
+ inputVal = reflect .ValueOf (mapVal ) // create nil map pointer
494
+ case reflect .Slice , reflect .Array :
495
+ var sliceVal []interface {}
496
+ inputVal = reflect .ValueOf (sliceVal ) // create nil slice pointer
497
+ default :
498
+ inputVal = reflect .Zero (outVal .Type ())
499
+ }
491
500
}
492
501
493
502
if d .cachedDecodeHook != nil {
@@ -498,9 +507,11 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
498
507
return fmt .Errorf ("error decoding '%s': %w" , name , err )
499
508
}
500
509
}
510
+ if isNil (input ) {
511
+ return nil
512
+ }
501
513
502
514
var err error
503
- outputKind := getKind (outVal )
504
515
addMetaKey := true
505
516
switch outputKind {
506
517
case reflect .Bool :
@@ -781,8 +792,8 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e
781
792
}
782
793
default :
783
794
return fmt .Errorf (
784
- "'%s' expected type '%s', got unconvertible type '%s ', value: '%v'" ,
785
- name , val . Type () , dataVal . Type () , data )
795
+ "'%s' expected type '%s', got unconvertible type '%#v ', value: '%# v'" ,
796
+ name , val , dataVal , data )
786
797
}
787
798
788
799
return nil
0 commit comments