@ -100,6 +100,47 @@
// "address": "123 Maple St.",
// }
//
// Omit Empty Values
//
// When decoding from a struct to any other value, you may use the
// ",omitempty" suffix on your tag to omit that value if it equates to
// the zero value. The zero value of all types is specified in the Go
// specification.
//
// For example, the zero type of a numeric type is zero ("0"). If the struct
// field value is zero and a numeric type, the field is empty, and it won't
// be encoded into the destination type.
//
// type Source {
// Age int `mapstructure:",omitempty"`
// }
//
// Unexported fields
//
// Since unexported (private) struct fields cannot be set outside the package
// where they are defined, the decoder will simply skip them.
//
// For this output type definition:
//
// type Exported struct {
// private string // this unexported field will be skipped
// Public string
// }
//
// Using this map as input:
//
// map[string]interface{}{
// "private": "I will be ignored",
// "Public": "I made it through!",
// }
//
// The following struct will be decoded:
//
// type Exported struct {
// private: "" // field is left with an empty string (zero value)
// Public: "I made it through!"
// }
//
// Other Configuration
//
// mapstructure is highly configurable. See the DecoderConfig struct
@ -378,6 +419,7 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
var err error
outputKind := getKind ( outVal )
addMetaKey := true
switch outputKind {
case reflect . Bool :
err = d . decodeBool ( name , input , outVal )
@ -396,7 +438,7 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
case reflect . Map :
err = d . decodeMap ( name , input , outVal )
case reflect . Ptr :
err = d . decodePtr ( name , input , outVal )
addMetaKey , err = d . decodePtr ( name , input , outVal )
case reflect . Slice :
err = d . decodeSlice ( name , input , outVal )
case reflect . Array :
@ -410,7 +452,7 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
// If we reached here, then we successfully decoded SOMETHING, so
// mark the key as used if we're tracking metainput.
if d . config . Metadata != nil && name != "" {
if addMetaKey && d . config . Metadata != nil && name != "" {
d . config . Metadata . Keys = append ( d . config . Metadata . Keys , name )
}
@ -421,7 +463,34 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
// value to "data" of that type.
func ( d * Decoder ) decodeBasic ( name string , data interface { } , val reflect . Value ) error {
if val . IsValid ( ) && val . Elem ( ) . IsValid ( ) {
return d . decode ( name , data , val . Elem ( ) )
elem := val . Elem ( )
// If we can't address this element, then its not writable. Instead,
// we make a copy of the value (which is a pointer and therefore
// writable), decode into that, and replace the whole value.
copied := false
if ! elem . CanAddr ( ) {
copied = true
// Make *T
copy := reflect . New ( elem . Type ( ) )
// *T = elem
copy . Elem ( ) . Set ( elem )
// Set elem so we decode into it
elem = copy
}
// Decode. If we have an error then return. We also return right
// away if we're not a copy because that means we decoded directly.
if err := d . decode ( name , data , elem ) ; err != nil || ! copied {
return err
}
// If we're a copy, we need to set te final result
val . Set ( elem . Elem ( ) )
return nil
}
dataVal := reflect . ValueOf ( data )
@ -798,30 +867,31 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
}
tagValue := f . Tag . Get ( d . config . TagName )
tagParts := strings . Split ( tagValue , "," )
keyName := f . Name
// If Squash is set in the config, we squash the field down.
squash := d . config . Squash && v . Kind ( ) == reflect . Struct && f . Anonymous
// Determine the name of the key in the map
keyName := f . Name
if tagParts [ 0 ] != "" {
if tagParts [ 0 ] == "-" {
if index := strings . Index ( tagValue , "," ) ; index != - 1 {
if tagValue [ : index ] == "-" {
continue
}
keyName = tagParts [ 0 ]
}
// If Squash is set in the config, we squash the field down.
squash := d . config . Squash && v . Kind ( ) == reflect . Struct
// If "squash" is specified in the tag, we squash the field down.
if ! squash {
for _ , tag := range tagParts [ 1 : ] {
if tag == "squash" {
squash = true
break
}
// If "omitempty" is specified in the tag, it ignores empty values.
if strings . Index ( tagValue [ index + 1 : ] , "omitempty" ) != - 1 && isEmptyValue ( v ) {
continue
}
// If "squash" is specified in the tag, we squash the field down.
squash = ! squash && strings . Index ( tagValue [ index + 1 : ] , "squash" ) != - 1
if squash && v . Kind ( ) != reflect . Struct {
return fmt . Errorf ( "cannot squash non-struct type '%s'" , v . Type ( ) )
}
keyName = tagValue [ : index ]
} else if len ( tagValue ) > 0 {
if tagValue == "-" {
continue
}
keyName = tagValue
}
switch v . Kind ( ) {
@ -836,11 +906,22 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
mType := reflect . MapOf ( vKeyType , vElemType )
vMap := reflect . MakeMap ( mType )
err := d . decode ( keyName , x . Interface ( ) , vMap )
// Creating a pointer to a map so that other methods can completely
// overwrite the map if need be (looking at you decodeMapFromMap). The
// indirection allows the underlying map to be settable (CanSet() == true)
// where as reflect.MakeMap returns an unsettable map.
addrVal := reflect . New ( vMap . Type ( ) )
reflect . Indirect ( addrVal ) . Set ( vMap )
err := d . decode ( keyName , x . Interface ( ) , reflect . Indirect ( addrVal ) )
if err != nil {
return err
}
// the underlying map may have been completely overwritten so pull
// it indirectly out of the enclosing value.
vMap = reflect . Indirect ( addrVal )
if squash {
for _ , k := range vMap . MapKeys ( ) {
valMap . SetMapIndex ( k , vMap . MapIndex ( k ) )
@ -861,7 +942,7 @@ func (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val re
return nil
}
func ( d * Decoder ) decodePtr ( name string , data interface { } , val reflect . Value ) error {
func ( d * Decoder ) decodePtr ( name string , data interface { } , val reflect . Value ) ( bool , error ) {
// If the input data is nil, then we want to just set the output
// pointer to be nil as well.
isNil := data == nil
@ -882,7 +963,7 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er
val . Set ( nilValue )
}
return nil
return true , nil
}
// Create an element of the concrete (non pointer) type and decode
@ -896,16 +977,16 @@ func (d *Decoder) decodePtr(name string, data interface{}, val reflect.Value) er
}
if err := d . decode ( name , data , reflect . Indirect ( realVal ) ) ; err != nil {
return err
return false , err
}
val . Set ( realVal )
} else {
if err := d . decode ( name , data , reflect . Indirect ( val ) ) ; err != nil {
return err
return false , err
}
}
return nil
return false , nil
}
func ( d * Decoder ) decodeFunc ( name string , data interface { } , val reflect . Value ) error {
@ -1084,13 +1165,23 @@ func (d *Decoder) decodeStruct(name string, data interface{}, val reflect.Value)
// Not the most efficient way to do this but we can optimize later if
// we want to. To convert from struct to struct we go to map first
// as an intermediary.
m := make ( map [ string ] interface { } )
mval := reflect . Indirect ( reflect . ValueOf ( & m ) )
if err := d . decodeMapFromStruct ( name , dataVal , mval , mval ) ; err != nil {
// Make a new map to hold our result
mapType := reflect . TypeOf ( ( map [ string ] interface { } ) ( nil ) )
mval := reflect . MakeMap ( mapType )
// Creating a pointer to a map so that other methods can completely
// overwrite the map if need be (looking at you decodeMapFromMap). The
// indirection allows the underlying map to be settable (CanSet() == true)
// where as reflect.MakeMap returns an unsettable map.
addrVal := reflect . New ( mval . Type ( ) )
reflect . Indirect ( addrVal ) . Set ( mval )
if err := d . decodeMapFromStruct ( name , dataVal , reflect . Indirect ( addrVal ) , mval ) ; err != nil {
return err
}
result := d . decodeStructFromMap ( name , mval , val )
result := d . decodeStructFromMap ( name , reflect . Indirect ( addrVal ) , val )
return result
default :
@ -1144,7 +1235,7 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
fieldKind := fieldType . Type . Kind ( )
// If "squash" is specified in the tag, we squash the field down.
squash := d . config . Squash && fieldKind == reflect . Struct
squash := d . config . Squash && fieldKind == reflect . Struct && fieldType . Anonymous
remain := false
// We always parse the tags cause we're looking for other tags too
@ -1172,9 +1263,8 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
}
// Build our field
fieldCurrent := field { fieldType , structVal . Field ( i ) }
if remain {
remainField = & fieldCurrent
remainField = & field { fieldType , structVal . Field ( i ) }
} else {
// Normal struct field, store it away
fields = append ( fields , field { fieldType , structVal . Field ( i ) } )
@ -1293,6 +1383,24 @@ func (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) e
return nil
}
func isEmptyValue ( v reflect . Value ) bool {
switch getKind ( v ) {
case reflect . Array , reflect . Map , reflect . Slice , reflect . String :
return v . Len ( ) == 0
case reflect . Bool :
return ! v . Bool ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return v . Int ( ) == 0
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return v . Uint ( ) == 0
case reflect . Float32 , reflect . Float64 :
return v . Float ( ) == 0
case reflect . Interface , reflect . Ptr :
return v . IsNil ( )
}
return false
}
func getKind ( val reflect . Value ) reflect . Kind {
kind := val . Kind ( )