// Package mapstructure exposes functionality to convert one arbitrary // Go type into another, typically to convert a map[string]any // into a native Go structure. // // The Go structure can be arbitrarily complex, containing slices, // other structs, etc. and the decoder will properly decode nested // maps and so on into the proper structures in the native Go struct. // See the examples to see what the decoder is capable of. // // The simplest function to start with is Decode. // // # Field Tags // // When decoding to a struct, mapstructure will use the field name by // default to perform the mapping. For example, if a struct has a field // "Username" then mapstructure will look for a key in the source value // of "username" (case insensitive). // // type User struct { // Username string // } // // You can change the behavior of mapstructure by using struct tags. // The default struct tag that mapstructure looks for is "mapstructure" // but you can customize it using DecoderConfig. // // # Renaming Fields // // To rename the key that mapstructure looks for, use the "mapstructure" // tag and set a value directly. For example, to change the "username" example // above to "user": // // type User struct { // Username string `mapstructure:"user"` // } // // # Embedded Structs and Squashing // // Embedded structs are treated as if they're another field with that name. // By default, the two structs below are equivalent when decoding with // mapstructure: // // type Person struct { // Name string // } // // type Friend struct { // Person // } // // type Friend struct { // Person Person // } // // This would require an input that looks like below: // // map[string]any{ // "person": map[string]any{"name": "alice"}, // } // // If your "person" value is NOT nested, then you can append ",squash" to // your tag value and mapstructure will treat it as if the embedded struct // were part of the struct directly. Example: // // type Friend struct { // Person `mapstructure:",squash"` // } // // Now the following input would be accepted: // // map[string]any{ // "name": "alice", // } // // When decoding from a struct to a map, the squash tag squashes the struct // fields into a single map. Using the example structs from above: // // Friend{Person: Person{Name: "alice"}} // // Will be decoded into a map: // // map[string]any{ // "name": "alice", // } // // DecoderConfig has a field that changes the behavior of mapstructure // to always squash embedded structs. // // # Remainder Values // // If there are any unmapped keys in the source value, mapstructure by // default will silently ignore them. You can error by setting ErrorUnused // in DecoderConfig. If you're using Metadata you can also maintain a slice // of the unused keys. // // You can also use the ",remain" suffix on your tag to collect all unused // values in a map. The field with this tag MUST be a map type and should // probably be a "map[string]any" or "map[any]any". // See example below: // // type Friend struct { // Name string // Other map[string]any `mapstructure:",remain"` // } // // Given the input below, Other would be populated with the other // values that weren't used (everything but "name"): // // map[string]any{ // "name": "bob", // "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, or a zero-length element. 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. And likewise for the URLs field, if the // slice is nil or empty, it won't be encoded into the destination type. // // type Source struct { // Age int `mapstructure:",omitempty"` // URLs []string `mapstructure:",omitempty"` // } // // # Omit Zero Values // // When decoding from a struct to any other value, you may use the // ",omitzero" 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. And likewise for the URLs field, if the // slice is nil, it won't be encoded into the destination type. // // Note that if the field is a slice, and it is empty but not nil, it will // still be encoded into the destination type. // // type Source struct { // Age int `mapstructure:",omitzero"` // URLs []string `mapstructure:",omitzero"` // } // // # 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]any{ // "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 // for other features and options that are supported.
package mapstructure import ( ) // DecodeHookFunc is the callback function that can be used for // data transformations. See "DecodeHook" in the DecoderConfig // struct. // // The type must be one of DecodeHookFuncType, DecodeHookFuncKind, or // DecodeHookFuncValue. // Values are a superset of Types (Values can return types), and Types are a // superset of Kinds (Types can return Kinds) and are generally a richer thing // to use, but Kinds are simpler if you only need those. // // The reason DecodeHookFunc is multi-typed is for backwards compatibility: // we started with Kinds and then realized Types were the better solution, // but have a promise to not break backwards compat so we now support // both. type DecodeHookFunc any // DecodeHookFuncType is a DecodeHookFunc which has complete information about // the source and target types. type DecodeHookFuncType func(reflect.Type, reflect.Type, any) (any, error) // DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the // source and target types. type DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error) // DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target // values. type DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error) // DecoderConfig is the configuration that is used to create a new decoder // and allows customization of various aspects of decoding. type DecoderConfig struct { // DecodeHook, if set, will be called before any decoding and any // type conversion (if WeaklyTypedInput is on). This lets you modify // the values before they're set down onto the resulting struct. The // DecodeHook is called for every map and value in the input. This means // that if a struct has embedded fields with squash tags the decode hook // is called only once with all of the input data, not once for each // embedded struct. // // If an error is returned, the entire decode will fail with that error. DecodeHook DecodeHookFunc // If ErrorUnused is true, then it is an error for there to exist // keys in the original map that were unused in the decoding process // (extra keys). ErrorUnused bool // If ErrorUnset is true, then it is an error for there to exist // fields in the result that were not set in the decoding process // (extra fields). This only applies to decoding to a struct. This // will affect all nested structs as well. ErrorUnset bool // AllowUnsetPointer, if set to true, will prevent fields with pointer types // from being reported as unset, even if ErrorUnset is true and the field was // not present in the input data. This allows pointer fields to be optional // without triggering an error when they are missing. AllowUnsetPointer bool // ZeroFields, if set to true, will zero fields before writing them. // For example, a map will be emptied before decoded values are put in // it. If this is false, a map will be merged. ZeroFields bool // If WeaklyTypedInput is true, the decoder will make the following // "weak" conversions: // // - bools to string (true = "1", false = "0") // - numbers to string (base 10) // - bools to int/uint (true = 1, false = 0) // - strings to int/uint (base implied by prefix) // - int to bool (true if value != 0) // - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F, // FALSE, false, False. Anything else is an error) // - empty array = empty map and vice versa // - negative numbers to overflowed uint values (base 10) // - slice of maps to a merged map // - single values are converted to slices if required. Each // element is weakly decoded. For example: "4" can become []int{4} // if the target type is an int slice. // WeaklyTypedInput bool // Squash will squash embedded structs. A squash tag may also be // added to an individual struct field using a tag. For example: // // type Parent struct { // Child `mapstructure:",squash"` // } Squash bool // Metadata is the struct that will contain extra metadata about // the decoding. If this is nil, then no metadata will be tracked. Metadata *Metadata // Result is a pointer to the struct that will contain the decoded // value. Result any // The tag name that mapstructure reads for field names. This // defaults to "mapstructure" TagName string // The option of the value in the tag that indicates a field should // be squashed. This defaults to "squash". SquashTagOption string // IgnoreUntaggedFields ignores all struct fields without explicit // TagName, comparable to `mapstructure:"-"` as default behaviour. IgnoreUntaggedFields bool // MatchName is the function used to match the map key to the struct // field name or tag. Defaults to `strings.EqualFold`. This can be used // to implement case-sensitive tag values, support snake casing, etc. MatchName func(mapKey, fieldName string) bool // DecodeNil, if set to true, will cause the DecodeHook (if present) to run // even if the input is nil. This can be used to provide default values. DecodeNil bool } // A Decoder takes a raw interface value and turns it into structured // data, keeping track of rich error information along the way in case // anything goes wrong. Unlike the basic top-level Decode method, you can // more finely control how the Decoder behaves using the DecoderConfig // structure. The top-level Decode method is just a convenience that sets // up the most basic Decoder. type Decoder struct { config *DecoderConfig cachedDecodeHook func(from reflect.Value, to reflect.Value) (any, error) } // Metadata contains information about decoding a structure that // is tedious or difficult to get otherwise. type Metadata struct { // Keys are the keys of the structure which were successfully decoded Keys []string // Unused is a slice of keys that were found in the raw value but // weren't decoded since there was no matching field in the result interface Unused []string // Unset is a slice of field names that were found in the result interface // but weren't set in the decoding process since there was no matching value // in the input Unset []string } // Decode takes an input structure and uses reflection to translate it to // the output structure. output must be a pointer to a map or struct. func ( any, any) error { := &DecoderConfig{ Metadata: nil, Result: , } , := NewDecoder() if != nil { return } return .Decode() } // WeakDecode is the same as Decode but is shorthand to enable // WeaklyTypedInput. See DecoderConfig for more info. func (, any) error { := &DecoderConfig{ Metadata: nil, Result: , WeaklyTypedInput: true, } , := NewDecoder() if != nil { return } return .Decode() } // DecodeMetadata is the same as Decode, but is shorthand to // enable metadata collection. See DecoderConfig for more info. func ( any, any, *Metadata) error { := &DecoderConfig{ Metadata: , Result: , } , := NewDecoder() if != nil { return } return .Decode() } // WeakDecodeMetadata is the same as Decode, but is shorthand to // enable both WeaklyTypedInput and metadata collection. See // DecoderConfig for more info. func ( any, any, *Metadata) error { := &DecoderConfig{ Metadata: , Result: , WeaklyTypedInput: true, } , := NewDecoder() if != nil { return } return .Decode() } // NewDecoder returns a new decoder for the given configuration. Once // a decoder has been returned, the same configuration must not be used // again. func ( *DecoderConfig) (*Decoder, error) { := reflect.ValueOf(.Result) if .Kind() != reflect.Ptr { return nil, errors.New("result must be a pointer") } = .Elem() if !.CanAddr() { return nil, errors.New("result must be addressable (a pointer)") } if .Metadata != nil { if .Metadata.Keys == nil { .Metadata.Keys = make([]string, 0) } if .Metadata.Unused == nil { .Metadata.Unused = make([]string, 0) } if .Metadata.Unset == nil { .Metadata.Unset = make([]string, 0) } } if .TagName == "" { .TagName = "mapstructure" } if .SquashTagOption == "" { .SquashTagOption = "squash" } if .MatchName == nil { .MatchName = strings.EqualFold } := &Decoder{ config: , } if .DecodeHook != nil { .cachedDecodeHook = cachedDecodeHook(.DecodeHook) } return , nil } // Decode decodes the given raw interface to the target pointer specified // by the configuration. func ( *Decoder) ( any) error { := .decode("", , reflect.ValueOf(.config.Result).Elem()) // Retain some of the original behavior when multiple errors ocurr var interface{ () []error } if errors.As(, &) { return fmt.Errorf("decoding failed due to the following error(s):\n\n%w", ) } return } // isNil returns true if the input is nil or a typed nil pointer. func isNil( any) bool { if == nil { return true } := reflect.ValueOf() return .Kind() == reflect.Ptr && .IsNil() } // Decodes an unknown data type into a specific reflection value. func ( *Decoder) ( string, any, reflect.Value) error { var ( = reflect.ValueOf() = getKind() = .config.DecodeNil && .cachedDecodeHook != nil ) if isNil() { // Typed nils won't match the "input == nil" below, so reset input. = nil } if == nil { // If the data is nil, then we don't set anything, unless ZeroFields is set // to true. if .config.ZeroFields { .Set(reflect.Zero(.Type())) if .config.Metadata != nil && != "" { .config.Metadata.Keys = append(.config.Metadata.Keys, ) } } if ! { return nil } } if !.IsValid() { if ! { // If the input value is invalid, then we just set the value // to be the zero value. .Set(reflect.Zero(.Type())) if .config.Metadata != nil && != "" { .config.Metadata.Keys = append(.config.Metadata.Keys, ) } return nil } // Hooks need a valid inputVal, so reset it to zero value of outVal type. switch { case reflect.Struct, reflect.Map: var map[string]any = reflect.ValueOf() // create nil map pointer case reflect.Slice, reflect.Array: var []any = reflect.ValueOf() // create nil slice pointer default: = reflect.Zero(.Type()) } } if .cachedDecodeHook != nil { // We have a DecodeHook, so let's pre-process the input. var error , = .cachedDecodeHook(, ) if != nil { return newDecodeError(, ) } } if isNil() { return nil } var error := true switch { case reflect.Bool: = .decodeBool(, , ) case reflect.Interface: = .decodeBasic(, , ) case reflect.String: = .decodeString(, , ) case reflect.Int: = .decodeInt(, , ) case reflect.Uint: = .decodeUint(, , ) case reflect.Float32: = .decodeFloat(, , ) case reflect.Complex64: = .decodeComplex(, , ) case reflect.Struct: = .decodeStruct(, , ) case reflect.Map: = .decodeMap(, , ) case reflect.Ptr: , = .decodePtr(, , ) case reflect.Slice: = .decodeSlice(, , ) case reflect.Array: = .decodeArray(, , ) case reflect.Func: = .decodeFunc(, , ) default: // If we reached this point then we weren't able to decode it return newDecodeError(, fmt.Errorf("unsupported type: %s", )) } // If we reached here, then we successfully decoded SOMETHING, so // mark the key as used if we're tracking metainput. if && .config.Metadata != nil && != "" { .config.Metadata.Keys = append(.config.Metadata.Keys, ) } return } // This decodes a basic type (bool, int, string, etc.) and sets the // value to "data" of that type. func ( *Decoder) ( string, any, reflect.Value) error { if .IsValid() && .Elem().IsValid() { := .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. := false if !.CanAddr() { = true // Make *T := reflect.New(.Type()) // *T = elem .Elem().Set() // Set elem so we decode into it = } // 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 := .decode(, , ); != nil || ! { return } // If we're a copy, we need to set te final result .Set(.Elem()) return nil } := reflect.ValueOf() // If the input data is a pointer, and the assigned type is the dereference // of that exact pointer, then indirect it so that we can assign it. // Example: *string to string if .Kind() == reflect.Ptr && .Type().Elem() == .Type() { = reflect.Indirect() } if !.IsValid() { = reflect.Zero(.Type()) } := .Type() if !.AssignableTo(.Type()) { return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } .Set() return nil } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := getKind() := true switch { case == reflect.String: .SetString(.String()) case == reflect.Bool && .config.WeaklyTypedInput: if .Bool() { .SetString("1") } else { .SetString("0") } case == reflect.Int && .config.WeaklyTypedInput: .SetString(strconv.FormatInt(.Int(), 10)) case == reflect.Uint && .config.WeaklyTypedInput: .SetString(strconv.FormatUint(.Uint(), 10)) case == reflect.Float32 && .config.WeaklyTypedInput: .SetString(strconv.FormatFloat(.Float(), 'f', -1, 64)) case == reflect.Slice && .config.WeaklyTypedInput, == reflect.Array && .config.WeaklyTypedInput: := .Type() := .Elem().Kind() switch { case reflect.Uint8: var []uint8 if == reflect.Array { = make([]uint8, .Len(), .Len()) for := range { [] = .Index().Interface().(uint8) } } else { = .Interface().([]uint8) } .SetString(string()) default: = false } default: = false } if ! { return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } return nil } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := getKind() := .Type() switch { case == reflect.Int: .SetInt(.Int()) case == reflect.Uint: .SetInt(int64(.Uint())) case == reflect.Float32: .SetInt(int64(.Float())) case == reflect.Bool && .config.WeaklyTypedInput: if .Bool() { .SetInt(1) } else { .SetInt(0) } case == reflect.String && .config.WeaklyTypedInput: := .String() if == "" { = "0" } , := strconv.ParseInt(, 0, .Type().Bits()) if == nil { .SetInt() } else { return newDecodeError(, &ParseError{ Expected: , Value: , Err: wrapStrconvNumError(), }) } case .PkgPath() == "encoding/json" && .Name() == "Number": := .(json.Number) , := .Int64() if != nil { return newDecodeError(, &ParseError{ Expected: , Value: , Err: , }) } .SetInt() default: return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } return nil } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := getKind() := .Type() switch { case == reflect.Int: := .Int() if < 0 && !.config.WeaklyTypedInput { return newDecodeError(, &ParseError{ Expected: , Value: , Err: fmt.Errorf("%d overflows uint", ), }) } .SetUint(uint64()) case == reflect.Uint: .SetUint(.Uint()) case == reflect.Float32: := .Float() if < 0 && !.config.WeaklyTypedInput { return newDecodeError(, &ParseError{ Expected: , Value: , Err: fmt.Errorf("%f overflows uint", ), }) } .SetUint(uint64()) case == reflect.Bool && .config.WeaklyTypedInput: if .Bool() { .SetUint(1) } else { .SetUint(0) } case == reflect.String && .config.WeaklyTypedInput: := .String() if == "" { = "0" } , := strconv.ParseUint(, 0, .Type().Bits()) if == nil { .SetUint() } else { return newDecodeError(, &ParseError{ Expected: , Value: , Err: wrapStrconvNumError(), }) } case .PkgPath() == "encoding/json" && .Name() == "Number": := .(json.Number) , := strconv.ParseUint(string(), 0, 64) if != nil { return newDecodeError(, &ParseError{ Expected: , Value: , Err: wrapStrconvNumError(), }) } .SetUint() default: return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } return nil } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := getKind() switch { case == reflect.Bool: .SetBool(.Bool()) case == reflect.Int && .config.WeaklyTypedInput: .SetBool(.Int() != 0) case == reflect.Uint && .config.WeaklyTypedInput: .SetBool(.Uint() != 0) case == reflect.Float32 && .config.WeaklyTypedInput: .SetBool(.Float() != 0) case == reflect.String && .config.WeaklyTypedInput: , := strconv.ParseBool(.String()) if == nil { .SetBool() } else if .String() == "" { .SetBool(false) } else { return newDecodeError(, &ParseError{ Expected: , Value: , Err: wrapStrconvNumError(), }) } default: return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } return nil } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := getKind() := .Type() switch { case == reflect.Int: .SetFloat(float64(.Int())) case == reflect.Uint: .SetFloat(float64(.Uint())) case == reflect.Float32: .SetFloat(.Float()) case == reflect.Bool && .config.WeaklyTypedInput: if .Bool() { .SetFloat(1) } else { .SetFloat(0) } case == reflect.String && .config.WeaklyTypedInput: := .String() if == "" { = "0" } , := strconv.ParseFloat(, .Type().Bits()) if == nil { .SetFloat() } else { return newDecodeError(, &ParseError{ Expected: , Value: , Err: wrapStrconvNumError(), }) } case .PkgPath() == "encoding/json" && .Name() == "Number": := .(json.Number) , := .Float64() if != nil { return newDecodeError(, &ParseError{ Expected: , Value: , Err: , }) } .SetFloat() default: return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } return nil } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := getKind() switch { case == reflect.Complex64: .SetComplex(.Complex()) default: return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } return nil } func ( *Decoder) ( string, any, reflect.Value) error { := .Type() := .Key() := .Elem() // By default we overwrite keys in the current map := // If the map is nil or we're purposely zeroing fields, make a new map if .IsNil() || .config.ZeroFields { // Make a new map to hold our result := reflect.MapOf(, ) = reflect.MakeMap() } := reflect.ValueOf() // Resolve any levels of indirection for .Kind() == reflect.Pointer { = reflect.Indirect() } // Check input type and based on the input type jump to the proper func switch .Kind() { case reflect.Map: return .decodeMapFromMap(, , , ) case reflect.Struct: return .decodeMapFromStruct(, , , ) case reflect.Array, reflect.Slice: if .config.WeaklyTypedInput { return .decodeMapFromSlice(, , , ) } fallthrough default: return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } } func ( *Decoder) ( string, reflect.Value, reflect.Value, reflect.Value) error { // Special case for BC reasons (covered by tests) if .Len() == 0 { .Set() return nil } for := 0; < .Len(); ++ { := .decode( +"["+strconv.Itoa()+"]", .Index().Interface(), ) if != nil { return } } return nil } func ( *Decoder) ( string, reflect.Value, reflect.Value, reflect.Value) error { := .Type() := .Key() := .Elem() // Accumulate errors var []error // If the input data is empty, then we just match what the input data is. if .Len() == 0 { if .IsNil() { if !.IsNil() { .Set() } } else { // Set to empty allocated value .Set() } return nil } for , := range .MapKeys() { := + "[" + .String() + "]" // First decode the key into the proper type := reflect.Indirect(reflect.New()) if := .decode(, .Interface(), ); != nil { = append(, ) continue } // Next decode the data into the proper type := .MapIndex().Interface() := reflect.Indirect(reflect.New()) if := .decode(, , ); != nil { = append(, ) continue } .SetMapIndex(, ) } // Set the built up map to the value .Set() return errors.Join(...) } func ( *Decoder) ( string, reflect.Value, reflect.Value, reflect.Value) error { := .Type() for := 0; < .NumField(); ++ { // Get the StructField first since this is a cheap operation. If the // field is unexported, then ignore it. := .Field() if .PkgPath != "" { continue } // Next get the actual value of this field and verify it is assignable // to the map value. := .Field() if !.Type().AssignableTo(.Type().Elem()) { return newDecodeError( +"."+.Name, fmt.Errorf("cannot assign type %q to map value field of type %q", .Type(), .Type().Elem()), ) } := .Tag.Get(.config.TagName) := .Name if == "" && .config.IgnoreUntaggedFields { continue } // If Squash is set in the config, we squash the field down. := .config.Squash && .Kind() == reflect.Struct && .Anonymous = dereferencePtrToStructIfNeeded(, .config.TagName) // Determine the name of the key in the map if := strings.Index(, ","); != -1 { if [:] == "-" { continue } // If "omitempty" is specified in the tag, it ignores empty values. if strings.Index([+1:], "omitempty") != -1 && isEmptyValue() { continue } // If "omitzero" is specified in the tag, it ignores zero values. if strings.Index([+1:], "omitzero") != -1 && .IsZero() { continue } // If "squash" is specified in the tag, we squash the field down. = || strings.Contains([+1:], .config.SquashTagOption) if { // When squashing, the embedded type can be a pointer to a struct. if .Kind() == reflect.Ptr && .Elem().Kind() == reflect.Struct { = .Elem() } // The final type must be a struct if .Kind() != reflect.Struct { return newDecodeError( +"."+.Name, fmt.Errorf("cannot squash non-struct type %q", .Type()), ) } } else { if strings.Index([+1:], "remain") != -1 { if .Kind() != reflect.Map { return newDecodeError( +"."+.Name, fmt.Errorf("error remain-tag field with invalid type: %q", .Type()), ) } := .MapRange() for .Next() { .SetMapIndex(.Key(), .Value()) } continue } } if := [:]; != "" { = } } else if len() > 0 { if == "-" { continue } = } switch .Kind() { // this is an embedded struct, so handle it differently case reflect.Struct: := reflect.New(.Type()) .Elem().Set() := .Type() := .Key() := .Elem() := reflect.MapOf(, ) := reflect.MakeMap() // 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. := reflect.New(.Type()) reflect.Indirect().Set() := .decode(, .Interface(), reflect.Indirect()) if != nil { return } // the underlying map may have been completely overwritten so pull // it indirectly out of the enclosing value. = reflect.Indirect() if { for , := range .MapKeys() { .SetMapIndex(, .MapIndex()) } } else { .SetMapIndex(reflect.ValueOf(), ) } default: .SetMapIndex(reflect.ValueOf(), ) } } if .CanAddr() { .Set() } return nil } func ( *Decoder) ( string, any, reflect.Value) (bool, error) { // If the input data is nil, then we want to just set the output // pointer to be nil as well. := == nil if ! { switch := reflect.Indirect(reflect.ValueOf()); .Kind() { case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: = .IsNil() } } if { if !.IsNil() && .CanSet() { := reflect.New(.Type()).Elem() .Set() } return true, nil } // Create an element of the concrete (non pointer) type and decode // into that. Then set the value of the pointer to this type. := .Type() := .Elem() if .CanSet() { := if .IsNil() || .config.ZeroFields { = reflect.New() } if := .decode(, , reflect.Indirect()); != nil { return false, } .Set() } else { if := .decode(, , reflect.Indirect()); != nil { return false, } } return false, nil } func ( *Decoder) ( string, any, reflect.Value) error { // Create an element of the concrete (non pointer) type and decode // into that. Then set the value of the pointer to this type. := reflect.Indirect(reflect.ValueOf()) if .Type() != .Type() { return newDecodeError(, &UnconvertibleTypeError{ Expected: , Value: , }) } .Set() return nil } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := .Kind() := .Type() := .Elem() := reflect.SliceOf() // If we have a non array/slice type then we first attempt to convert. if != reflect.Array && != reflect.Slice { if .config.WeaklyTypedInput { switch { // Slice and array we use the normal logic case == reflect.Slice, == reflect.Array: break // Empty maps turn into empty slices case == reflect.Map: if .Len() == 0 { .Set(reflect.MakeSlice(, 0, 0)) return nil } // Create slice of maps of other sizes return .(, []any{}, ) case == reflect.String && .Kind() == reflect.Uint8: return .(, []byte(.String()), ) // All other types we try to convert to the slice type // and "lift" it into it. i.e. a string becomes a string slice. default: // Just re-try this function with data as a slice. return .(, []any{}, ) } } return newDecodeError(, fmt.Errorf("source data must be an array or slice, got %s", )) } // If the input value is nil, then don't allocate since empty != nil if != reflect.Array && .IsNil() { return nil } := if .IsNil() || .config.ZeroFields { // Make a new slice to hold our result, same size as the original data. = reflect.MakeSlice(, .Len(), .Len()) } else if .Len() > .Len() { = .Slice(0, .Len()) } // Accumulate any errors var []error for := 0; < .Len(); ++ { := .Index().Interface() for .Len() <= { = reflect.Append(, reflect.Zero()) } := .Index() := + "[" + strconv.Itoa() + "]" if := .decode(, , ); != nil { = append(, ) } } // Finally, set the value to the slice we built up .Set() return errors.Join(...) } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) := .Kind() := .Type() := .Elem() := reflect.ArrayOf(.Len(), ) := if isComparable() && .Interface() == reflect.Zero(.Type()).Interface() || .config.ZeroFields { // Check input type if != reflect.Array && != reflect.Slice { if .config.WeaklyTypedInput { switch { // Empty maps turn into empty arrays case == reflect.Map: if .Len() == 0 { .Set(reflect.Zero()) return nil } // All other types we try to convert to the array type // and "lift" it into it. i.e. a string becomes a string array. default: // Just re-try this function with data as a slice. return .(, []any{}, ) } } return newDecodeError(, fmt.Errorf("source data must be an array or slice, got %s", )) } if .Len() > .Len() { return newDecodeError(, fmt.Errorf("expected source data to have length less or equal to %d, got %d", .Len(), .Len())) } // Make a new array to hold our result, same size as the original data. = reflect.New().Elem() } // Accumulate any errors var []error for := 0; < .Len(); ++ { := .Index().Interface() := .Index() := + "[" + strconv.Itoa() + "]" if := .decode(, , ); != nil { = append(, ) } } // Finally, set the value to the array we built up .Set() return errors.Join(...) } func ( *Decoder) ( string, any, reflect.Value) error { := reflect.Indirect(reflect.ValueOf()) // If the type of the value to write to and the data match directly, // then we just set it directly instead of recursing into the structure. if .Type() == .Type() { .Set() return nil } := .Kind() switch { case reflect.Map: return .decodeStructFromMap(, , ) case reflect.Struct: // 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. // Make a new map to hold our result := reflect.TypeOf((map[string]any)(nil)) := reflect.MakeMap() // 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. := reflect.New(.Type()) reflect.Indirect().Set() if := .decodeMapFromStruct(, , reflect.Indirect(), ); != nil { return } := .decodeStructFromMap(, reflect.Indirect(), ) return default: return newDecodeError(, fmt.Errorf("expected a map or struct, got %q", )) } } func ( *Decoder) ( string, , reflect.Value) error { := .Type() if := .Key().Kind(); != reflect.String && != reflect.Interface { return newDecodeError(, fmt.Errorf("needs a map with string keys, has %q keys", )) } := make(map[reflect.Value]struct{}) := make(map[any]struct{}) for , := range .MapKeys() { [] = struct{}{} [.Interface()] = struct{}{} } := make(map[any]struct{}) var []error // This slice will keep track of all the structs we'll be decoding. // There can be more than one struct if there are embedded structs // that are squashed. := make([]reflect.Value, 1, 5) [0] = // Compile the list of all the fields that we're going to be decoding // from all the structs. type struct { reflect.StructField reflect.Value } // remainField is set to a valid field set with the "remain" tag if // we are keeping track of remaining values. var * := []{} for len() > 0 { := [0] = [1:] := .Type() for := 0; < .NumField(); ++ { := .Field() := .Field() if .Kind() == reflect.Ptr && .Elem().Kind() == reflect.Struct { // Handle embedded struct pointers as embedded structs. = .Elem() } // If "squash" is specified in the tag, we squash the field down. := .config.Squash && .Kind() == reflect.Struct && .Anonymous := false // We always parse the tags cause we're looking for other tags too := strings.Split(.Tag.Get(.config.TagName), ",") for , := range [1:] { if == .config.SquashTagOption { = true break } if == "remain" { = true break } } if { switch .Kind() { case reflect.Struct: = append(, ) case reflect.Interface: if !.IsNil() { = append(, .Elem().Elem()) } default: = append(, newDecodeError( +"."+.Name, fmt.Errorf("unsupported type for squash: %s", .Kind()), )) } continue } // Build our field if { = &{, } } else { // Normal struct field, store it away = append(, {, }) } } } // for fieldType, field := range fields { for , := range { , := ., . := .Name := .Tag.Get(.config.TagName) if == "" && .config.IgnoreUntaggedFields { continue } = strings.SplitN(, ",", 2)[0] if != "" { = } := reflect.ValueOf() := .MapIndex() if !.IsValid() { // Do a slower search by iterating over each key and // doing case-insensitive search. for := range { , := .Interface().(string) if ! { // Not a string key continue } if .config.MatchName(, ) { = = .MapIndex() break } } if !.IsValid() { // There was no matching key in the map for the value in // the struct. Remember it for potential errors and metadata. if !(.config.AllowUnsetPointer && .Kind() == reflect.Ptr) { [] = struct{}{} } continue } } if !.IsValid() { // This should never happen panic("field is not valid") } // If we can't set the field, then it is unexported or something, // and we just continue onwards. if !.CanSet() { continue } // Delete the key we're using from the unused map so we stop tracking delete(, .Interface()) // If the name is empty string, then we're at the root, and we // don't dot-join the fields. if != "" { = + "." + } if := .decode(, .Interface(), ); != nil { = append(, ) } } // If we have a "remain"-tagged field and we have unused keys then // we put the unused keys directly into the remain field. if != nil && len() > 0 { // Build a map of only the unused values := map[any]any{} for := range { [] = .MapIndex(reflect.ValueOf()).Interface() } // Decode it as-if we were just decoding this map onto our map. if := .decodeMap(, , .); != nil { = append(, ) } // Set the map to nil so we have none so that the next check will // not error (ErrorUnused) = nil } if .config.ErrorUnused && len() > 0 { := make([]string, 0, len()) for := range { = append(, .(string)) } sort.Strings() = append(, newDecodeError( , fmt.Errorf("has invalid keys: %s", strings.Join(, ", ")), )) } if .config.ErrorUnset && len() > 0 { := make([]string, 0, len()) for := range { = append(, .(string)) } sort.Strings() = append(, newDecodeError( , fmt.Errorf("has unset fields: %s", strings.Join(, ", ")), )) } if := errors.Join(...); != nil { return } // Add the unused keys to the list of unused keys if we're tracking metadata if .config.Metadata != nil { for := range { := .(string) if != "" { = + "." + } .config.Metadata.Unused = append(.config.Metadata.Unused, ) } for := range { := .(string) if != "" { = + "." + } .config.Metadata.Unset = append(.config.Metadata.Unset, ) } } return nil } func isEmptyValue( reflect.Value) bool { switch getKind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: return .Len() == 0 case reflect.Bool: return !.Bool() case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return .Int() == 0 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: return .Uint() == 0 case reflect.Float32, reflect.Float64: return .Float() == 0 case reflect.Interface, reflect.Ptr: return .IsNil() } return false } func getKind( reflect.Value) reflect.Kind { := .Kind() switch { case >= reflect.Int && <= reflect.Int64: return reflect.Int case >= reflect.Uint && <= reflect.Uint64: return reflect.Uint case >= reflect.Float32 && <= reflect.Float64: return reflect.Float32 case >= reflect.Complex64 && <= reflect.Complex128: return reflect.Complex64 default: return } } func isStructTypeConvertibleToMap( reflect.Type, bool, string) bool { for := 0; < .NumField(); ++ { := .Field() if .PkgPath == "" && ! { // check for unexported fields return true } if && .Tag.Get() != "" { // check for mapstructure tags inside return true } } return false } func dereferencePtrToStructIfNeeded( reflect.Value, string) reflect.Value { if .Kind() != reflect.Ptr || .Elem().Kind() != reflect.Struct { return } := .Elem() := .Type() if isStructTypeConvertibleToMap(, true, ) { return } return }