@@ -281,6 +281,13 @@ type DecoderConfig struct {
281281 // }
282282 Squash bool
283283
284+ // Deep will map structures in slices instead of copying them
285+ //
286+ // type Parent struct {
287+ // Children []Child `mapstructure:",deep"`
288+ // }
289+ Deep bool
290+
284291 // Metadata is the struct that will contain extra metadata about
285292 // the decoding. If this is nil, then no metadata will be tracked.
286293 Metadata * Metadata
@@ -1070,6 +1077,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
10701077 // If Squash is set in the config, we squash the field down.
10711078 squash := d .config .Squash && v .Kind () == reflect .Struct && f .Anonymous
10721079
1080+ // If Deep is set in the config, set as default value.
1081+ deep := d .config .Deep
1082+
10731083 v = dereferencePtrToStructIfNeeded (v , d .config .TagName )
10741084
10751085 // Determine the name of the key in the map
@@ -1118,6 +1128,9 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
11181128 continue
11191129 }
11201130 }
1131+
1132+ deep = deep || strings .Index (tagValue [index + 1 :], "deep" ) != - 1
1133+
11211134 if keyNameTagValue := tagValue [:index ]; keyNameTagValue != "" {
11221135 keyName = keyNameTagValue
11231136 }
@@ -1164,6 +1177,41 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
11641177 valMap .SetMapIndex (reflect .ValueOf (keyName ), vMap )
11651178 }
11661179
1180+ case reflect .Slice :
1181+ if deep {
1182+ var childType reflect.Type
1183+ switch v .Type ().Elem ().Kind () {
1184+ case reflect .Struct :
1185+ childType = reflect .TypeOf (map [string ]interface {}{})
1186+ default :
1187+ childType = v .Type ().Elem ()
1188+ }
1189+
1190+ sType := reflect .SliceOf (childType )
1191+
1192+ addrVal := reflect .New (sType )
1193+
1194+ vSlice := reflect .MakeSlice (sType , v .Len (), v .Cap ())
1195+
1196+ if v .Len () > 0 {
1197+ reflect .Indirect (addrVal ).Set (vSlice )
1198+
1199+ err := d .decode (keyName , v .Interface (), reflect .Indirect (addrVal ))
1200+ if err != nil {
1201+ return err
1202+ }
1203+ }
1204+
1205+ vSlice = reflect .Indirect (addrVal )
1206+
1207+ valMap .SetMapIndex (reflect .ValueOf (keyName ), vSlice )
1208+
1209+ break
1210+ }
1211+
1212+ // When deep mapping is not needed, fallthrough to normal copy
1213+ fallthrough
1214+
11671215 default :
11681216 valMap .SetMapIndex (reflect .ValueOf (keyName ), v )
11691217 }
@@ -1718,13 +1766,24 @@ func isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool,
17181766}
17191767
17201768func dereferencePtrToStructIfNeeded (v reflect.Value , tagName string ) reflect.Value {
1721- if v .Kind () != reflect .Ptr || v .Elem ().Kind () != reflect .Struct {
1769+
1770+ if v .Kind () != reflect .Ptr {
17221771 return v
17231772 }
1724- deref := v .Elem ()
1725- derefT := deref .Type ()
1726- if isStructTypeConvertibleToMap (derefT , true , tagName ) {
1727- return deref
1773+
1774+ switch v .Elem ().Kind () {
1775+ case reflect .Slice :
1776+ return v .Elem ()
1777+
1778+ case reflect .Struct :
1779+ deref := v .Elem ()
1780+ derefT := deref .Type ()
1781+ if isStructTypeConvertibleToMap (derefT , true , tagName ) {
1782+ return deref
1783+ }
1784+ return v
1785+
1786+ default :
1787+ return v
17281788 }
1729- return v
17301789}
0 commit comments