[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\nindent_style = space\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[*.go]\nindent_style = tab\n\n[{Makefile,*.mk}]\nindent_style = tab\n\n[*.nix]\nindent_size = 2\n\n[.golangci.yaml]\nindent_size = 2\n\n[devenv.yaml]\nindent_size = 2\n"
  },
  {
    "path": ".envrc",
    "content": "#!/usr/bin/env bash\n\nexport DIRENV_WARN_TIMEOUT=20s\n\neval \"$(devenv direnvrc)\"\n\nuse devenv\n"
  },
  {
    "path": ".github/.editorconfig",
    "content": "[{*.yml,*.yaml}]\nindent_size = 2\n"
  },
  {
    "path": ".github/dependabot.yaml",
    "content": "version: 2\n\nupdates:\n  - package-ecosystem: gomod\n    directory: /\n    schedule:\n      interval: daily\n\n  - package-ecosystem: github-actions\n    directory: /\n    schedule:\n      interval: daily\n"
  },
  {
    "path": ".github/workflows/analysis-scorecard.yaml",
    "content": "name: OpenSSF Scorecard\n\non:\n  branch_protection_rule:\n  push:\n    branches: [main]\n  schedule:\n    - cron: \"30 0 * * 5\"\n\npermissions:\n  contents: read\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ubuntu-latest\n\n    permissions:\n      actions: read\n      contents: read\n      id-token: write\n      security-events: write\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n        with:\n          persist-credentials: false\n\n      - name: Run analysis\n        uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3\n        with:\n          results_file: results.sarif\n          results_format: sarif\n          publish_results: true\n\n      - name: Upload results as artifact\n        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0\n        with:\n          name: OpenSSF Scorecard results\n          path: results.sarif\n          retention-days: 5\n\n      - name: Upload results to GitHub Security tab\n        uses: github/codeql-action/upload-sarif@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v3.29.5\n        with:\n          sarif_file: results.sarif\n"
  },
  {
    "path": ".github/workflows/ci.yaml",
    "content": "name: CI\n\non:\n  push:\n    branches: [main]\n  pull_request:\n\npermissions:\n  contents: read\n\njobs:\n  test:\n    name: Test\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        go:\n          [\n            \"1.18\",\n            \"1.19\",\n            \"1.20\",\n            \"1.21\",\n            \"1.22\",\n            \"1.23\",\n            \"1.24\",\n            \"1.25\",\n            \"stable\",\n            \"oldstable\",\n          ]\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n\n      - name: Set up Go\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0\n        with:\n          go-version: ${{ matrix.go }}\n\n      - name: Test\n        run: go test -race -v -shuffle=on ./...\n\n  lint:\n    name: Lint\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2\n\n      - name: Set up Go\n        uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0\n        with:\n          go-version: \"1.25\"\n\n      - name: Lint\n        uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0\n        with:\n          version: v2.6.2\n"
  },
  {
    "path": ".gitignore",
    "content": "/bin/\n/build/\n/var/\n\n# Devenv\n.devenv*\ndevenv.local.nix\ndevenv.local.yaml\n.direnv\n.pre-commit-config.yaml\n"
  },
  {
    "path": ".golangci.yaml",
    "content": "version: \"2\"\n\nrun:\n  timeout: 10m\n\nlinters:\n  enable:\n    - govet\n    - ineffassign\n    # - misspell\n    - nolintlint\n    # - revive\n\n  disable:\n    - errcheck\n    - staticcheck\n    - unused\n\n  settings:\n    misspell:\n      locale: US\n    nolintlint:\n      allow-unused: false # report any unused nolint directives\n      require-specific: false # don't require nolint directives to be specific about which linter is being skipped\n\nformatters:\n  enable:\n    - gci\n    - gofmt\n    - gofumpt\n    - goimports\n    # - golines\n\n  settings:\n    gci:\n      sections:\n        - standard\n        - default\n        - localmodule\n    gofmt:\n      simplify: true\n      rewrite-rules:\n        - pattern: interface{}\n          replacement: any\n\n  exclusions:\n    paths:\n      - internal/\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "> [!WARNING]\n> As of v2 of this library, change log can be found in GitHub releases.\n\n## 1.5.1\n\n* Wrap errors so they're compatible with `errors.Is` and `errors.As` [GH-282]\n* Fix map of slices not decoding properly in certain cases. [GH-266]\n\n## 1.5.0\n\n* New option `IgnoreUntaggedFields` to ignore decoding to any fields\n  without `mapstructure` (or the configured tag name) set [GH-277]\n* New option `ErrorUnset` which makes it an error if any fields\n  in a target struct are not set by the decoding process. [GH-225]\n* New function `OrComposeDecodeHookFunc` to help compose decode hooks. [GH-240]\n* Decoding to slice from array no longer crashes [GH-265]\n* Decode nested struct pointers to map [GH-271]\n* Fix issue where `,squash` was ignored if `Squash` option was set. [GH-280]\n* Fix issue where fields with `,omitempty` would sometimes decode\n  into a map with an empty string key [GH-281]\n\n## 1.4.3\n\n* Fix cases where `json.Number` didn't decode properly [GH-261]\n\n## 1.4.2\n\n* Custom name matchers to support any sort of casing, formatting, etc. for\n  field names. [GH-250]\n* Fix possible panic in ComposeDecodeHookFunc [GH-251]\n\n## 1.4.1\n\n* Fix regression where `*time.Time` value would be set to empty and not be sent\n  to decode hooks properly [GH-232]\n\n## 1.4.0\n\n* A new decode hook type `DecodeHookFuncValue` has been added that has\n  access to the full values. [GH-183]\n* Squash is now supported with embedded fields that are struct pointers [GH-205]\n* Empty strings will convert to 0 for all numeric types when weakly decoding [GH-206]\n\n## 1.3.3\n\n* Decoding maps from maps creates a settable value for decode hooks [GH-203]\n\n## 1.3.2\n\n* Decode into interface type with a struct value is supported [GH-187]\n\n## 1.3.1\n\n* Squash should only squash embedded structs. [GH-194]\n\n## 1.3.0\n\n* Added `\",omitempty\"` support. This will ignore zero values in the source\n  structure when encoding. [GH-145]\n\n## 1.2.3\n\n* Fix duplicate entries in Keys list with pointer values. [GH-185]\n\n## 1.2.2\n\n* Do not add unsettable (unexported) values to the unused metadata key\n  or \"remain\" value. [GH-150]\n\n## 1.2.1\n\n* Go modules checksum mismatch fix\n\n## 1.2.0\n\n* Added support to capture unused values in a field using the `\",remain\"` value\n  in the mapstructure tag. There is an example to showcase usage.\n* Added `DecoderConfig` option to always squash embedded structs\n* `json.Number` can decode into `uint` types\n* Empty slices are preserved and not replaced with nil slices\n* Fix panic that can occur in when decoding a map into a nil slice of structs\n* Improved package documentation for godoc\n\n## 1.1.2\n\n* Fix error when decode hook decodes interface implementation into interface\n  type. [GH-140]\n\n## 1.1.1\n\n* Fix panic that can happen in `decodePtr`\n\n## 1.1.0\n\n* Added `StringToIPHookFunc` to convert `string` to `net.IP` and `net.IPNet` [GH-133]\n* Support struct to struct decoding [GH-137]\n* If source map value is nil, then destination map value is nil (instead of empty)\n* If source slice value is nil, then destination slice value is nil (instead of empty)\n* If source pointer is nil, then destination pointer is set to nil (instead of\n  allocated zero value of type)\n\n## 1.0.0\n\n* Initial tagged stable release.\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2013 Mitchell Hashimoto\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# mapstructure\n\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/go-viper/mapstructure/ci.yaml?style=flat-square)](https://github.com/go-viper/mapstructure/actions/workflows/ci.yaml)\n[![go.dev reference](https://img.shields.io/badge/go.dev-reference-007d9c?logo=go&logoColor=white&style=flat-square)](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2)\n![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/go-viper/mapstructure?style=flat-square&color=61CFDD)\n[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-viper/mapstructure/badge?style=flat-square)](https://deps.dev/go/github.com%252Fgo-viper%252Fmapstructure%252Fv2)\n\nmapstructure is a Go library for decoding generic map values to structures\nand vice versa, while providing helpful error handling.\n\nThis library is most useful when decoding values from some data stream (JSON,\nGob, etc.) where you don't _quite_ know the structure of the underlying data\nuntil you read a part of it. You can therefore read a `map[string]interface{}`\nand use this library to decode it into the proper underlying native Go\nstructure.\n\n## Installation\n\n```shell\ngo get github.com/go-viper/mapstructure/v2\n```\n\n## Migrating from `github.com/mitchellh/mapstructure`\n\n[@mitchehllh](https://github.com/mitchellh) announced his intent to archive some of his unmaintained projects (see [here](https://gist.github.com/mitchellh/90029601268e59a29e64e55bab1c5bdc) and [here](https://github.com/mitchellh/mapstructure/issues/349)). This is a repository achieved the \"blessed fork\" status.\n\nYou can migrate to this package by changing your import paths in your Go files to `github.com/go-viper/mapstructure/v2`.\nThe API is the same, so you don't need to change anything else.\n\nHere is a script that can help you with the migration:\n\n```shell\nsed -i 's|github.com/mitchellh/mapstructure|github.com/go-viper/mapstructure/v2|g' $(find . -type f -name '*.go')\n```\n\nIf you need more time to migrate your code, that is absolutely fine.\n\nSome of the latest fixes are backported to the v1 release branch of this package, so you can use the Go modules `replace` feature until you are ready to migrate:\n\n```shell\nreplace github.com/mitchellh/mapstructure => github.com/go-viper/mapstructure v1.6.0\n```\n\n## Usage & Example\n\nFor usage and examples see the [documentation](https://pkg.go.dev/mod/github.com/go-viper/mapstructure/v2).\n\nThe `Decode` function has examples associated with it there.\n\n## But Why?!\n\nGo offers fantastic standard libraries for decoding formats such as JSON.\nThe standard method is to have a struct pre-created, and populate that struct\nfrom the bytes of the encoded format. This is great, but the problem is if\nyou have configuration or an encoding that changes slightly depending on\nspecific fields. For example, consider this JSON:\n\n```json\n{\n  \"type\": \"person\",\n  \"name\": \"Mitchell\"\n}\n```\n\nPerhaps we can't populate a specific structure without first reading\nthe \"type\" field from the JSON. We could always do two passes over the\ndecoding of the JSON (reading the \"type\" first, and the rest later).\nHowever, it is much simpler to just decode this into a `map[string]interface{}`\nstructure, read the \"type\" key, then use something like this library\nto decode it into the proper structure.\n\n## Credits\n\nMapstructure was originally created by [@mitchellh](https://github.com/mitchellh).\nThis is a maintained fork of the original library.\n\nRead more about the reasons for the fork [here](https://github.com/mitchellh/mapstructure/issues/349).\n\n## License\n\nThe project is licensed under the [MIT License](LICENSE).\n"
  },
  {
    "path": "decode_hooks.go",
    "content": "package mapstructure\n\nimport (\n\t\"encoding\"\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// safeInterface safely extracts the interface value from a reflect.Value.\n// It returns nil if the value is not valid or is a nil interface.\nfunc safeInterface(v reflect.Value) any {\n\tif !v.IsValid() {\n\t\treturn nil\n\t}\n\treturn v.Interface()\n}\n\n// typedDecodeHook takes a raw DecodeHookFunc (an any) and turns\n// it into the proper DecodeHookFunc type, such as DecodeHookFuncType.\nfunc typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {\n\t// Create variables here so we can reference them with the reflect pkg\n\tvar f1 DecodeHookFuncType\n\tvar f2 DecodeHookFuncKind\n\tvar f3 DecodeHookFuncValue\n\n\t// Fill in the variables into this interface and the rest is done\n\t// automatically using the reflect package.\n\tpotential := []any{f1, f2, f3}\n\n\tv := reflect.ValueOf(h)\n\tvt := v.Type()\n\tfor _, raw := range potential {\n\t\tpt := reflect.ValueOf(raw).Type()\n\t\tif vt.ConvertibleTo(pt) {\n\t\t\treturn v.Convert(pt).Interface()\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// cachedDecodeHook takes a raw DecodeHookFunc (an any) and turns\n// it into a closure to be used directly\n// if the type fails to convert we return a closure always erroring to keep the previous behaviour\nfunc cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (any, error) {\n\tswitch f := typedDecodeHook(raw).(type) {\n\tcase DecodeHookFuncType:\n\t\treturn func(from reflect.Value, to reflect.Value) (any, error) {\n\t\t\tif !from.IsValid() {\n\t\t\t\treturn f(reflect.TypeOf((*any)(nil)).Elem(), to.Type(), nil)\n\t\t\t}\n\t\t\treturn f(from.Type(), to.Type(), from.Interface())\n\t\t}\n\tcase DecodeHookFuncKind:\n\t\treturn func(from reflect.Value, to reflect.Value) (any, error) {\n\t\t\tif !from.IsValid() {\n\t\t\t\treturn f(reflect.Invalid, to.Kind(), nil)\n\t\t\t}\n\t\t\treturn f(from.Kind(), to.Kind(), from.Interface())\n\t\t}\n\tcase DecodeHookFuncValue:\n\t\treturn func(from reflect.Value, to reflect.Value) (any, error) {\n\t\t\treturn f(from, to)\n\t\t}\n\tdefault:\n\t\treturn func(from reflect.Value, to reflect.Value) (any, error) {\n\t\t\treturn nil, errors.New(\"invalid decode hook signature\")\n\t\t}\n\t}\n}\n\n// DecodeHookExec executes the given decode hook. This should be used\n// since it'll naturally degrade to the older backwards compatible DecodeHookFunc\n// that took reflect.Kind instead of reflect.Type.\nfunc DecodeHookExec(\n\traw DecodeHookFunc,\n\tfrom reflect.Value, to reflect.Value,\n) (any, error) {\n\tswitch f := typedDecodeHook(raw).(type) {\n\tcase DecodeHookFuncType:\n\t\tif !from.IsValid() {\n\t\t\treturn f(reflect.TypeOf((*any)(nil)).Elem(), to.Type(), nil)\n\t\t}\n\t\treturn f(from.Type(), to.Type(), from.Interface())\n\tcase DecodeHookFuncKind:\n\t\tif !from.IsValid() {\n\t\t\treturn f(reflect.Invalid, to.Kind(), nil)\n\t\t}\n\t\treturn f(from.Kind(), to.Kind(), from.Interface())\n\tcase DecodeHookFuncValue:\n\t\treturn f(from, to)\n\tdefault:\n\t\treturn nil, errors.New(\"invalid decode hook signature\")\n\t}\n}\n\n// ComposeDecodeHookFunc creates a single DecodeHookFunc that\n// automatically composes multiple DecodeHookFuncs.\n//\n// The composed funcs are called in order, with the result of the\n// previous transformation.\nfunc ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {\n\tcached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(fs))\n\tfor _, f := range fs {\n\t\tcached = append(cached, cachedDecodeHook(f))\n\t}\n\treturn func(f reflect.Value, t reflect.Value) (any, error) {\n\t\tvar err error\n\t\tdata := safeInterface(f)\n\n\t\tnewFrom := f\n\t\tfor _, c := range cached {\n\t\t\tdata, err = c(newFrom, t)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif v, ok := data.(reflect.Value); ok {\n\t\t\t\tnewFrom = v\n\t\t\t} else if data != nil {\n\t\t\t\tnewFrom = reflect.ValueOf(data)\n\t\t\t} else {\n\t\t\t\t// Keep newFrom as invalid (zero) Value when data is nil\n\t\t\t\tnewFrom = reflect.Value{}\n\t\t\t}\n\t\t}\n\n\t\treturn data, nil\n\t}\n}\n\n// OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.\n// If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.\nfunc OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {\n\tcached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(ff))\n\tfor _, f := range ff {\n\t\tcached = append(cached, cachedDecodeHook(f))\n\t}\n\treturn func(a, b reflect.Value) (any, error) {\n\t\tvar allErrs string\n\t\tvar out any\n\t\tvar err error\n\n\t\tfor _, c := range cached {\n\t\t\tout, err = c(a, b)\n\t\t\tif err != nil {\n\t\t\t\tallErrs += err.Error() + \"\\n\"\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\treturn out, nil\n\t\t}\n\n\t\treturn nil, errors.New(allErrs)\n\t}\n}\n\n// StringToSliceHookFunc returns a DecodeHookFunc that converts\n// string to []string by splitting on the given sep.\nfunc StringToSliceHookFunc(sep string) DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.SliceOf(f) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\traw := data.(string)\n\t\tif raw == \"\" {\n\t\t\treturn []string{}, nil\n\t\t}\n\n\t\treturn strings.Split(raw, sep), nil\n\t}\n}\n\n// StringToWeakSliceHookFunc brings back the old (pre-v2) behavior of [StringToSliceHookFunc].\n//\n// As of mapstructure v2.0.0 [StringToSliceHookFunc] checks if the return type is a string slice.\n// This function removes that check.\nfunc StringToWeakSliceHookFunc(sep string) DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Slice {\n\t\t\treturn data, nil\n\t\t}\n\n\t\traw := data.(string)\n\t\tif raw == \"\" {\n\t\t\treturn []string{}, nil\n\t\t}\n\n\t\treturn strings.Split(raw, sep), nil\n\t}\n}\n\n// StringToTimeDurationHookFunc returns a DecodeHookFunc that converts\n// strings to time.Duration.\nfunc StringToTimeDurationHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(time.Duration(5)) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\td, err := time.ParseDuration(data.(string))\n\n\t\treturn d, wrapTimeParseDurationError(err)\n\t}\n}\n\n// StringToTimeLocationHookFunc returns a DecodeHookFunc that converts\n// strings to *time.Location.\nfunc StringToTimeLocationHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(time.Local) {\n\t\t\treturn data, nil\n\t\t}\n\t\td, err := time.LoadLocation(data.(string))\n\n\t\treturn d, wrapTimeParseLocationError(err)\n\t}\n}\n\n// StringToURLHookFunc returns a DecodeHookFunc that converts\n// strings to *url.URL.\nfunc StringToURLHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(&url.URL{}) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tu, err := url.Parse(data.(string))\n\n\t\treturn u, wrapUrlError(err)\n\t}\n}\n\n// StringToIPHookFunc returns a DecodeHookFunc that converts\n// strings to net.IP\nfunc StringToIPHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(net.IP{}) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tip := net.ParseIP(data.(string))\n\t\tif ip == nil {\n\t\t\treturn net.IP{}, fmt.Errorf(\"failed parsing ip\")\n\t\t}\n\n\t\treturn ip, nil\n\t}\n}\n\n// StringToIPNetHookFunc returns a DecodeHookFunc that converts\n// strings to net.IPNet\nfunc StringToIPNetHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(net.IPNet{}) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\t_, net, err := net.ParseCIDR(data.(string))\n\t\treturn net, wrapNetParseError(err)\n\t}\n}\n\n// StringToTimeHookFunc returns a DecodeHookFunc that converts\n// strings to time.Time.\nfunc StringToTimeHookFunc(layout string) DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(time.Time{}) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tti, err := time.Parse(layout, data.(string))\n\n\t\treturn ti, wrapTimeParseError(err)\n\t}\n}\n\n// WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to\n// the decoder.\n//\n// Note that this is significantly different from the WeaklyTypedInput option\n// of the DecoderConfig.\nfunc WeaklyTypedHook(\n\tf reflect.Kind,\n\tt reflect.Kind,\n\tdata any,\n) (any, error) {\n\tdataVal := reflect.ValueOf(data)\n\tswitch t {\n\tcase reflect.String:\n\t\tswitch f {\n\t\tcase reflect.Bool:\n\t\t\tif dataVal.Bool() {\n\t\t\t\treturn \"1\", nil\n\t\t\t}\n\t\t\treturn \"0\", nil\n\t\tcase reflect.Float32:\n\t\t\treturn strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil\n\t\tcase reflect.Int:\n\t\t\treturn strconv.FormatInt(dataVal.Int(), 10), nil\n\t\tcase reflect.Slice:\n\t\t\tdataType := dataVal.Type()\n\t\t\telemKind := dataType.Elem().Kind()\n\t\t\tif elemKind == reflect.Uint8 {\n\t\t\t\treturn string(dataVal.Interface().([]uint8)), nil\n\t\t\t}\n\t\tcase reflect.Uint:\n\t\t\treturn strconv.FormatUint(dataVal.Uint(), 10), nil\n\t\t}\n\t}\n\n\treturn data, nil\n}\n\nfunc RecursiveStructToMapHookFunc() DecodeHookFunc {\n\treturn func(f reflect.Value, t reflect.Value) (any, error) {\n\t\tif f.Kind() != reflect.Struct {\n\t\t\treturn f.Interface(), nil\n\t\t}\n\n\t\tvar i any = struct{}{}\n\t\tif t.Type() != reflect.TypeOf(&i).Elem() {\n\t\t\treturn f.Interface(), nil\n\t\t}\n\n\t\tm := make(map[string]any)\n\t\tt.Set(reflect.ValueOf(m))\n\n\t\treturn f.Interface(), nil\n\t}\n}\n\n// TextUnmarshallerHookFunc returns a DecodeHookFunc that applies\n// strings to the UnmarshalText function, when the target type\n// implements the encoding.TextUnmarshaler interface\nfunc TextUnmarshallerHookFunc() DecodeHookFuncType {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tresult := reflect.New(t).Interface()\n\t\tunmarshaller, ok := result.(encoding.TextUnmarshaler)\n\t\tif !ok {\n\t\t\treturn data, nil\n\t\t}\n\t\tstr, ok := data.(string)\n\t\tif !ok {\n\t\t\tstr = reflect.Indirect(reflect.ValueOf(&data)).Elem().String()\n\t\t}\n\t\tif err := unmarshaller.UnmarshalText([]byte(str)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn result, nil\n\t}\n}\n\n// StringToNetIPAddrHookFunc returns a DecodeHookFunc that converts\n// strings to netip.Addr.\nfunc StringToNetIPAddrHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(netip.Addr{}) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\taddr, err := netip.ParseAddr(data.(string))\n\n\t\treturn addr, wrapNetIPParseAddrError(err)\n\t}\n}\n\n// StringToNetIPAddrPortHookFunc returns a DecodeHookFunc that converts\n// strings to netip.AddrPort.\nfunc StringToNetIPAddrPortHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(netip.AddrPort{}) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\taddrPort, err := netip.ParseAddrPort(data.(string))\n\n\t\treturn addrPort, wrapNetIPParseAddrPortError(err)\n\t}\n}\n\n// StringToNetIPPrefixHookFunc returns a DecodeHookFunc that converts\n// strings to netip.Prefix.\nfunc StringToNetIPPrefixHookFunc() DecodeHookFunc {\n\treturn func(\n\t\tf reflect.Type,\n\t\tt reflect.Type,\n\t\tdata any,\n\t) (any, error) {\n\t\tif f.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\t\tif t != reflect.TypeOf(netip.Prefix{}) {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tprefix, err := netip.ParsePrefix(data.(string))\n\n\t\treturn prefix, wrapNetIPParsePrefixError(err)\n\t}\n}\n\n// StringToBasicTypeHookFunc returns a DecodeHookFunc that converts\n// strings to basic types.\n// int8, uint8, int16, uint16, int32, uint32, int64, uint64, int, uint, float32, float64, bool, byte, rune, complex64, complex128\nfunc StringToBasicTypeHookFunc() DecodeHookFunc {\n\treturn ComposeDecodeHookFunc(\n\t\tStringToInt8HookFunc(),\n\t\tStringToUint8HookFunc(),\n\t\tStringToInt16HookFunc(),\n\t\tStringToUint16HookFunc(),\n\t\tStringToInt32HookFunc(),\n\t\tStringToUint32HookFunc(),\n\t\tStringToInt64HookFunc(),\n\t\tStringToUint64HookFunc(),\n\t\tStringToIntHookFunc(),\n\t\tStringToUintHookFunc(),\n\t\tStringToFloat32HookFunc(),\n\t\tStringToFloat64HookFunc(),\n\t\tStringToBoolHookFunc(),\n\t\t// byte and rune are aliases for uint8 and int32 respectively\n\t\t// StringToByteHookFunc(),\n\t\t// StringToRuneHookFunc(),\n\t\tStringToComplex64HookFunc(),\n\t\tStringToComplex128HookFunc(),\n\t)\n}\n\n// StringToInt8HookFunc returns a DecodeHookFunc that converts\n// strings to int8.\nfunc StringToInt8HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Int8 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\ti64, err := strconv.ParseInt(data.(string), 0, 8)\n\t\treturn int8(i64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToUint8HookFunc returns a DecodeHookFunc that converts\n// strings to uint8.\nfunc StringToUint8HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Uint8 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tu64, err := strconv.ParseUint(data.(string), 0, 8)\n\t\treturn uint8(u64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToInt16HookFunc returns a DecodeHookFunc that converts\n// strings to int16.\nfunc StringToInt16HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Int16 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\ti64, err := strconv.ParseInt(data.(string), 0, 16)\n\t\treturn int16(i64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToUint16HookFunc returns a DecodeHookFunc that converts\n// strings to uint16.\nfunc StringToUint16HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Uint16 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tu64, err := strconv.ParseUint(data.(string), 0, 16)\n\t\treturn uint16(u64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToInt32HookFunc returns a DecodeHookFunc that converts\n// strings to int32.\nfunc StringToInt32HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Int32 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\ti64, err := strconv.ParseInt(data.(string), 0, 32)\n\t\treturn int32(i64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToUint32HookFunc returns a DecodeHookFunc that converts\n// strings to uint32.\nfunc StringToUint32HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Uint32 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tu64, err := strconv.ParseUint(data.(string), 0, 32)\n\t\treturn uint32(u64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToInt64HookFunc returns a DecodeHookFunc that converts\n// strings to int64.\nfunc StringToInt64HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Int64 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\ti64, err := strconv.ParseInt(data.(string), 0, 64)\n\t\treturn int64(i64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToUint64HookFunc returns a DecodeHookFunc that converts\n// strings to uint64.\nfunc StringToUint64HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Uint64 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tu64, err := strconv.ParseUint(data.(string), 0, 64)\n\t\treturn uint64(u64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToIntHookFunc returns a DecodeHookFunc that converts\n// strings to int.\nfunc StringToIntHookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Int {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\ti64, err := strconv.ParseInt(data.(string), 0, 0)\n\t\treturn int(i64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToUintHookFunc returns a DecodeHookFunc that converts\n// strings to uint.\nfunc StringToUintHookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Uint {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tu64, err := strconv.ParseUint(data.(string), 0, 0)\n\t\treturn uint(u64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToFloat32HookFunc returns a DecodeHookFunc that converts\n// strings to float32.\nfunc StringToFloat32HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Float32 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tf64, err := strconv.ParseFloat(data.(string), 32)\n\t\treturn float32(f64), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToFloat64HookFunc returns a DecodeHookFunc that converts\n// strings to float64.\nfunc StringToFloat64HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Float64 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tf64, err := strconv.ParseFloat(data.(string), 64)\n\t\treturn f64, wrapStrconvNumError(err)\n\t}\n}\n\n// StringToBoolHookFunc returns a DecodeHookFunc that converts\n// strings to bool.\nfunc StringToBoolHookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Bool {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tb, err := strconv.ParseBool(data.(string))\n\t\treturn b, wrapStrconvNumError(err)\n\t}\n}\n\n// StringToByteHookFunc returns a DecodeHookFunc that converts\n// strings to byte.\nfunc StringToByteHookFunc() DecodeHookFunc {\n\treturn StringToUint8HookFunc()\n}\n\n// StringToRuneHookFunc returns a DecodeHookFunc that converts\n// strings to rune.\nfunc StringToRuneHookFunc() DecodeHookFunc {\n\treturn StringToInt32HookFunc()\n}\n\n// StringToComplex64HookFunc returns a DecodeHookFunc that converts\n// strings to complex64.\nfunc StringToComplex64HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Complex64 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tc128, err := strconv.ParseComplex(data.(string), 64)\n\t\treturn complex64(c128), wrapStrconvNumError(err)\n\t}\n}\n\n// StringToComplex128HookFunc returns a DecodeHookFunc that converts\n// strings to complex128.\nfunc StringToComplex128HookFunc() DecodeHookFunc {\n\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\tif f.Kind() != reflect.String || t.Kind() != reflect.Complex128 {\n\t\t\treturn data, nil\n\t\t}\n\n\t\t// Convert it by parsing\n\t\tc128, err := strconv.ParseComplex(data.(string), 128)\n\t\treturn c128, wrapStrconvNumError(err)\n\t}\n}\n"
  },
  {
    "path": "decode_hooks_test.go",
    "content": "package mapstructure\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"math/big\"\n\t\"net\"\n\t\"net/netip\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n)\n\ntype decodeHookTestSuite[F any, T any] struct {\n\tfn   DecodeHookFunc\n\tok   []decodeHookTestCase[F, T]\n\tfail []decodeHookFailureTestCase[F, T]\n}\n\nfunc (ts decodeHookTestSuite[F, T]) Run(t *testing.T) {\n\tt.Run(\"OK\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor _, tc := range ts.ok {\n\t\t\ttc := tc\n\n\t\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttc.Run(t, ts.fn)\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"Fail\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tfor _, tc := range ts.fail {\n\t\t\ttc := tc\n\n\t\t\tt.Run(\"\", func(t *testing.T) {\n\t\t\t\tt.Parallel()\n\n\t\t\t\ttc.Run(t, ts.fn)\n\t\t\t})\n\t\t}\n\t})\n\n\tt.Run(\"NoOp\", func(t *testing.T) {\n\t\tt.Parallel()\n\n\t\tvar zero F\n\n\t\tactual, err := DecodeHookExec(ts.fn, reflect.ValueOf(zero), reflect.ValueOf(zero))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\n\t\tif !reflect.DeepEqual(actual, zero) {\n\t\t\tt.Fatalf(\"expected %[1]T(%#[1]v), got %[2]T(%#[2]v)\", zero, actual)\n\t\t}\n\t})\n}\n\ntype decodeHookTestCase[F any, T any] struct {\n\tfrom     F\n\texpected T\n}\n\nfunc (tc decodeHookTestCase[F, T]) Run(t *testing.T, fn DecodeHookFunc) {\n\tvar to T\n\n\tactual, err := DecodeHookExec(fn, reflect.ValueOf(tc.from), reflect.ValueOf(to))\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif !reflect.DeepEqual(actual, tc.expected) {\n\t\tt.Fatalf(\"expected %[1]T(%#[1]v), got %[2]T(%#[2]v)\", tc.expected, actual)\n\t}\n}\n\ntype decodeHookFailureTestCase[F any, T any] struct {\n\tfrom F\n}\n\nfunc (tc decodeHookFailureTestCase[F, T]) Run(t *testing.T, fn DecodeHookFunc) {\n\tvar to T\n\n\t_, err := DecodeHookExec(fn, reflect.ValueOf(tc.from), reflect.ValueOf(to))\n\tif err == nil {\n\t\tt.Fatalf(\"expected error, got none\")\n\t}\n}\n\nfunc TestComposeDecodeHookFunc(t *testing.T) {\n\tf1 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn data.(string) + \"foo\", nil\n\t}\n\n\tf2 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn data.(string) + \"bar\", nil\n\t}\n\n\tf := ComposeDecodeHookFunc(f1, f2)\n\n\tresult, err := DecodeHookExec(\n\t\tf, reflect.ValueOf(\"\"), reflect.ValueOf([]byte(\"\")))\n\tif err != nil {\n\t\tt.Fatalf(\"bad: %s\", err)\n\t}\n\tif result.(string) != \"foobar\" {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestComposeDecodeHookFunc_err(t *testing.T) {\n\tf1 := func(reflect.Kind, reflect.Kind, any) (any, error) {\n\t\treturn nil, errors.New(\"foo\")\n\t}\n\n\tf2 := func(reflect.Kind, reflect.Kind, any) (any, error) {\n\t\tpanic(\"NOPE\")\n\t}\n\n\tf := ComposeDecodeHookFunc(f1, f2)\n\n\t_, err := DecodeHookExec(\n\t\tf, reflect.ValueOf(\"\"), reflect.ValueOf([]byte(\"\")))\n\tif err.Error() != \"foo\" {\n\t\tt.Fatalf(\"bad: %s\", err)\n\t}\n}\n\nfunc TestComposeDecodeHookFunc_kinds(t *testing.T) {\n\tvar f2From reflect.Kind\n\n\tf1 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn int(42), nil\n\t}\n\n\tf2 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\tf2From = f\n\t\treturn data, nil\n\t}\n\n\tf := ComposeDecodeHookFunc(f1, f2)\n\n\t_, err := DecodeHookExec(\n\t\tf, reflect.ValueOf(\"\"), reflect.ValueOf([]byte(\"\")))\n\tif err != nil {\n\t\tt.Fatalf(\"bad: %s\", err)\n\t}\n\tif f2From != reflect.Int {\n\t\tt.Fatalf(\"bad: %#v\", f2From)\n\t}\n}\n\nfunc TestOrComposeDecodeHookFunc(t *testing.T) {\n\tf1 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn data.(string) + \"foo\", nil\n\t}\n\n\tf2 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn data.(string) + \"bar\", nil\n\t}\n\n\tf := OrComposeDecodeHookFunc(f1, f2)\n\n\tresult, err := DecodeHookExec(\n\t\tf, reflect.ValueOf(\"\"), reflect.ValueOf([]byte(\"\")))\n\tif err != nil {\n\t\tt.Fatalf(\"bad: %s\", err)\n\t}\n\tif result.(string) != \"foo\" {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestOrComposeDecodeHookFunc_correctValueIsLast(t *testing.T) {\n\tf1 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn nil, errors.New(\"f1 error\")\n\t}\n\n\tf2 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn nil, errors.New(\"f2 error\")\n\t}\n\n\tf3 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn data.(string) + \"bar\", nil\n\t}\n\n\tf := OrComposeDecodeHookFunc(f1, f2, f3)\n\n\tresult, err := DecodeHookExec(\n\t\tf, reflect.ValueOf(\"\"), reflect.ValueOf([]byte(\"\")))\n\tif err != nil {\n\t\tt.Fatalf(\"bad: %s\", err)\n\t}\n\tif result.(string) != \"bar\" {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestOrComposeDecodeHookFunc_err(t *testing.T) {\n\tf1 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn nil, errors.New(\"f1 error\")\n\t}\n\n\tf2 := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn nil, errors.New(\"f2 error\")\n\t}\n\n\tf := OrComposeDecodeHookFunc(f1, f2)\n\n\t_, err := DecodeHookExec(\n\t\tf, reflect.ValueOf(\"\"), reflect.ValueOf([]byte(\"\")))\n\tif err == nil {\n\t\tt.Fatalf(\"bad: should return an error\")\n\t}\n\tif err.Error() != \"f1 error\\nf2 error\\n\" {\n\t\tt.Fatalf(\"bad: %s\", err)\n\t}\n}\n\nfunc TestComposeDecodeHookFunc_safe_nofuncs(t *testing.T) {\n\tf := ComposeDecodeHookFunc()\n\ttype myStruct2 struct {\n\t\tMyInt int\n\t}\n\n\ttype myStruct1 struct {\n\t\tBlah map[string]myStruct2\n\t}\n\n\tsrc := &myStruct1{Blah: map[string]myStruct2{\n\t\t\"test\": {\n\t\t\tMyInt: 1,\n\t\t},\n\t}}\n\n\tdst := &myStruct1{}\n\tdConf := &DecoderConfig{\n\t\tResult:      dst,\n\t\tErrorUnused: true,\n\t\tDecodeHook:  f,\n\t}\n\td, err := NewDecoder(dConf)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n\terr = d.Decode(src)\n\tif err != nil {\n\t\tt.Fatal(err)\n\t}\n}\n\nfunc TestComposeDecodeHookFunc_ReflectValueHook(t *testing.T) {\n\treflectValueHook := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\tnew := data.(string) + \"foo\"\n\t\treturn reflect.ValueOf(new), nil\n\t}\n\n\tstringHook := func(\n\t\tf reflect.Kind,\n\t\tt reflect.Kind,\n\t\tdata any,\n\t) (any, error) {\n\t\treturn data.(string) + \"bar\", nil\n\t}\n\n\tf := ComposeDecodeHookFunc(reflectValueHook, stringHook)\n\n\tresult, err := DecodeHookExec(\n\t\tf, reflect.ValueOf(\"\"), reflect.ValueOf([]byte(\"\")))\n\tif err != nil {\n\t\tt.Fatalf(\"bad: %s\", err)\n\t}\n\tif result.(string) != \"foobar\" {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\n// TestComposeDecodeHookFunc_NilValue tests that ComposeDecodeHookFunc\n// doesn't panic when a hook returns nil (issue #121).\nfunc TestComposeDecodeHookFunc_NilValue(t *testing.T) {\n\thook := func(f reflect.Kind, t reflect.Kind, data any) (any, error) {\n\t\treturn data, nil\n\t}\n\n\tf := ComposeDecodeHookFunc(hook, hook)\n\n\t// Test with nil input - this should not panic\n\tresult, err := DecodeHookExec(f, reflect.Value{}, reflect.ValueOf(\"\"))\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\tif result != nil {\n\t\tt.Fatalf(\"expected nil result, got: %#v\", result)\n\t}\n}\n\n// TestComposeDecodeHookFunc_DecodeNilRemain tests the specific scenario from issue #121\n// where using ComposeDecodeHookFunc with DecodeNil and ,remain tag causes a panic.\nfunc TestComposeDecodeHookFunc_DecodeNilRemain(t *testing.T) {\n\tv := make(map[string]any)\n\tv[\"m\"] = nil\n\n\tvar result struct {\n\t\tV map[string]any `mapstructure:\",remain\"`\n\t}\n\n\thook := func(f reflect.Kind, t reflect.Kind, data any) (any, error) {\n\t\treturn data, nil\n\t}\n\n\tdec, err := NewDecoder(&DecoderConfig{\n\t\tDecodeHook: ComposeDecodeHookFunc(hook, hook),\n\t\tDecodeNil:  true,\n\t\tResult:     &result,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error creating decoder: %s\", err)\n\t}\n\n\t// This should not panic\n\terr = dec.Decode(&v)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error decoding: %s\", err)\n\t}\n}\n\nfunc TestStringToSliceHookFunc(t *testing.T) {\n\t// Test comma separator\n\tcommaSuite := decodeHookTestSuite[string, []string]{\n\t\tfn: StringToSliceHookFunc(\",\"),\n\t\tok: []decodeHookTestCase[string, []string]{\n\t\t\t{\"foo,bar,baz\", []string{\"foo\", \"bar\", \"baz\"}}, // Basic comma separation\n\t\t\t{\"\", []string{}},                                                                    // Empty string\n\t\t\t{\"single\", []string{\"single\"}},                                                      // Single element\n\t\t\t{\"one,two\", []string{\"one\", \"two\"}},                                                 // Two elements\n\t\t\t{\"foo, bar, baz\", []string{\"foo\", \" bar\", \" baz\"}},                                  // Preserves spaces\n\t\t\t{\"foo,,bar\", []string{\"foo\", \"\", \"bar\"}},                                            // Empty elements\n\t\t\t{\",foo,bar,\", []string{\"\", \"foo\", \"bar\", \"\"}},                                       // Leading/trailing separators\n\t\t\t{\"foo,bar,baz,\", []string{\"foo\", \"bar\", \"baz\", \"\"}},                                 // Trailing separator\n\t\t\t{\",foo\", []string{\"\", \"foo\"}},                                                       // Leading separator only\n\t\t\t{\"foo,\", []string{\"foo\", \"\"}},                                                       // Trailing separator only\n\t\t\t{\"a,b,c,d,e,f,g,h,i,j\", []string{\"a\", \"b\", \"c\", \"d\", \"e\", \"f\", \"g\", \"h\", \"i\", \"j\"}}, // Many elements\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, []string]{\n\t\t\t// StringToSliceHookFunc doesn't have failure cases - it always succeeds\n\t\t},\n\t}\n\tt.Run(\"CommaSeparator\", commaSuite.Run)\n\n\t// Test semicolon separator\n\tsemicolonSuite := decodeHookTestSuite[string, []string]{\n\t\tfn: StringToSliceHookFunc(\";\"),\n\t\tok: []decodeHookTestCase[string, []string]{\n\t\t\t{\"foo;bar;baz\", []string{\"foo\", \"bar\", \"baz\"}}, // Basic semicolon separation\n\t\t\t{\"\", []string{}},                                   // Empty string\n\t\t\t{\"single\", []string{\"single\"}},                     // Single element\n\t\t\t{\"one;two\", []string{\"one\", \"two\"}},                // Two elements\n\t\t\t{\"foo; bar; baz\", []string{\"foo\", \" bar\", \" baz\"}}, // Preserves spaces\n\t\t\t{\"foo;;bar\", []string{\"foo\", \"\", \"bar\"}},           // Empty elements\n\t\t\t{\";foo;bar;\", []string{\"\", \"foo\", \"bar\", \"\"}},      // Leading/trailing separators\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, []string]{},\n\t}\n\tt.Run(\"SemicolonSeparator\", semicolonSuite.Run)\n\n\t// Test pipe separator\n\tpipeSuite := decodeHookTestSuite[string, []string]{\n\t\tfn: StringToSliceHookFunc(\"|\"),\n\t\tok: []decodeHookTestCase[string, []string]{\n\t\t\t{\"foo|bar|baz\", []string{\"foo\", \"bar\", \"baz\"}}, // Basic pipe separation\n\t\t\t{\"\", []string{}},                         // Empty string\n\t\t\t{\"single\", []string{\"single\"}},           // Single element\n\t\t\t{\"foo||bar\", []string{\"foo\", \"\", \"bar\"}}, // Empty elements\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, []string]{},\n\t}\n\tt.Run(\"PipeSeparator\", pipeSuite.Run)\n\n\t// Test space separator\n\tspaceSuite := decodeHookTestSuite[string, []string]{\n\t\tfn: StringToSliceHookFunc(\" \"),\n\t\tok: []decodeHookTestCase[string, []string]{\n\t\t\t{\"foo bar baz\", []string{\"foo\", \"bar\", \"baz\"}}, // Basic space separation\n\t\t\t{\"\", []string{}},                         // Empty string\n\t\t\t{\"single\", []string{\"single\"}},           // Single element\n\t\t\t{\"foo  bar\", []string{\"foo\", \"\", \"bar\"}}, // Double space creates empty element\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, []string]{},\n\t}\n\tt.Run(\"SpaceSeparator\", spaceSuite.Run)\n\n\t// Test multi-character separator\n\tmultiCharSuite := decodeHookTestSuite[string, []string]{\n\t\tfn: StringToSliceHookFunc(\"::\"),\n\t\tok: []decodeHookTestCase[string, []string]{\n\t\t\t{\"foo::bar::baz\", []string{\"foo\", \"bar\", \"baz\"}}, // Basic multi-char separation\n\t\t\t{\"\", []string{}},                                 // Empty string\n\t\t\t{\"single\", []string{\"single\"}},                   // Single element\n\t\t\t{\"foo::::bar\", []string{\"foo\", \"\", \"bar\"}},       // Double separator creates empty element\n\t\t\t{\"::foo::bar::\", []string{\"\", \"foo\", \"bar\", \"\"}}, // Leading/trailing separators\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, []string]{},\n\t}\n\tt.Run(\"MultiCharSeparator\", multiCharSuite.Run)\n\n\t// Test edge cases with custom logic for type conversion\n\tt.Run(\"NonStringTypes\", func(t *testing.T) {\n\t\tf := StringToSliceHookFunc(\",\")\n\n\t\t// Test that non-string types are passed through unchanged\n\t\tsliceValue := reflect.ValueOf([]string{\"42\"})\n\t\tactual, err := DecodeHookExec(f, sliceValue, sliceValue)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif !reflect.DeepEqual(actual, []string{\"42\"}) {\n\t\t\tt.Fatalf(\"expected %v, got %v\", []string{\"42\"}, actual)\n\t\t}\n\n\t\t// Test byte slice passthrough\n\t\tbyteValue := reflect.ValueOf([]byte(\"42\"))\n\t\tactual, err = DecodeHookExec(f, byteValue, reflect.ValueOf([]byte{}))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif !reflect.DeepEqual(actual, []byte(\"42\")) {\n\t\t\tt.Fatalf(\"expected %v, got %v\", []byte(\"42\"), actual)\n\t\t}\n\n\t\t// Test string to string passthrough\n\t\tstrValue := reflect.ValueOf(\"42\")\n\t\tactual, err = DecodeHookExec(f, strValue, strValue)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif !reflect.DeepEqual(actual, \"42\") {\n\t\t\tt.Fatalf(\"expected %v, got %v\", \"42\", actual)\n\t\t}\n\t})\n}\n\nfunc TestStringToWeakSliceHookFunc(t *testing.T) {\n\tf := StringToWeakSliceHookFunc(\",\")\n\n\tstrValue := reflect.ValueOf(\"42\")\n\tsliceValue := reflect.ValueOf([]string{\"42\"})\n\tsliceValue2 := reflect.ValueOf([]byte(\"42\"))\n\n\tcases := []struct {\n\t\tf, t   reflect.Value\n\t\tresult any\n\t\terr    bool\n\t}{\n\t\t{sliceValue, sliceValue, []string{\"42\"}, false},\n\t\t{sliceValue2, sliceValue2, []byte(\"42\"), false},\n\t\t{reflect.ValueOf([]byte(\"42\")), reflect.ValueOf([]byte{}), []byte(\"42\"), false},\n\t\t{strValue, strValue, \"42\", false},\n\t\t{\n\t\t\treflect.ValueOf(\"foo,bar,baz\"),\n\t\t\tsliceValue,\n\t\t\t[]string{\"foo\", \"bar\", \"baz\"},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\treflect.ValueOf(\"foo,bar,baz\"),\n\t\t\tsliceValue2,\n\t\t\t[]string{\"foo\", \"bar\", \"baz\"},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\treflect.ValueOf(\"\"),\n\t\t\tsliceValue,\n\t\t\t[]string{},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\treflect.ValueOf(\"\"),\n\t\t\tsliceValue2,\n\t\t\t[]string{},\n\t\t\tfalse,\n\t\t},\n\t}\n\n\tfor i, tc := range cases {\n\t\tactual, err := DecodeHookExec(f, tc.f, tc.t)\n\n\t\tif tc.err != (err != nil) {\n\t\t\tt.Fatalf(\"case %d: expected err %#v\", i, tc.err)\n\t\t}\n\n\t\tif !reflect.DeepEqual(actual, tc.result) {\n\t\t\tt.Fatalf(\n\t\t\t\t\"case %d: expected %#v, got %#v\",\n\t\t\t\ti, tc.result, actual)\n\t\t}\n\t}\n}\n\nfunc TestStringToTimeDurationHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, time.Duration]{\n\t\tfn: StringToTimeDurationHookFunc(),\n\t\tok: []decodeHookTestCase[string, time.Duration]{\n\t\t\t// Basic units\n\t\t\t{\"5s\", 5 * time.Second},            // Seconds\n\t\t\t{\"10ms\", 10 * time.Millisecond},    // Milliseconds\n\t\t\t{\"100us\", 100 * time.Microsecond},  // Microseconds\n\t\t\t{\"1000ns\", 1000 * time.Nanosecond}, // Nanoseconds\n\t\t\t{\"2m\", 2 * time.Minute},            // Minutes\n\t\t\t{\"3h\", 3 * time.Hour},              // Hours\n\t\t\t{\"24h\", 24 * time.Hour},            // Day in hours\n\n\t\t\t// Combinations\n\t\t\t{\"1h30m\", time.Hour + 30*time.Minute},                       // Hour and minutes\n\t\t\t{\"2h45m30s\", 2*time.Hour + 45*time.Minute + 30*time.Second}, // Multiple units\n\t\t\t{\"1m30s\", time.Minute + 30*time.Second},                     // Minutes and seconds\n\t\t\t{\"500ms\", 500 * time.Millisecond},                           // Milliseconds only\n\t\t\t{\"1.5s\", time.Second + 500*time.Millisecond},                // Fractional seconds\n\t\t\t{\"2.5h\", 2*time.Hour + 30*time.Minute},                      // Fractional hours\n\n\t\t\t// Zero values\n\t\t\t{\"0s\", 0},  // Zero seconds\n\t\t\t{\"0ms\", 0}, // Zero milliseconds\n\t\t\t{\"0h\", 0},  // Zero hours\n\t\t\t{\"0\", 0},   // Just zero\n\n\t\t\t// Negative durations\n\t\t\t{\"-5s\", -5 * time.Second},                 // Negative seconds\n\t\t\t{\"-1h30m\", -(time.Hour + 30*time.Minute)}, // Negative combined\n\t\t\t{\"-100ms\", -100 * time.Millisecond},       // Negative milliseconds\n\n\t\t\t// Fractional values\n\t\t\t{\"0.5s\", 500 * time.Millisecond},                     // Half second\n\t\t\t{\"1.25m\", time.Minute + 15*time.Second},              // Fractional minute\n\t\t\t{\"0.1h\", 6 * time.Minute},                            // Fractional hour\n\t\t\t{\"2.5ms\", 2*time.Millisecond + 500*time.Microsecond}, // Fractional millisecond\n\n\t\t\t// Large values\n\t\t\t{\"8760h\", 8760 * time.Hour},               // 1 year in hours\n\t\t\t{\"525600m\", 525600 * time.Minute},         // 1 year in minutes\n\t\t\t{\"1000000us\", 1000000 * time.Microsecond}, // Large microseconds\n\n\t\t\t// Additional valid cases\n\t\t\t{\".5s\", 500 * time.Millisecond},            // Leading decimal is valid\n\t\t\t{\"5µs\", 5 * time.Microsecond},              // Unicode micro symbol is valid\n\t\t\t{\"5.s\", 5 * time.Second},                   // Trailing decimal is valid\n\t\t\t{\"5s5m5s\", 10*time.Second + 5*time.Minute}, // Duplicate units are valid\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, time.Duration]{\n\t\t\t{\"5\"},        // Missing unit\n\t\t\t{\"abc\"},      // Invalid format\n\t\t\t{\"\"},         // Empty string\n\t\t\t{\"5x\"},       // Invalid unit\n\t\t\t{\"5ss\"},      // Double unit letters\n\t\t\t{\"5..5s\"},    // Multiple decimal points\n\t\t\t{\"++5s\"},     // Double plus sign\n\t\t\t{\"--5s\"},     // Double minus sign\n\t\t\t{\" 5s \"},     // Leading/trailing whitespace not handled\n\t\t\t{\"\\t10ms\\n\"}, // Tab/newline whitespace not handled\n\t\t\t{\"\\r1h\\r\"},   // Carriage return whitespace not handled\n\t\t\t{\"5s \"},      // Trailing space after unit\n\t\t\t{\" 5 s\"},     // Space before unit\n\t\t\t{\"5 s 10 m\"}, // Spaces in combined duration\n\t\t\t{\"∞s\"},       // Unicode infinity symbol\n\t\t\t{\"1y\"},       // Unsupported unit (years)\n\t\t\t{\"1w\"},       // Unsupported unit (weeks)\n\t\t\t{\"1d\"},       // Unsupported unit (days)\n\t\t},\n\t}\n\n\t// Test non-string and non-duration type passthrough\n\tt.Run(\"Passthrough\", func(t *testing.T) {\n\t\tf := StringToTimeDurationHookFunc()\n\n\t\t// Non-string type should pass through\n\t\tintValue := reflect.ValueOf(42)\n\t\tactual, err := DecodeHookExec(f, intValue, reflect.ValueOf(time.Duration(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif actual != 42 {\n\t\t\tt.Fatalf(\"expected 42, got %v\", actual)\n\t\t}\n\n\t\t// Non-duration target type should pass through\n\t\tstrValue := reflect.ValueOf(\"5s\")\n\t\tactual, err = DecodeHookExec(f, strValue, strValue)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif actual != \"5s\" {\n\t\t\tt.Fatalf(\"expected '5s', got %v\", actual)\n\t\t}\n\t})\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToTimeLocationHookFunc(t *testing.T) {\n\tnewYork, _ := time.LoadLocation(\"America/New_York\")\n\tlondon, _ := time.LoadLocation(\"Europe/London\")\n\ttehran, _ := time.LoadLocation(\"Asia/Tehran\")\n\tshanghai, _ := time.LoadLocation(\"Asia/Shanghai\")\n\n\tsuite := decodeHookTestSuite[string, *time.Location]{\n\t\tfn: StringToTimeLocationHookFunc(),\n\t\tok: []decodeHookTestCase[string, *time.Location]{\n\t\t\t{\"UTC\", time.UTC},\n\t\t\t{\"Local\", time.Local},\n\t\t\t{\"America/New_York\", newYork},\n\t\t\t{\"Europe/London\", london},\n\t\t\t{\"Asia/Tehran\", tehran},\n\t\t\t{\"Asia/Shanghai\", shanghai},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, *time.Location]{\n\t\t\t{\"UTC2\"},           // Non-existent\n\t\t\t{\"5s\"},             // Duration-like, not a zone\n\t\t\t{\"Europe\\\\London\"}, // Invalid path separator\n\t\t\t{\"../etc/passwd\"},  // Unsafe path\n\t\t\t{\"/etc/zoneinfo\"},  // Absolute path (rejected by stdlib)\n\t\t\t{\"Asia\\\\Tehran\"},   // Invalid Windows-style path\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToURLHookFunc(t *testing.T) {\n\thttpURL, _ := url.Parse(\"http://example.com\")\n\thttpsURL, _ := url.Parse(\"https://example.com\")\n\tftpURL, _ := url.Parse(\"ftp://ftp.example.com\")\n\tfileURL, _ := url.Parse(\"file:///path/to/file\")\n\tcomplexURL, _ := url.Parse(\"https://user:pass@example.com:8080/path?query=value&foo=bar#fragment\")\n\tipURL, _ := url.Parse(\"http://192.168.1.1:8080\")\n\tipv6URL, _ := url.Parse(\"http://[::1]:8080\")\n\temptyURL, _ := url.Parse(\"\")\n\n\tsuite := decodeHookTestSuite[string, *url.URL]{\n\t\tfn: StringToURLHookFunc(),\n\t\tok: []decodeHookTestCase[string, *url.URL]{\n\t\t\t{\"http://example.com\", httpURL},   // Basic HTTP URL\n\t\t\t{\"https://example.com\", httpsURL}, // HTTPS URL\n\t\t\t{\"ftp://ftp.example.com\", ftpURL}, // FTP URL\n\t\t\t{\"file:///path/to/file\", fileURL}, // File URL\n\t\t\t{\"https://user:pass@example.com:8080/path?query=value&foo=bar#fragment\", complexURL}, // Complex URL with all components\n\t\t\t{\"http://192.168.1.1:8080\", ipURL},                                                   // IPv4 address with port\n\t\t\t{\"http://[::1]:8080\", ipv6URL},                                                       // IPv6 address with port\n\t\t\t{\"\", emptyURL},                                                                       // Empty URL\n\t\t\t// Additional valid cases that url.Parse accepts\n\t\t\t{\"http://\", func() *url.URL { u, _ := url.Parse(\"http://\"); return u }()},                                   // Scheme with empty host\n\t\t\t{\"http://example.com:99999\", func() *url.URL { u, _ := url.Parse(\"http://example.com:99999\"); return u }()}, // High port number\n\t\t\t{\"not a url at all\", func() *url.URL { u, _ := url.Parse(\"not a url at all\"); return u }()},                 // Relative path (valid)\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, *url.URL]{\n\t\t\t{\"http ://example.com\"},  // Space in scheme\n\t\t\t{\"://invalid\"},           // Missing scheme\n\t\t\t{\"http://[invalid:ipv6\"}, // Malformed IPv6 bracket\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToTimeHookFunc(t *testing.T) {\n\tstrValue := reflect.ValueOf(\"5\")\n\ttimeValue := reflect.ValueOf(time.Time{})\n\tcases := []struct {\n\t\tf, t   reflect.Value\n\t\tlayout string\n\t\tresult any\n\t\terr    bool\n\t}{\n\t\t{\n\t\t\treflect.ValueOf(\"2006-01-02T15:04:05Z\"), timeValue, time.RFC3339,\n\t\t\ttime.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), false,\n\t\t},\n\t\t{strValue, timeValue, time.RFC3339, time.Time{}, true},\n\t\t{strValue, strValue, time.RFC3339, \"5\", false},\n\t}\n\n\tfor i, tc := range cases {\n\t\tf := StringToTimeHookFunc(tc.layout)\n\t\tactual, err := DecodeHookExec(f, tc.f, tc.t)\n\t\tif tc.err != (err != nil) {\n\t\t\tt.Fatalf(\"case %d: expected err %#v\", i, tc.err)\n\t\t}\n\t\tif !reflect.DeepEqual(actual, tc.result) {\n\t\t\tt.Fatalf(\n\t\t\t\t\"case %d: expected %#v, got %#v\",\n\t\t\t\ti, tc.result, actual)\n\t\t}\n\t}\n}\n\nfunc TestStringToIPHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, net.IP]{\n\t\tfn: StringToIPHookFunc(),\n\t\tok: []decodeHookTestCase[string, net.IP]{\n\t\t\t// IPv4 addresses\n\t\t\t{\"1.2.3.4\", net.IPv4(0x01, 0x02, 0x03, 0x04)},     // Basic IPv4\n\t\t\t{\"192.168.1.1\", net.IPv4(192, 168, 1, 1)},         // Private network address\n\t\t\t{\"0.0.0.0\", net.IPv4(0, 0, 0, 0)},                 // Zero address\n\t\t\t{\"255.255.255.255\", net.IPv4(255, 255, 255, 255)}, // Broadcast address\n\t\t\t{\"127.0.0.1\", net.IPv4(127, 0, 0, 1)},             // Localhost\n\t\t\t{\"10.0.0.1\", net.IPv4(10, 0, 0, 1)},               // Private network\n\t\t\t// IPv6 addresses\n\t\t\t{\"::1\", net.ParseIP(\"::1\")},                 // IPv6 localhost\n\t\t\t{\"2001:db8::1\", net.ParseIP(\"2001:db8::1\")}, // Documentation address\n\t\t\t{\"fe80::1\", net.ParseIP(\"fe80::1\")},         // Link-local address\n\t\t\t{\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\", net.ParseIP(\"2001:0db8:85a3:0000:0000:8a2e:0370:7334\")}, // Full IPv6 address\n\t\t\t{\"2001:db8:85a3::8a2e:370:7334\", net.ParseIP(\"2001:db8:85a3::8a2e:370:7334\")},                       // Compressed IPv6\n\t\t\t{\"::\", net.ParseIP(\"::\")},                             // IPv6 zero address\n\t\t\t{\"::ffff:192.0.2.1\", net.ParseIP(\"::ffff:192.0.2.1\")}, // IPv4-mapped IPv6\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, net.IP]{\n\t\t\t{\"5\"},                 // Single number\n\t\t\t{\"256.1.1.1\"},         // IPv4 octet too large\n\t\t\t{\"1.2.3\"},             // Too few IPv4 octets\n\t\t\t{\"1.2.3.4.5\"},         // Too many IPv4 octets\n\t\t\t{\"not.an.ip.address\"}, // Non-numeric text\n\t\t\t{\"\"},                  // Empty string\n\t\t\t{\"192.168.1.256\"},     // Last octet too large\n\t\t\t{\"192.168.-1.1\"},      // Negative octet\n\t\t\t{\"gggg::1\"},           // Invalid hex in IPv6\n\t\t\t{\"2001:db8::1::2\"},    // Double :: in IPv6\n\t\t\t{\"[::1]\"},             // IPv6 with brackets (not raw IP)\n\t\t\t{\"192.168.1.1:8080\"},  // IPv4 with port\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToIPNetHookFunc(t *testing.T) {\n\tstrValue := reflect.ValueOf(\"5\")\n\tipNetValue := reflect.ValueOf(net.IPNet{})\n\tvar nilNet *net.IPNet = nil\n\n\tcases := []struct {\n\t\tf, t   reflect.Value\n\t\tresult any\n\t\terr    bool\n\t}{\n\t\t{\n\t\t\treflect.ValueOf(\"1.2.3.4/24\"), ipNetValue,\n\t\t\t&net.IPNet{\n\t\t\t\tIP:   net.IP{0x01, 0x02, 0x03, 0x00},\n\t\t\t\tMask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),\n\t\t\t}, false,\n\t\t},\n\t\t{strValue, ipNetValue, nilNet, true},\n\t\t{strValue, strValue, \"5\", false},\n\t}\n\n\tfor i, tc := range cases {\n\t\tf := StringToIPNetHookFunc()\n\t\tactual, err := DecodeHookExec(f, tc.f, tc.t)\n\t\tif tc.err != (err != nil) {\n\t\t\tt.Fatalf(\"case %d: expected err %#v\", i, tc.err)\n\t\t}\n\t\tif !reflect.DeepEqual(actual, tc.result) {\n\t\t\tt.Fatalf(\n\t\t\t\t\"case %d: expected %#v, got %#v\",\n\t\t\t\ti, tc.result, actual)\n\t\t}\n\t}\n}\n\nfunc TestWeaklyTypedHook(t *testing.T) {\n\tvar f DecodeHookFunc = WeaklyTypedHook\n\n\tstrValue := reflect.ValueOf(\"\")\n\tcases := []struct {\n\t\tf, t   reflect.Value\n\t\tresult any\n\t\terr    bool\n\t}{\n\t\t// TO STRING\n\t\t{\n\t\t\treflect.ValueOf(false),\n\t\t\tstrValue,\n\t\t\t\"0\", // bool false converts to \"0\"\n\t\t\tfalse,\n\t\t},\n\n\t\t{\n\t\t\treflect.ValueOf(true),\n\t\t\tstrValue,\n\t\t\t\"1\", // bool true converts to \"1\"\n\t\t\tfalse,\n\t\t},\n\n\t\t{\n\t\t\treflect.ValueOf(float32(7)),\n\t\t\tstrValue,\n\t\t\t\"7\", // float32 converts to string\n\t\t\tfalse,\n\t\t},\n\n\t\t{\n\t\t\treflect.ValueOf(int(7)),\n\t\t\tstrValue,\n\t\t\t\"7\", // int converts to string\n\t\t\tfalse,\n\t\t},\n\n\t\t{\n\t\t\treflect.ValueOf([]uint8(\"foo\")),\n\t\t\tstrValue,\n\t\t\t\"foo\", // byte slice converts to string\n\t\t\tfalse,\n\t\t},\n\n\t\t{\n\t\t\treflect.ValueOf(uint(7)),\n\t\t\tstrValue,\n\t\t\t\"7\", // uint converts to string\n\t\t\tfalse,\n\t\t},\n\t}\n\n\tfor i, tc := range cases {\n\t\tactual, err := DecodeHookExec(f, tc.f, tc.t)\n\t\tif tc.err != (err != nil) {\n\t\t\tt.Fatalf(\"case %d: expected err %#v\", i, tc.err)\n\t\t}\n\t\tif !reflect.DeepEqual(actual, tc.result) {\n\t\t\tt.Fatalf(\n\t\t\t\t\"case %d: expected %#v, got %#v\",\n\t\t\t\ti, tc.result, actual)\n\t\t}\n\t}\n}\n\nfunc TestStructToMapHookFuncTabled(t *testing.T) {\n\tvar f DecodeHookFunc = RecursiveStructToMapHookFunc()\n\n\ttype b struct {\n\t\tTestKey string\n\t}\n\n\ttype a struct {\n\t\tSub b\n\t}\n\n\ttestStruct := a{\n\t\tSub: b{\n\t\t\tTestKey: \"testval\",\n\t\t},\n\t}\n\n\ttestMap := map[string]any{\n\t\t\"Sub\": map[string]any{\n\t\t\t\"TestKey\": \"testval\",\n\t\t},\n\t}\n\n\tcases := []struct {\n\t\tname     string\n\t\treceiver any\n\t\tinput    any\n\t\texpected any\n\t\terr      bool\n\t}{\n\t\t{\n\t\t\t\"map receiver\",\n\t\t\tfunc() any {\n\t\t\t\tvar res map[string]any\n\t\t\t\treturn &res\n\t\t\t}(),\n\t\t\ttestStruct,\n\t\t\t&testMap,\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"interface receiver\",\n\t\t\tfunc() any {\n\t\t\t\tvar res any\n\t\t\t\treturn &res\n\t\t\t}(),\n\t\t\ttestStruct,\n\t\t\tfunc() any {\n\t\t\t\tvar exp any = testMap\n\t\t\t\treturn &exp\n\t\t\t}(),\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"slice receiver errors\",\n\t\t\tfunc() any {\n\t\t\t\tvar res []string\n\t\t\t\treturn &res\n\t\t\t}(),\n\t\t\ttestStruct,\n\t\t\tnew([]string),\n\t\t\ttrue,\n\t\t},\n\t\t{\n\t\t\t\"slice to slice - no change\",\n\t\t\tfunc() any {\n\t\t\t\tvar res []string\n\t\t\t\treturn &res\n\t\t\t}(),\n\t\t\t[]string{\"a\", \"b\"},\n\t\t\t&[]string{\"a\", \"b\"},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"string to string - no change\",\n\t\t\tfunc() any {\n\t\t\t\tvar res string\n\t\t\t\treturn &res\n\t\t\t}(),\n\t\t\t\"test\",\n\t\t\tfunc() *string {\n\t\t\t\ts := \"test\"\n\t\t\t\treturn &s\n\t\t\t}(),\n\t\t\tfalse,\n\t\t},\n\t}\n\n\tfor _, tc := range cases {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tcfg := &DecoderConfig{\n\t\t\t\tDecodeHook: f,\n\t\t\t\tResult:     tc.receiver,\n\t\t\t}\n\n\t\t\td, err := NewDecoder(cfg)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"unexpected err %#v\", err)\n\t\t\t}\n\n\t\t\terr = d.Decode(tc.input)\n\t\t\tif tc.err != (err != nil) {\n\t\t\t\tt.Fatalf(\"expected err %#v\", err)\n\t\t\t}\n\n\t\t\tif !reflect.DeepEqual(tc.expected, tc.receiver) {\n\t\t\t\tt.Fatalf(\"expected %#v, got %#v\",\n\t\t\t\t\ttc.expected, tc.receiver)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestTextUnmarshallerHookFunc(t *testing.T) {\n\ttype MyString string\n\n\tcases := []struct {\n\t\tf, t   reflect.Value\n\t\tresult any\n\t\terr    bool\n\t}{\n\t\t{reflect.ValueOf(\"42\"), reflect.ValueOf(big.Int{}), big.NewInt(42), false},\n\t\t{reflect.ValueOf(\"invalid\"), reflect.ValueOf(big.Int{}), nil, true},\n\t\t{reflect.ValueOf(\"5\"), reflect.ValueOf(\"5\"), \"5\", false},\n\t\t{reflect.ValueOf(json.Number(\"42\")), reflect.ValueOf(big.Int{}), big.NewInt(42), false},\n\t\t{reflect.ValueOf(MyString(\"42\")), reflect.ValueOf(big.Int{}), big.NewInt(42), false},\n\t}\n\tfor i, tc := range cases {\n\t\tf := TextUnmarshallerHookFunc()\n\t\tactual, err := DecodeHookExec(f, tc.f, tc.t)\n\t\tif tc.err != (err != nil) {\n\t\t\tt.Fatalf(\"case %d: expected err %#v\", i, tc.err)\n\t\t}\n\t\tif !reflect.DeepEqual(actual, tc.result) {\n\t\t\tt.Fatalf(\n\t\t\t\t\"case %d: expected %#v, got %#v\",\n\t\t\t\ti, tc.result, actual)\n\t\t}\n\t}\n}\n\nfunc TestStringToNetIPAddrHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, netip.Addr]{\n\t\tfn: StringToNetIPAddrHookFunc(),\n\t\tok: []decodeHookTestCase[string, netip.Addr]{\n\t\t\t// IPv4 addresses\n\t\t\t{\"192.0.2.1\", netip.AddrFrom4([4]byte{0xc0, 0x00, 0x02, 0x01})},   // Documentation address\n\t\t\t{\"127.0.0.1\", netip.AddrFrom4([4]byte{127, 0, 0, 1})},             // Localhost\n\t\t\t{\"0.0.0.0\", netip.AddrFrom4([4]byte{0, 0, 0, 0})},                 // Zero address\n\t\t\t{\"255.255.255.255\", netip.AddrFrom4([4]byte{255, 255, 255, 255})}, // Broadcast address\n\t\t\t{\"10.0.0.1\", netip.AddrFrom4([4]byte{10, 0, 0, 1})},               // Private network\n\t\t\t{\"192.168.1.100\", netip.AddrFrom4([4]byte{192, 168, 1, 100})},     // Private network\n\t\t\t// IPv6 addresses\n\t\t\t{\"::1\", netip.AddrFrom16([16]byte{15: 1})},                                               // IPv6 localhost\n\t\t\t{\"2001:db8::1\", netip.AddrFrom16([16]byte{0x20, 0x01, 0x0d, 0xb8, 12: 0, 0, 0, 1})},      // Documentation address\n\t\t\t{\"fe80::1\", netip.AddrFrom16([16]byte{0xfe, 0x80, 14: 0, 1})},                            // Link-local address\n\t\t\t{\"::\", netip.AddrFrom16([16]byte{})},                                                     // IPv6 zero address\n\t\t\t{\"::ffff:192.0.2.1\", netip.AddrFrom16([16]byte{10: 0xff, 0xff, 0xc0, 0x00, 0x02, 0x01})}, // IPv4-mapped IPv6\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, netip.Addr]{\n\t\t\t{\"5\"},                 // Single number\n\t\t\t{\"256.1.1.1\"},         // IPv4 octet too large\n\t\t\t{\"1.2.3\"},             // Too few IPv4 octets\n\t\t\t{\"1.2.3.4.5\"},         // Too many IPv4 octets\n\t\t\t{\"not.an.ip.address\"}, // Non-numeric text\n\t\t\t{\"\"},                  // Empty string\n\t\t\t{\"192.168.1.256\"},     // Last octet too large\n\t\t\t{\"192.168.-1.1\"},      // Negative octet\n\t\t\t{\"gggg::1\"},           // Invalid hex in IPv6\n\t\t\t{\"2001:db8::1::2\"},    // Double :: in IPv6\n\t\t\t{\"[::1]\"},             // IPv6 with brackets\n\t\t\t{\"192.168.1.1:8080\"},  // IPv4 with port\n\t\t\t{\"192.168.1.1/24\"},    // IPv4 with CIDR\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToNetIPAddrPortHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, netip.AddrPort]{\n\t\tfn: StringToNetIPAddrPortHookFunc(),\n\t\tok: []decodeHookTestCase[string, netip.AddrPort]{\n\t\t\t// IPv4 with ports\n\t\t\t{\"192.0.2.1:80\", netip.AddrPortFrom(netip.AddrFrom4([4]byte{0xc0, 0x00, 0x02, 0x01}), 80)},         // HTTP port\n\t\t\t{\"127.0.0.1:8080\", netip.AddrPortFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 8080)},               // Alternative HTTP port\n\t\t\t{\"10.0.0.1:443\", netip.AddrPortFrom(netip.AddrFrom4([4]byte{10, 0, 0, 1}), 443)},                   // HTTPS port\n\t\t\t{\"192.168.1.100:22\", netip.AddrPortFrom(netip.AddrFrom4([4]byte{192, 168, 1, 100}), 22)},           // SSH port\n\t\t\t{\"0.0.0.0:0\", netip.AddrPortFrom(netip.AddrFrom4([4]byte{0, 0, 0, 0}), 0)},                         // Zero address and port\n\t\t\t{\"255.255.255.255:65535\", netip.AddrPortFrom(netip.AddrFrom4([4]byte{255, 255, 255, 255}), 65535)}, // Max address and port\n\t\t\t// IPv6 with ports\n\t\t\t{\"[::1]:80\", netip.AddrPortFrom(netip.AddrFrom16([16]byte{15: 1}), 80)},                                               // IPv6 localhost with HTTP\n\t\t\t{\"[2001:db8::1]:443\", netip.AddrPortFrom(netip.AddrFrom16([16]byte{0x20, 0x01, 0x0d, 0xb8, 12: 0, 0, 0, 1}), 443)},    // Documentation address with HTTPS\n\t\t\t{\"[fe80::1]:8080\", netip.AddrPortFrom(netip.AddrFrom16([16]byte{0xfe, 0x80, 14: 0, 1}), 8080)},                        // Link-local with alt HTTP\n\t\t\t{\"[::]:22\", netip.AddrPortFrom(netip.AddrFrom16([16]byte{}), 22)},                                                     // IPv6 zero address with SSH\n\t\t\t{\"[::ffff:192.0.2.1]:80\", netip.AddrPortFrom(netip.AddrFrom16([16]byte{10: 0xff, 0xff, 0xc0, 0x00, 0x02, 0x01}), 80)}, // IPv4-mapped IPv6 with HTTP\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, netip.AddrPort]{\n\t\t\t{\"5\"},                  // Just a number\n\t\t\t{\"192.168.1.1\"},        // Missing port\n\t\t\t{\"192.168.1.1:\"},       // Empty port\n\t\t\t{\"192.168.1.1:65536\"},  // Port too large\n\t\t\t{\"192.168.1.1:-1\"},     // Negative port\n\t\t\t{\"192.168.1.1:abc\"},    // Non-numeric port\n\t\t\t{\"256.1.1.1:80\"},       // Invalid IP\n\t\t\t{\"::1:80\"},             // IPv6 without brackets\n\t\t\t{\"[::1\"},               // Missing closing bracket\n\t\t\t{\"::1]:80\"},            // Missing opening bracket\n\t\t\t{\"[invalid::ip]:80\"},   // Invalid IPv6\n\t\t\t{\"\"},                   // Empty string\n\t\t\t{\":80\"},                // Missing IP\n\t\t\t{\"192.168.1.1:80:443\"}, // Multiple ports\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToNetIPPrefixHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, netip.Prefix]{\n\t\tfn: StringToNetIPPrefixHookFunc(),\n\t\tok: []decodeHookTestCase[string, netip.Prefix]{\n\t\t\t// IPv4 CIDR notation\n\t\t\t{\"192.0.2.1/24\", netip.PrefixFrom(netip.AddrFrom4([4]byte{0xc0, 0x00, 0x02, 0x01}), 24)},   // Documentation network\n\t\t\t{\"127.0.0.1/32\", netip.PrefixFrom(netip.AddrFrom4([4]byte{127, 0, 0, 1}), 32)},             // Localhost single host\n\t\t\t{\"10.0.0.0/8\", netip.PrefixFrom(netip.AddrFrom4([4]byte{10, 0, 0, 0}), 8)},                 // Class A private network\n\t\t\t{\"192.168.1.0/24\", netip.PrefixFrom(netip.AddrFrom4([4]byte{192, 168, 1, 0}), 24)},         // Class C private network\n\t\t\t{\"172.16.0.0/12\", netip.PrefixFrom(netip.AddrFrom4([4]byte{172, 16, 0, 0}), 12)},           // Class B private network\n\t\t\t{\"0.0.0.0/0\", netip.PrefixFrom(netip.AddrFrom4([4]byte{0, 0, 0, 0}), 0)},                   // Default route\n\t\t\t{\"255.255.255.255/32\", netip.PrefixFrom(netip.AddrFrom4([4]byte{255, 255, 255, 255}), 32)}, // Broadcast single host\n\t\t\t{\"192.168.1.1/30\", netip.PrefixFrom(netip.AddrFrom4([4]byte{192, 168, 1, 1}), 30)},         // Point-to-point subnet\n\t\t\t// IPv6 CIDR notation\n\t\t\t{\"fd7a:115c::626b:430b/118\", netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfd, 0x7a, 0x11, 0x5c, 12: 0x62, 0x6b, 0x43, 0x0b}), 118)}, // ULA with specific prefix\n\t\t\t{\"2001:db8::/32\", netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x01, 0x0d, 0xb8}), 32)},                                         // Documentation network\n\t\t\t{\"::1/128\", netip.PrefixFrom(netip.AddrFrom16([16]byte{15: 1}), 128)},                                                               // IPv6 localhost single host\n\t\t\t{\"::/0\", netip.PrefixFrom(netip.AddrFrom16([16]byte{}), 0)},                                                                         // IPv6 default route\n\t\t\t{\"fe80::/10\", netip.PrefixFrom(netip.AddrFrom16([16]byte{0xfe, 0x80}), 10)},                                                         // Link-local network\n\t\t\t{\"2001:db8::1/64\", netip.PrefixFrom(netip.AddrFrom16([16]byte{0x20, 0x01, 0x0d, 0xb8, 12: 0, 0, 0, 1}), 64)},                        // Standard IPv6 subnet\n\t\t\t{\"::ffff:0:0/96\", netip.PrefixFrom(netip.AddrFrom16([16]byte{10: 0xff, 0xff}), 96)},                                                 // IPv4-mapped IPv6 prefix\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, netip.Prefix]{\n\t\t\t{\"5\"},                // Just a number\n\t\t\t{\"192.168.1.1\"},      // Missing prefix length\n\t\t\t{\"192.168.1.1/\"},     // Empty prefix length\n\t\t\t{\"192.168.1.1/33\"},   // IPv4 prefix too large\n\t\t\t{\"192.168.1.1/-1\"},   // Negative prefix\n\t\t\t{\"192.168.1.1/abc\"},  // Non-numeric prefix\n\t\t\t{\"256.1.1.1/24\"},     // Invalid IP\n\t\t\t{\"::1/129\"},          // IPv6 prefix too large\n\t\t\t{\"invalid::ip/64\"},   // Invalid IPv6\n\t\t\t{\"\"},                 // Empty string\n\t\t\t{\"/24\"},              // Missing IP\n\t\t\t{\"192.168.1.1/24/8\"}, // Multiple prefixes\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToBasicTypeHookFunc(t *testing.T) {\n\tstrValue := reflect.ValueOf(\"42\")\n\n\tcases := []struct {\n\t\tf, t   reflect.Value\n\t\tresult any\n\t\terr    bool\n\t}{\n\t\t{strValue, strValue, \"42\", false},\n\t\t{strValue, reflect.ValueOf(int8(0)), int8(42), false},\n\t\t{strValue, reflect.ValueOf(uint8(0)), uint8(42), false},\n\t\t{strValue, reflect.ValueOf(int16(0)), int16(42), false},\n\t\t{strValue, reflect.ValueOf(uint16(0)), uint16(42), false},\n\t\t{strValue, reflect.ValueOf(int32(0)), int32(42), false},\n\t\t{strValue, reflect.ValueOf(uint32(0)), uint32(42), false},\n\t\t{strValue, reflect.ValueOf(int64(0)), int64(42), false},\n\t\t{strValue, reflect.ValueOf(uint64(0)), uint64(42), false},\n\t\t{strValue, reflect.ValueOf(int(0)), int(42), false},\n\t\t{strValue, reflect.ValueOf(uint(0)), uint(42), false},\n\t\t{strValue, reflect.ValueOf(float32(0)), float32(42), false},\n\t\t{strValue, reflect.ValueOf(float64(0)), float64(42), false},\n\t\t{reflect.ValueOf(\"true\"), reflect.ValueOf(bool(false)), true, false},\n\t\t{strValue, reflect.ValueOf(byte(0)), byte(42), false},\n\t\t{strValue, reflect.ValueOf(rune(0)), rune(42), false},\n\t\t{strValue, reflect.ValueOf(complex64(0)), complex64(42), false},\n\t\t{strValue, reflect.ValueOf(complex128(0)), complex128(42), false},\n\t}\n\n\tfor i, tc := range cases {\n\t\tf := StringToBasicTypeHookFunc()\n\t\tactual, err := DecodeHookExec(f, tc.f, tc.t)\n\t\tif tc.err != (err != nil) {\n\t\t\tt.Fatalf(\"case %d: expected err %#v\", i, tc.err)\n\t\t}\n\t\tif !tc.err && !reflect.DeepEqual(actual, tc.result) {\n\t\t\tt.Fatalf(\n\t\t\t\t\"case %d: expected %#v, got %#v\",\n\t\t\t\ti, tc.result, actual)\n\t\t}\n\t}\n}\n\nfunc TestStringToInt8HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, int8]{\n\t\tfn: StringToInt8HookFunc(),\n\t\tok: []decodeHookTestCase[string, int8]{\n\t\t\t{\"42\", 42},             // Basic positive decimal\n\t\t\t{\"-42\", int8(-42)},     // Basic negative decimal\n\t\t\t{\"0b101010\", int8(42)}, // Binary notation\n\t\t\t{\"052\", int8(42)},      // Octal notation (legacy)\n\t\t\t{\"0o52\", int8(42)},     // Octal notation (modern)\n\t\t\t{\"0x2a\", int8(42)},     // Hex notation (lowercase)\n\t\t\t{\"0X2A\", int8(42)},     // Hex notation (uppercase)\n\t\t\t{\"0\", int8(0)},         // Zero\n\t\t\t{\"+42\", int8(42)},      // Explicit positive sign\n\t\t\t// Boundary values\n\t\t\t{\"127\", int8(127)},          // Max value\n\t\t\t{\"-128\", int8(-128)},        // Min value\n\t\t\t{\"0x7F\", int8(127)},         // Max value in hex\n\t\t\t{\"-0x80\", int8(-128)},       // Min value in hex\n\t\t\t{\"0177\", int8(127)},         // Max value in octal\n\t\t\t{\"-0200\", int8(-128)},       // Min value in octal\n\t\t\t{\"0b01111111\", int8(127)},   // Max value in binary\n\t\t\t{\"-0b10000000\", int8(-128)}, // Min value in binary\n\t\t\t// Zero variants\n\t\t\t{\"+0\", int8(0)},  // Explicit positive zero\n\t\t\t{\"-0\", int8(0)},  // Explicit negative zero\n\t\t\t{\"00\", int8(0)},  // Leading zero\n\t\t\t{\"0x0\", int8(0)}, // Hex zero\n\t\t\t{\"0b0\", int8(0)}, // Binary zero\n\t\t\t{\"0o0\", int8(0)}, // Octal zero\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, int8]{\n\t\t\t{strings.Repeat(\"42\", 42)}, // Very long number string\n\t\t\t{\"128\"},                    // Overflow\n\t\t\t{\"-129\"},                   // Underflow\n\t\t\t{\"256\"},                    // Way over max\n\t\t\t{\"-256\"},                   // Way under min\n\t\t\t{\"42.5\"},                   // Float\n\t\t\t{\"abc\"},                    // Non-numeric\n\t\t\t{\"\"},                       // Empty string\n\t\t\t{\" 42 \"},                   // Whitespace not handled by strconv\n\t\t\t{\"\\t42\\n\"},                 // Whitespace not handled by strconv\n\t\t\t{\"\\r42\\r\"},                 // Whitespace not handled by strconv\n\t\t\t{\"0x\"},                     // Invalid hex\n\t\t\t{\"0b\"},                     // Invalid binary\n\t\t\t{\"0o\"},                     // Invalid octal\n\t\t\t{\"++42\"},                   // Double plus\n\t\t\t{\"--42\"},                   // Double minus\n\t\t\t{\"42abc\"},                  // Trailing non-numeric\n\t\t\t{\"abc42\"},                  // Leading non-numeric\n\t\t\t{\"42 43\"},                  // Multiple numbers\n\t\t\t{\"0x10000\"},                // Hex overflow\n\t\t\t{\"-0x10001\"},               // Hex underflow\n\t\t\t{\"0777\"},                   // Octal overflow\n\t\t\t{\"-01000\"},                 // Octal underflow\n\t\t\t{\"0b100000000\"},            // Binary overflow\n\t\t\t{\"-0b100000001\"},           // Binary underflow\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToUint8HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, uint8]{\n\t\tfn: StringToUint8HookFunc(),\n\t\tok: []decodeHookTestCase[string, uint8]{\n\t\t\t{\"42\", 42},              // Basic decimal\n\t\t\t{\"0b101010\", uint8(42)}, // Binary notation\n\t\t\t{\"052\", uint8(42)},      // Octal notation (legacy)\n\t\t\t{\"0o52\", uint8(42)},     // Octal notation (modern)\n\t\t\t{\"0x2a\", uint8(42)},     // Hex notation (lowercase)\n\t\t\t{\"0X2A\", uint8(42)},     // Hex notation (uppercase)\n\t\t\t{\"0\", uint8(0)},         // Zero\n\n\t\t\t// Boundary values\n\t\t\t{\"255\", uint8(255)},        // Max value\n\t\t\t{\"0xFF\", uint8(255)},       // Max value in hex\n\t\t\t{\"0377\", uint8(255)},       // Max value in octal\n\t\t\t{\"0b11111111\", uint8(255)}, // Max value in binary\n\t\t\t{\"1\", uint8(1)},            // Min positive value\n\t\t\t// Zero variants\n\n\t\t\t{\"00\", uint8(0)},  // Leading zero\n\t\t\t{\"0x0\", uint8(0)}, // Hex zero\n\t\t\t{\"0b0\", uint8(0)}, // Binary zero\n\t\t\t{\"0o0\", uint8(0)}, // Octal zero\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, uint8]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"256\"},         // Overflow\n\t\t\t{\"512\"},         // Way over max\n\t\t\t{\"42.5\"},        // Float\n\t\t\t{\"abc\"},         // Non-numeric\n\t\t\t{\"\"},            // Empty string\n\t\t\t{\"-1\"},          // Negative number\n\t\t\t{\"-42\"},         // Negative number\n\t\t\t{\"0x\"},          // Invalid hex\n\t\t\t{\"0b\"},          // Invalid binary\n\t\t\t{\"0o\"},          // Invalid octal\n\t\t\t{\"++42\"},        // Double plus\n\t\t\t{\" 42 \"},        // Whitespace not handled by strconv\n\t\t\t{\"\\t42\\n\"},      // Whitespace not handled by strconv\n\t\t\t{\"\\r42\\r\"},      // Whitespace not handled by strconv\n\t\t\t{\"42abc\"},       // Trailing non-numeric\n\t\t\t{\"abc42\"},       // Leading non-numeric\n\t\t\t{\"42 43\"},       // Multiple numbers\n\t\t\t{\"0x100\"},       // Hex overflow\n\t\t\t{\"0400\"},        // Octal overflow\n\t\t\t{\"0b100000000\"}, // Binary overflow\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToInt16HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, int16]{\n\t\tfn: StringToInt16HookFunc(),\n\t\tok: []decodeHookTestCase[string, int16]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"-42\", int16(-42)},\n\t\t\t{\"0b101010\", int16(42)},\n\t\t\t{\"052\", int16(42)},\n\t\t\t{\"0o52\", int16(42)},\n\t\t\t{\"0x2a\", int16(42)},\n\t\t\t{\"0X2A\", int16(42)},\n\t\t\t{\"0\", int16(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, int16]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToUint16HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, uint16]{\n\t\tfn: StringToUint16HookFunc(),\n\t\tok: []decodeHookTestCase[string, uint16]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"0b101010\", uint16(42)},\n\t\t\t{\"052\", uint16(42)},\n\t\t\t{\"0o52\", uint16(42)},\n\t\t\t{\"0x2a\", uint16(42)},\n\t\t\t{\"0X2A\", uint16(42)},\n\t\t\t{\"0\", uint16(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, uint16]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"-42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToInt32HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, int32]{\n\t\tfn: StringToInt32HookFunc(),\n\t\tok: []decodeHookTestCase[string, int32]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"-42\", int32(-42)},\n\t\t\t{\"0b101010\", int32(42)},\n\t\t\t{\"052\", int32(42)},\n\t\t\t{\"0o52\", int32(42)},\n\t\t\t{\"0x2a\", int32(42)},\n\t\t\t{\"0X2A\", int32(42)},\n\t\t\t{\"0\", int32(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, int32]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToUint32HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, uint32]{\n\t\tfn: StringToUint32HookFunc(),\n\t\tok: []decodeHookTestCase[string, uint32]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"0b101010\", uint32(42)},\n\t\t\t{\"052\", uint32(42)},\n\t\t\t{\"0o52\", uint32(42)},\n\t\t\t{\"0x2a\", uint32(42)},\n\t\t\t{\"0X2A\", uint32(42)},\n\t\t\t{\"0\", uint32(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, uint32]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"-42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToInt64HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, int64]{\n\t\tfn: StringToInt64HookFunc(),\n\t\tok: []decodeHookTestCase[string, int64]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"-42\", int64(-42)},\n\t\t\t{\"0b101010\", int64(42)},\n\t\t\t{\"052\", int64(42)},\n\t\t\t{\"0o52\", int64(42)},\n\t\t\t{\"0x2a\", int64(42)},\n\t\t\t{\"0X2A\", int64(42)},\n\t\t\t{\"0\", int64(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, int64]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToUint64HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, uint64]{\n\t\tfn: StringToUint64HookFunc(),\n\t\tok: []decodeHookTestCase[string, uint64]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"0b101010\", uint64(42)},\n\t\t\t{\"052\", uint64(42)},\n\t\t\t{\"0o52\", uint64(42)},\n\t\t\t{\"0x2a\", uint64(42)},\n\t\t\t{\"0X2A\", uint64(42)},\n\t\t\t{\"0\", uint64(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, uint64]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"-42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToIntHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, int]{\n\t\tfn: StringToIntHookFunc(),\n\t\tok: []decodeHookTestCase[string, int]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"-42\", int(-42)},\n\t\t\t{\"0b101010\", int(42)},\n\t\t\t{\"052\", int(42)},\n\t\t\t{\"0o52\", int(42)},\n\t\t\t{\"0x2a\", int(42)},\n\t\t\t{\"0X2A\", int(42)},\n\t\t\t{\"0\", int(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, int]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToUintHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, uint]{\n\t\tfn: StringToUintHookFunc(),\n\t\tok: []decodeHookTestCase[string, uint]{\n\t\t\t{\"42\", 42},\n\t\t\t{\"0b101010\", uint(42)},\n\t\t\t{\"052\", uint(42)},\n\t\t\t{\"0o52\", uint(42)},\n\t\t\t{\"0x2a\", uint(42)},\n\t\t\t{\"0X2A\", uint(42)},\n\t\t\t{\"0\", uint(0)},\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, uint]{\n\t\t\t{strings.Repeat(\"42\", 42)},\n\t\t\t{\"42.42\"},\n\t\t\t{\"-42\"},\n\t\t\t{\"0.0\"},\n\t\t},\n\t}\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToFloat32HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, float32]{\n\t\tfn: StringToFloat32HookFunc(),\n\t\tok: []decodeHookTestCase[string, float32]{\n\t\t\t{\"42.42\", float32(42.42)},   // Basic decimal\n\t\t\t{\"-42.42\", float32(-42.42)}, // Negative decimal\n\t\t\t{\"0\", float32(0)},           // Zero as integer\n\t\t\t{\"1e3\", float32(1000)},      // Scientific notation\n\t\t\t{\"1e-3\", float32(0.001)},    // Small scientific notation\n\t\t\t// Integer values\n\t\t\t{\"42\", float32(42)},   // Positive integer\n\t\t\t{\"-42\", float32(-42)}, // Negative integer\n\t\t\t{\"+42\", float32(42)},  // Explicit positive integer\n\t\t\t// Zero variants\n\t\t\t{\"0.0\", float32(0.0)}, // Zero with decimal\n\t\t\t{\"+0\", float32(0)},    // Explicit positive zero\n\t\t\t{\"-0\", float32(0)},    // Explicit negative zero\n\t\t\t{\"00.00\", float32(0)}, // Zero with leading zeros\n\t\t\t// Scientific notation\n\t\t\t{\"1E3\", float32(1000)},        // Scientific notation (uppercase E)\n\t\t\t{\"1.5e2\", float32(150)},       // Fractional base with exponent\n\t\t\t{\"1.5E2\", float32(150)},       // Fractional base with uppercase E\n\t\t\t{\"-1.5e2\", float32(-150)},     // Negative fractional with exponent\n\t\t\t{\"1e+3\", float32(1000)},       // Explicit positive exponent\n\t\t\t{\"1e-10\", float32(1e-10)},     // Very small exponent\n\t\t\t{\"3.14159\", float32(3.14159)}, // Pi approximation\n\t\t\t// Special values - infinity\n\t\t\t{\"inf\", float32(math.Inf(1))},        // Infinity (lowercase)\n\t\t\t{\"+inf\", float32(math.Inf(1))},       // Positive infinity\n\t\t\t{\"-inf\", float32(math.Inf(-1))},      // Negative infinity\n\t\t\t{\"Inf\", float32(math.Inf(1))},        // Infinity (capitalized)\n\t\t\t{\"+Inf\", float32(math.Inf(1))},       // Positive infinity (capitalized)\n\t\t\t{\"-Inf\", float32(math.Inf(-1))},      // Negative infinity (capitalized)\n\t\t\t{\"infinity\", float32(math.Inf(1))},   // Infinity (full word)\n\t\t\t{\"+infinity\", float32(math.Inf(1))},  // Positive infinity (full word)\n\t\t\t{\"-infinity\", float32(math.Inf(-1))}, // Negative infinity (full word)\n\t\t\t{\"Infinity\", float32(math.Inf(1))},   // Infinity (full word capitalized)\n\t\t\t{\"+Infinity\", float32(math.Inf(1))},  // Positive infinity (full word capitalized)\n\t\t\t{\"-Infinity\", float32(math.Inf(-1))}, // Negative infinity (full word capitalized)\n\t\t\t// Decimal variations\n\t\t\t{\".5\", float32(0.5)},   // Leading decimal point\n\t\t\t{\"-.5\", float32(-0.5)}, // Negative leading decimal\n\t\t\t{\"+.5\", float32(0.5)},  // Positive leading decimal\n\t\t\t{\"5.\", float32(5.0)},   // Trailing decimal point\n\t\t\t{\"-5.\", float32(-5.0)}, // Negative trailing decimal\n\t\t\t{\"+5.\", float32(5.0)},  // Positive trailing decimal\n\t\t\t// Very small and large numbers\n\t\t\t{\"1.1754943508222875e-38\", float32(1.1754943508222875e-38)}, // Near min positive\n\t\t\t{\"3.4028234663852886e+38\", float32(3.4028234663852886e+38)}, // Near max\n\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, float32]{\n\t\t\t{strings.Repeat(\"42\", 420)},\n\t\t\t{\"42.42.42\"},\n\t\t\t{\"abc\"},      // Non-numeric\n\t\t\t{\"\"},         // Empty string\n\t\t\t{\"42abc\"},    // Trailing non-numeric\n\t\t\t{\"abc42\"},    // Leading non-numeric\n\t\t\t{\"42 43\"},    // Multiple numbers\n\t\t\t{\"++42\"},     // Double plus\n\t\t\t{\"--42\"},     // Double minus\n\t\t\t{\"1e\"},       // Incomplete scientific notation\n\t\t\t{\"1e+\"},      // Incomplete scientific notation\n\t\t\t{\"1e-\"},      // Incomplete scientific notation\n\t\t\t{\"1.2.3\"},    // Multiple dots\n\t\t\t{\"1..2\"},     // Double dots\n\t\t\t{\".\"},        // Just a dot\n\t\t\t{\" 42.5 \"},   // Whitespace not handled by strconv\n\t\t\t{\"\\t42.5\\n\"}, // Whitespace not handled by strconv\n\t\t\t{\"\\r42.5\\r\"}, // Whitespace not handled by strconv\n\t\t\t{\" 42.5 \"},   // Whitespace not handled by strconv\n\t\t\t{\"\\t42.5\\n\"}, // Whitespace not handled by strconv\n\t\t\t{\"\\r42.5\\r\"}, // Whitespace not handled by strconv\n\t\t\t{\"1e1e1\"},    // Multiple exponents\n\t\t\t{\"∞\"},        // Unicode infinity\n\t\t\t{\"NaΝ\"},      // Unicode NaN lookalike\n\t\t},\n\t}\n\n\t// Custom test for NaN since NaN != NaN\n\tt.Run(\"NaN\", func(t *testing.T) {\n\t\tf := StringToFloat32HookFunc()\n\t\tactual, err := DecodeHookExec(f, reflect.ValueOf(\"nan\"), reflect.ValueOf(float32(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif !math.IsNaN(float64(actual.(float32))) {\n\t\t\tt.Fatalf(\"expected NaN, got %v\", actual)\n\t\t}\n\t})\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToFloat64HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, float64]{\n\t\tfn: StringToFloat64HookFunc(),\n\t\tok: []decodeHookTestCase[string, float64]{\n\t\t\t{\"42.42\", float64(42.42)},   // Basic decimal\n\t\t\t{\"-42.42\", float64(-42.42)}, // Negative decimal\n\t\t\t{\"0\", float64(0)},           // Zero as integer\n\t\t\t{\"0.0\", float64(0)},         // Zero with decimal\n\t\t\t{\"1e3\", float64(1000)},      // Scientific notation\n\t\t\t{\"1e-3\", float64(0.001)},    // Small scientific notation\n\t\t\t// Integer values\n\t\t\t{\"42\", float64(42)},   // Positive integer\n\t\t\t{\"-42\", float64(-42)}, // Negative integer\n\t\t\t{\"+42\", float64(42)},  // Explicit positive integer\n\t\t\t// Zero variants\n\t\t\t{\"+0\", float64(0)},    // Explicit positive zero\n\t\t\t{\"-0\", float64(0)},    // Explicit negative zero\n\t\t\t{\"00.00\", float64(0)}, // Zero with leading zeros\n\t\t\t// Scientific notation\n\t\t\t{\"1E3\", float64(1000)},                            // Scientific notation (uppercase E)\n\t\t\t{\"1.5e2\", float64(150)},                           // Fractional base with exponent\n\t\t\t{\"1.5E2\", float64(150)},                           // Fractional base with uppercase E\n\t\t\t{\"-1.5e2\", float64(-150)},                         // Negative fractional with exponent\n\t\t\t{\"1e+3\", float64(1000)},                           // Explicit positive exponent\n\t\t\t{\"1e-15\", float64(1e-15)},                         // Very small exponent\n\t\t\t{\"3.141592653589793\", float64(3.141592653589793)}, // Pi with high precision\n\t\t\t// Special values - infinity\n\t\t\t{\"inf\", math.Inf(1)},        // Infinity (lowercase)\n\t\t\t{\"+inf\", math.Inf(1)},       // Positive infinity\n\t\t\t{\"-inf\", math.Inf(-1)},      // Negative infinity\n\t\t\t{\"Inf\", math.Inf(1)},        // Infinity (capitalized)\n\t\t\t{\"+Inf\", math.Inf(1)},       // Positive infinity (capitalized)\n\t\t\t{\"-Inf\", math.Inf(-1)},      // Negative infinity (capitalized)\n\t\t\t{\"infinity\", math.Inf(1)},   // Infinity (full word)\n\t\t\t{\"+infinity\", math.Inf(1)},  // Positive infinity (full word)\n\t\t\t{\"-infinity\", math.Inf(-1)}, // Negative infinity (full word)\n\t\t\t{\"Infinity\", math.Inf(1)},   // Infinity (full word capitalized)\n\t\t\t{\"+Infinity\", math.Inf(1)},  // Positive infinity (full word capitalized)\n\t\t\t{\"-Infinity\", math.Inf(-1)}, // Negative infinity (full word capitalized)\n\t\t\t// Decimal variations\n\t\t\t{\".5\", float64(0.5)},   // Leading decimal point\n\t\t\t{\"-.5\", float64(-0.5)}, // Negative leading decimal\n\t\t\t{\"+.5\", float64(0.5)},  // Positive leading decimal\n\t\t\t{\"5.\", float64(5.0)},   // Trailing decimal point\n\t\t\t{\"-5.\", float64(-5.0)}, // Negative trailing decimal\n\t\t\t{\"+5.\", float64(5.0)},  // Positive trailing decimal\n\t\t\t// Very small and large numbers\n\t\t\t{\"2.2250738585072014e-308\", float64(2.2250738585072014e-308)}, // Near min positive\n\t\t\t{\"1.7976931348623157e+308\", float64(1.7976931348623157e+308)}, // Near max\n\t\t\t{\"4.9406564584124654e-324\", float64(4.9406564584124654e-324)}, // Min positive subnormal\n\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, float64]{\n\t\t\t{strings.Repeat(\"42\", 420)},\n\t\t\t{\"42.42.42\"},\n\t\t\t{\"abc\"},   // Non-numeric\n\t\t\t{\"\"},      // Empty string\n\t\t\t{\"42abc\"}, // Trailing non-numeric\n\t\t\t{\"abc42\"}, // Leading non-numeric\n\t\t\t{\"42 43\"}, // Multiple numbers\n\t\t\t{\"++42\"},  // Double plus\n\t\t\t{\"--42\"},  // Double minus\n\t\t\t{\"1e\"},    // Incomplete scientific notation\n\t\t\t{\"1e+\"},   // Incomplete scientific notation\n\t\t\t{\"1e-\"},   // Incomplete scientific notation\n\t\t\t{\"1.2.3\"}, // Multiple dots\n\t\t\t{\"1..2\"},  // Double dots\n\t\t\t{\".\"},     // Just a dot\n\t\t\t{\"1e1e1\"}, // Multiple exponents\n\t\t\t{\"∞\"},     // Unicode infinity\n\t\t\t{\"NaΝ\"},   // Unicode NaN lookalike\n\t\t},\n\t}\n\n\t// Custom test for NaN since NaN != NaN\n\tt.Run(\"NaN\", func(t *testing.T) {\n\t\tf := StringToFloat64HookFunc()\n\t\tactual, err := DecodeHookExec(f, reflect.ValueOf(\"nan\"), reflect.ValueOf(float64(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif !math.IsNaN(actual.(float64)) {\n\t\t\tt.Fatalf(\"expected NaN, got %v\", actual)\n\t\t}\n\t})\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToComplex64HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, complex64]{\n\t\tfn: StringToComplex64HookFunc(),\n\t\tok: []decodeHookTestCase[string, complex64]{\n\t\t\t// Standard complex numbers\n\t\t\t{\"42.42+42.42i\", complex(float32(42.42), float32(42.42))}, // Basic complex number\n\t\t\t{\"1+2i\", complex(float32(1), float32(2))},                 // Simple complex number\n\t\t\t{\"-1-2i\", complex(float32(-1), float32(-2))},              // Negative real and imaginary\n\t\t\t{\"1-2i\", complex(float32(1), float32(-2))},                // Positive real, negative imaginary\n\t\t\t{\"-1+2i\", complex(float32(-1), float32(2))},               // Negative real, positive imaginary\n\t\t\t// Real numbers only\n\t\t\t{\"-42.42\", complex(float32(-42.42), 0)}, // Negative real number\n\t\t\t{\"42\", complex(float32(42), 0)},         // Positive integer\n\t\t\t{\"+42\", complex(float32(42), 0)},        // Explicit positive integer\n\t\t\t{\"0\", complex(float32(0), 0)},           // Zero\n\t\t\t{\"0.0\", complex(float32(0), 0)},         // Zero with decimal\n\t\t\t{\"+0\", complex(float32(0), 0)},          // Explicit positive zero\n\t\t\t{\"-0\", complex(float32(0), 0)},          // Explicit negative zero\n\t\t\t// Scientific notation\n\t\t\t{\"1e3\", complex(float32(1000), 0)},    // Scientific notation\n\t\t\t{\"1e-3\", complex(float32(0.001), 0)},  // Small scientific notation\n\t\t\t{\"1E3\", complex(float32(1000), 0)},    // Uppercase E\n\t\t\t{\"1e+3\", complex(float32(1000), 0)},   // Explicit positive exponent\n\t\t\t{\"1.5e2\", complex(float32(150), 0)},   // Fractional with exponent\n\t\t\t{\"-1.5e2\", complex(float32(-150), 0)}, // Negative fractional with exponent\n\t\t\t// Imaginary numbers only\n\t\t\t{\"1e3i\", complex(float32(0), 1000)},   // Scientific notation imaginary\n\t\t\t{\"1e-3i\", complex(float32(0), 0.001)}, // Small scientific notation imaginary\n\t\t\t{\"42i\", complex(float32(0), 42)},      // Basic imaginary\n\t\t\t{\"-42i\", complex(float32(0), -42)},    // Negative imaginary\n\t\t\t{\"+42i\", complex(float32(0), 42)},     // Explicit positive imaginary\n\t\t\t{\"0i\", complex(float32(0), 0)},        // Zero imaginary\n\t\t\t{\"1i\", complex(float32(0), 1)},        // Unit imaginary\n\t\t\t{\"-1i\", complex(float32(0), -1)},      // Negative unit imaginary\n\t\t\t{\"1.5i\", complex(float32(0), 1.5)},    // Fractional imaginary\n\t\t\t// Scientific notation imaginary\n\t\t\t{\"1E3i\", complex(float32(0), 1000)},    // Uppercase E imaginary\n\t\t\t{\"1e+3i\", complex(float32(0), 1000)},   // Explicit positive exponent imaginary\n\t\t\t{\"1.5e2i\", complex(float32(0), 150)},   // Fractional with exponent imaginary\n\t\t\t{\"-1.5e2i\", complex(float32(0), -150)}, // Negative fractional with exponent imaginary\n\t\t\t// Complex with scientific notation\n\t\t\t{\"1e3+2e2i\", complex(float32(1000), float32(200))},     // Both parts scientific\n\t\t\t{\"1e-3+2e-2i\", complex(float32(0.001), float32(0.02))}, // Both parts small scientific\n\t\t\t{\"1.5e2-2.5e1i\", complex(float32(150), float32(-25))},  // Mixed signs with scientific\n\t\t\t// Decimal variations\n\t\t\t{\".5\", complex(float32(0.5), 0)},    // Leading decimal point\n\t\t\t{\"-.5\", complex(float32(-0.5), 0)},  // Negative leading decimal\n\t\t\t{\"+.5\", complex(float32(0.5), 0)},   // Positive leading decimal\n\t\t\t{\"5.\", complex(float32(5.0), 0)},    // Trailing decimal point\n\t\t\t{\"-5.\", complex(float32(-5.0), 0)},  // Negative trailing decimal\n\t\t\t{\"+5.\", complex(float32(5.0), 0)},   // Positive trailing decimal\n\t\t\t{\".5i\", complex(float32(0), 0.5)},   // Leading decimal imaginary\n\t\t\t{\"-.5i\", complex(float32(0), -0.5)}, // Negative leading decimal imaginary\n\t\t\t{\"+.5i\", complex(float32(0), 0.5)},  // Positive leading decimal imaginary\n\t\t\t{\"5.i\", complex(float32(0), 5.0)},   // Trailing decimal imaginary\n\t\t\t{\"-5.i\", complex(float32(0), -5.0)}, // Negative trailing decimal imaginary\n\t\t\t{\"+5.i\", complex(float32(0), 5.0)},  // Positive trailing decimal imaginary\n\t\t\t// Complex decimal variations\n\t\t\t{\".5+.5i\", complex(float32(0.5), float32(0.5))},  // Both parts leading decimal\n\t\t\t{\"5.+5.i\", complex(float32(5.0), float32(5.0))},  // Both parts trailing decimal\n\t\t\t{\".5-.5i\", complex(float32(0.5), float32(-0.5))}, // Leading decimal with negative\n\t\t\t// Special values - infinity\n\t\t\t{\"inf\", complex(float32(math.Inf(1)), 0)},                // Real infinity\n\t\t\t{\"+inf\", complex(float32(math.Inf(1)), 0)},               // Positive real infinity\n\t\t\t{\"-inf\", complex(float32(math.Inf(-1)), 0)},              // Negative real infinity\n\t\t\t{\"Inf\", complex(float32(math.Inf(1)), 0)},                // Capitalized infinity\n\t\t\t{\"infinity\", complex(float32(math.Inf(1)), 0)},           // Full word infinity\n\t\t\t{\"Infinity\", complex(float32(math.Inf(1)), 0)},           // Capitalized full word infinity\n\t\t\t{\"infi\", complex(float32(0), float32(math.Inf(1)))},      // Imaginary infinity\n\t\t\t{\"+infi\", complex(float32(0), float32(math.Inf(1)))},     // Positive imaginary infinity\n\t\t\t{\"-infi\", complex(float32(0), float32(math.Inf(-1)))},    // Negative imaginary infinity\n\t\t\t{\"Infi\", complex(float32(0), float32(math.Inf(1)))},      // Capitalized imaginary infinity\n\t\t\t{\"infinityi\", complex(float32(0), float32(math.Inf(1)))}, // Full word imaginary infinity\n\t\t\t{\"Infinityi\", complex(float32(0), float32(math.Inf(1)))}, // Capitalized full word imaginary infinity\n\t\t\t// Complex with special values\n\t\t\t{\"inf+1i\", complex(float32(math.Inf(1)), float32(1))},                // Real infinity with imaginary\n\t\t\t{\"1+infi\", complex(float32(1), float32(math.Inf(1)))},                // Real with imaginary infinity\n\t\t\t{\"inf+infi\", complex(float32(math.Inf(1)), float32(math.Inf(1)))},    // Both infinities\n\t\t\t{\"-inf-infi\", complex(float32(math.Inf(-1)), float32(math.Inf(-1)))}, // Both negative infinities\n\t\t\t// Parentheses format\n\t\t\t{\"(42+42i)\", complex(float32(42), float32(42))},    // Complex in parentheses\n\t\t\t{\"(42)\", complex(float32(42), float32(0))},         // Real in parentheses\n\t\t\t{\"(42i)\", complex(float32(0), float32(42))},        // Imaginary in parentheses\n\t\t\t{\"(-42-42i)\", complex(float32(-42), float32(-42))}, // Negative complex in parentheses\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, complex64]{\n\t\t\t{strings.Repeat(\"42\", 420)},\n\t\t\t{\"42.42.42\"},\n\t\t\t{\"abc\"},            // Non-numeric\n\t\t\t{\"\"},               // Empty string\n\t\t\t{\"42abc\"},          // Trailing non-numeric\n\t\t\t{\"abc42\"},          // Leading non-numeric\n\t\t\t{\"42+abc\"},         // Invalid imaginary part\n\t\t\t{\"abc+42i\"},        // Invalid real part\n\t\t\t{\"42++42i\"},        // Double plus\n\t\t\t{\"42+-+42i\"},       // Multiple signs\n\t\t\t{\"42+42j\"},         // Wrong imaginary unit\n\t\t\t{\"42+42k\"},         // Wrong imaginary unit\n\t\t\t{\"42 + 42i\"},       // Spaces around operator\n\t\t\t{\"42+42i+1\"},       // Extra components\n\t\t\t{\"42+42i+1i\"},      // Multiple imaginary parts\n\t\t\t{\"42+42i+1+2i\"},    // Too many components\n\t\t\t{\"(42+42i\"},        // Unclosed parenthesis\n\t\t\t{\"42+42i)\"},        // Extra closing parenthesis\n\t\t\t{\"((42+42i))\"},     // Double parentheses\n\t\t\t{\"(42+42i)(1+1i)\"}, // Multiple complex numbers\n\t\t\t{\"42i+42\"},         // Imaginary first (not standard)\n\t\t\t{\"i\"},              // Just 'i'\n\t\t\t{\"42.42.42+1i\"},    // Invalid real part\n\t\t\t{\"42+42.42.42i\"},   // Invalid imaginary part\n\t\t\t{\"1e\"},             // Incomplete scientific notation\n\t\t\t{\"1e+\"},            // Incomplete scientific notation\n\t\t\t{\"1e-\"},            // Incomplete scientific notation\n\t\t\t{\"1e+i\"},           // Incomplete scientific notation\n\t\t\t{\"1.2.3+1i\"},       // Multiple dots in real\n\t\t\t{\"1+1.2.3i\"},       // Multiple dots in imaginary\n\t\t\t{\"1..2+1i\"},        // Double dots in real\n\t\t\t{\"1+1..2i\"},        // Double dots in imaginary\n\t\t\t{\".+.i\"},           // Just dots\n\t\t\t{\"1e1e1+1i\"},       // Multiple exponents in real\n\t\t\t{\" 42+42i \"},       // Whitespace not handled by strconv\n\t\t\t{\"\\t42i\\n\"},        // Whitespace not handled by strconv\n\t\t\t{\"\\r42\\r\"},         // Whitespace not handled by strconv\n\t\t\t{\" 42+42i \"},       // Whitespace not handled by strconv\n\t\t\t{\"\\t42i\\n\"},        // Whitespace not handled by strconv\n\t\t\t{\"\\r42\\r\"},         // Whitespace not handled by strconv\n\t\t\t{\"1+1e1e1i\"},       // Multiple exponents in imaginary\n\t\t\t{\"∞\"},              // Unicode infinity\n\t\t\t{\"∞+∞i\"},           // Unicode infinity complex\n\t\t\t{\"NaΝ\"},            // Unicode NaN lookalike\n\t\t},\n\t}\n\n\t// Custom test for NaN since NaN != NaN\n\tt.Run(\"NaN\", func(t *testing.T) {\n\t\tf := StringToComplex64HookFunc()\n\n\t\t// Test real NaN\n\t\tactual, err := DecodeHookExec(f, reflect.ValueOf(\"nan\"), reflect.ValueOf(complex64(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tc := actual.(complex64)\n\t\tif !math.IsNaN(float64(real(c))) || imag(c) != 0 {\n\t\t\tt.Fatalf(\"expected NaN+0i, got %v\", c)\n\t\t}\n\n\t\t// Test imaginary NaN\n\t\tactual, err = DecodeHookExec(f, reflect.ValueOf(\"nani\"), reflect.ValueOf(complex64(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tc = actual.(complex64)\n\t\tif real(c) != 0 || !math.IsNaN(float64(imag(c))) {\n\t\t\tt.Fatalf(\"expected 0+NaNi, got %v\", c)\n\t\t}\n\n\t\t// Test complex NaN\n\t\tactual, err = DecodeHookExec(f, reflect.ValueOf(\"nan+nani\"), reflect.ValueOf(complex64(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tc = actual.(complex64)\n\t\tif !math.IsNaN(float64(real(c))) || !math.IsNaN(float64(imag(c))) {\n\t\t\tt.Fatalf(\"expected NaN+NaNi, got %v\", c)\n\t\t}\n\t})\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToBoolHookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, bool]{\n\t\tfn: StringToBoolHookFunc(),\n\t\tok: []decodeHookTestCase[string, bool]{\n\t\t\t// True values (only those accepted by strconv.ParseBool)\n\t\t\t{\"true\", true}, // Boolean true (lowercase)\n\t\t\t{\"True\", true}, // Boolean true (capitalized)\n\t\t\t{\"TRUE\", true}, // Boolean true (uppercase)\n\t\t\t{\"t\", true},    // Single character true (lowercase)\n\t\t\t{\"T\", true},    // Single character true (uppercase)\n\t\t\t{\"1\", true},    // Numeric true\n\n\t\t\t// False values (only those accepted by strconv.ParseBool)\n\t\t\t{\"false\", false}, // Boolean false (lowercase)\n\t\t\t{\"False\", false}, // Boolean false (capitalized)\n\t\t\t{\"FALSE\", false}, // Boolean false (uppercase)\n\t\t\t{\"f\", false},     // Single character false (lowercase)\n\t\t\t{\"F\", false},     // Single character false (uppercase)\n\t\t\t{\"0\", false},     // Numeric false\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, bool]{\n\t\t\t{\"\"},           // Empty string\n\t\t\t{\"maybe\"},      // Invalid boolean word\n\t\t\t{\"yes\"},        // Not accepted by strconv.ParseBool\n\t\t\t{\"no\"},         // Not accepted by strconv.ParseBool\n\t\t\t{\"on\"},         // Not accepted by strconv.ParseBool\n\t\t\t{\"off\"},        // Not accepted by strconv.ParseBool\n\t\t\t{\"y\"},          // Not accepted by strconv.ParseBool\n\t\t\t{\"n\"},          // Not accepted by strconv.ParseBool\n\t\t\t{\"yes please\"}, // Invalid boolean phrase\n\t\t\t{\"true false\"}, // Multiple boolean values\n\t\t\t{\"2\"},          // Invalid number (only 0/1 accepted)\n\t\t\t{\"-1\"},         // Negative number\n\t\t\t{\"10\"},         // Number greater than 1\n\t\t\t{\"abc\"},        // Non-boolean text\n\t\t\t{\"True False\"}, // Multiple boolean values (capitalized)\n\t\t\t{\"1.0\"},        // Float representation of 1\n\t\t\t{\"0.0\"},        // Float representation of 0\n\t\t\t{\"++true\"},     // Double positive prefix\n\t\t\t{\"--false\"},    // Double negative prefix\n\t\t\t{\"truee\"},      // Typo in true\n\t\t\t{\"fasle\"},      // Typo in false\n\t\t\t{\"tru\"},        // Incomplete true\n\t\t\t{\"fals\"},       // Incomplete false\n\t\t\t{\" true \"},     // Whitespace not handled by strconv.ParseBool\n\t\t\t{\"\\ttrue\\n\"},   // Tab and newline whitespace\n\t\t\t{\"\\rfalse\\r\"},  // Carriage return whitespace\n\t\t\t{\" 1 \"},        // Whitespace around numeric true\n\t\t\t{\" 0 \"},        // Whitespace around numeric false\n\t\t\t{\"∞\"},          // Unicode infinity symbol\n\t\t\t{\"тrue\"},       // Cyrillic lookalike characters\n\t\t},\n\t}\n\n\t// Test non-string and non-bool type passthrough\n\tt.Run(\"Passthrough\", func(t *testing.T) {\n\t\tf := StringToBoolHookFunc()\n\n\t\t// Non-string type should pass through\n\t\tintValue := reflect.ValueOf(42)\n\t\tactual, err := DecodeHookExec(f, intValue, reflect.ValueOf(false))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif actual != 42 {\n\t\t\tt.Fatalf(\"expected 42, got %v\", actual)\n\t\t}\n\n\t\t// Non-bool target type should pass through\n\t\tstrValue := reflect.ValueOf(\"true\")\n\t\tactual, err = DecodeHookExec(f, strValue, strValue)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tif actual != \"true\" {\n\t\t\tt.Fatalf(\"expected 'true', got %v\", actual)\n\t\t}\n\t})\n\n\tsuite.Run(t)\n}\n\nfunc TestStringToComplex128HookFunc(t *testing.T) {\n\tsuite := decodeHookTestSuite[string, complex128]{\n\t\tfn: StringToComplex128HookFunc(),\n\t\tok: []decodeHookTestCase[string, complex128]{\n\t\t\t// Standard complex numbers\n\t\t\t{\"42.42+42.42i\", complex(42.42, 42.42)}, // Basic complex number\n\t\t\t{\"1+2i\", complex(1, 2)},                 // Simple complex number\n\t\t\t{\"-1-2i\", complex(-1, -2)},              // Negative real and imaginary\n\t\t\t{\"1-2i\", complex(1, -2)},                // Positive real, negative imaginary\n\t\t\t{\"-1+2i\", complex(-1, 2)},               // Negative real, positive imaginary\n\t\t\t// Real numbers only\n\t\t\t{\"-42.42\", complex(-42.42, 0)}, // Negative real number\n\t\t\t{\"42\", complex(42, 0)},         // Positive integer\n\t\t\t{\"+42\", complex(42, 0)},        // Explicit positive integer\n\t\t\t{\"0\", complex(0, 0)},           // Zero\n\t\t\t{\"0.0\", complex(0, 0)},         // Zero with decimal\n\t\t\t{\"+0\", complex(0, 0)},          // Explicit positive zero\n\t\t\t{\"-0\", complex(0, 0)},          // Explicit negative zero\n\t\t\t// Scientific notation\n\t\t\t{\"1e3\", complex(1000, 0)},                            // Scientific notation\n\t\t\t{\"1e-3\", complex(0.001, 0)},                          // Small scientific notation\n\t\t\t{\"1E3\", complex(1000, 0)},                            // Uppercase E\n\t\t\t{\"1e+3\", complex(1000, 0)},                           // Explicit positive exponent\n\t\t\t{\"1.5e2\", complex(150, 0)},                           // Fractional with exponent\n\t\t\t{\"-1.5e2\", complex(-150, 0)},                         // Negative fractional with exponent\n\t\t\t{\"1e-15\", complex(1e-15, 0)},                         // Very small scientific notation\n\t\t\t{\"3.141592653589793\", complex(3.141592653589793, 0)}, // Pi with high precision\n\t\t\t// Imaginary numbers only\n\t\t\t{\"1e3i\", complex(0, 1000)},   // Scientific notation imaginary\n\t\t\t{\"1e-3i\", complex(0, 0.001)}, // Small scientific notation imaginary\n\t\t\t{\"42i\", complex(0, 42)},      // Basic imaginary\n\t\t\t{\"-42i\", complex(0, -42)},    // Negative imaginary\n\t\t\t{\"+42i\", complex(0, 42)},     // Explicit positive imaginary\n\t\t\t{\"0i\", complex(0, 0)},        // Zero imaginary\n\t\t\t{\"1i\", complex(0, 1)},        // Unit imaginary\n\t\t\t{\"-1i\", complex(0, -1)},      // Negative unit imaginary\n\t\t\t{\"1.5i\", complex(0, 1.5)},    // Fractional imaginary\n\t\t\t// Scientific notation imaginary\n\t\t\t{\"1E3i\", complex(0, 1000)},    // Uppercase E imaginary\n\t\t\t{\"1e+3i\", complex(0, 1000)},   // Explicit positive exponent imaginary\n\t\t\t{\"1.5e2i\", complex(0, 150)},   // Fractional with exponent imaginary\n\t\t\t{\"-1.5e2i\", complex(0, -150)}, // Negative fractional with exponent imaginary\n\t\t\t{\"1e-15i\", complex(0, 1e-15)}, // Very small scientific notation imaginary\n\t\t\t// Complex with scientific notation\n\t\t\t{\"1e3+2e2i\", complex(1000, 200)},        // Both parts scientific\n\t\t\t{\"1e-3+2e-2i\", complex(0.001, 0.02)},    // Both parts small scientific\n\t\t\t{\"1.5e2-2.5e1i\", complex(150, -25)},     // Mixed signs with scientific\n\t\t\t{\"1e-15+1e-15i\", complex(1e-15, 1e-15)}, // Both parts very small scientific\n\t\t\t// Decimal variations\n\t\t\t{\".5\", complex(0.5, 0)},    // Leading decimal point\n\t\t\t{\"-.5\", complex(-0.5, 0)},  // Negative leading decimal\n\t\t\t{\"+.5\", complex(0.5, 0)},   // Positive leading decimal\n\t\t\t{\"5.\", complex(5.0, 0)},    // Trailing decimal point\n\t\t\t{\"-5.\", complex(-5.0, 0)},  // Negative trailing decimal\n\t\t\t{\"+5.\", complex(5.0, 0)},   // Positive trailing decimal\n\t\t\t{\".5i\", complex(0, 0.5)},   // Leading decimal imaginary\n\t\t\t{\"-.5i\", complex(0, -0.5)}, // Negative leading decimal imaginary\n\t\t\t{\"+.5i\", complex(0, 0.5)},  // Positive leading decimal imaginary\n\t\t\t{\"5.i\", complex(0, 5.0)},   // Trailing decimal imaginary\n\t\t\t{\"-5.i\", complex(0, -5.0)}, // Negative trailing decimal imaginary\n\t\t\t{\"+5.i\", complex(0, 5.0)},  // Positive trailing decimal imaginary\n\t\t\t// Complex decimal variations\n\t\t\t{\".5+.5i\", complex(0.5, 0.5)},  // Both parts leading decimal\n\t\t\t{\"5.+5.i\", complex(5.0, 5.0)},  // Both parts trailing decimal\n\t\t\t{\".5-.5i\", complex(0.5, -0.5)}, // Leading decimal with negative\n\t\t\t// Very small and large numbers\n\t\t\t{\"2.2250738585072014e-308\", complex(2.2250738585072014e-308, 0)},  // Near min positive real\n\t\t\t{\"1.7976931348623157e+308\", complex(1.7976931348623157e+308, 0)},  // Near max real\n\t\t\t{\"4.9406564584124654e-324\", complex(4.9406564584124654e-324, 0)},  // Min positive subnormal real\n\t\t\t{\"2.2250738585072014e-308i\", complex(0, 2.2250738585072014e-308)}, // Near min positive imaginary\n\t\t\t{\"1.7976931348623157e+308i\", complex(0, 1.7976931348623157e+308)}, // Near max imaginary\n\t\t\t{\"4.9406564584124654e-324i\", complex(0, 4.9406564584124654e-324)}, // Min positive subnormal imaginary\n\t\t\t// Special values - infinity\n\t\t\t{\"inf\", complex(math.Inf(1), 0)},       // Real infinity\n\t\t\t{\"+inf\", complex(math.Inf(1), 0)},      // Positive real infinity\n\t\t\t{\"-inf\", complex(math.Inf(-1), 0)},     // Negative real infinity\n\t\t\t{\"Inf\", complex(math.Inf(1), 0)},       // Capitalized infinity\n\t\t\t{\"infinity\", complex(math.Inf(1), 0)},  // Full word infinity\n\t\t\t{\"Infinity\", complex(math.Inf(1), 0)},  // Capitalized full word infinity\n\t\t\t{\"infi\", complex(0, math.Inf(1))},      // Imaginary infinity\n\t\t\t{\"+infi\", complex(0, math.Inf(1))},     // Positive imaginary infinity\n\t\t\t{\"-infi\", complex(0, math.Inf(-1))},    // Negative imaginary infinity\n\t\t\t{\"Infi\", complex(0, math.Inf(1))},      // Capitalized imaginary infinity\n\t\t\t{\"infinityi\", complex(0, math.Inf(1))}, // Full word imaginary infinity\n\t\t\t{\"Infinityi\", complex(0, math.Inf(1))}, // Capitalized full word imaginary infinity\n\t\t\t// Complex with special values\n\t\t\t{\"inf+1i\", complex(math.Inf(1), 1)},                // Real infinity with imaginary\n\t\t\t{\"1+infi\", complex(1, math.Inf(1))},                // Real with imaginary infinity\n\t\t\t{\"inf+infi\", complex(math.Inf(1), math.Inf(1))},    // Both infinities\n\t\t\t{\"-inf-infi\", complex(math.Inf(-1), math.Inf(-1))}, // Both negative infinities\n\t\t\t// Parentheses format\n\t\t\t{\"(42+42i)\", complex(42, 42)},    // Complex in parentheses\n\t\t\t{\"(42)\", complex(42, 0)},         // Real in parentheses\n\t\t\t{\"(42i)\", complex(0, 42)},        // Imaginary in parentheses\n\t\t\t{\"(-42-42i)\", complex(-42, -42)}, // Negative complex in parentheses\n\t\t},\n\t\tfail: []decodeHookFailureTestCase[string, complex128]{\n\t\t\t{strings.Repeat(\"42\", 420)},\n\t\t\t{\"42.42.42\"},\n\t\t\t{\"abc\"},            // Non-numeric\n\t\t\t{\"\"},               // Empty string\n\t\t\t{\"42abc\"},          // Trailing non-numeric\n\t\t\t{\"abc42\"},          // Leading non-numeric\n\t\t\t{\"42+abc\"},         // Invalid imaginary part\n\t\t\t{\"abc+42i\"},        // Invalid real part\n\t\t\t{\"42++42i\"},        // Double plus\n\t\t\t{\"42+-+42i\"},       // Multiple signs\n\t\t\t{\"42+42j\"},         // Wrong imaginary unit\n\t\t\t{\"42+42k\"},         // Wrong imaginary unit\n\t\t\t{\"42 + 42i\"},       // Spaces around operator\n\t\t\t{\"42+42i+1\"},       // Extra components\n\t\t\t{\"42+42i+1i\"},      // Multiple imaginary parts\n\t\t\t{\"42+42i+1+2i\"},    // Too many components\n\t\t\t{\"(42+42i\"},        // Unclosed parenthesis\n\t\t\t{\"42+42i)\"},        // Extra closing parenthesis\n\t\t\t{\"((42+42i))\"},     // Double parentheses\n\t\t\t{\"(42+42i)(1+1i)\"}, // Multiple complex numbers\n\t\t\t{\"42i+42\"},         // Imaginary first (not standard)\n\t\t\t{\"i\"},              // Just 'i'\n\t\t\t{\"42.42.42+1i\"},    // Invalid real part\n\t\t\t{\"42+42.42.42i\"},   // Invalid imaginary part\n\t\t\t{\"1e\"},             // Incomplete scientific notation\n\t\t\t{\"1e+\"},            // Incomplete scientific notation\n\t\t\t{\"1e-\"},            // Incomplete scientific notation\n\t\t\t{\"1e+i\"},           // Incomplete scientific notation\n\t\t\t{\"1.2.3+1i\"},       // Multiple dots in real\n\t\t\t{\"1+1.2.3i\"},       // Multiple dots in imaginary\n\t\t\t{\"1..2+1i\"},        // Double dots in real\n\t\t\t{\"1+1..2i\"},        // Double dots in imaginary\n\t\t\t{\".+.i\"},           // Just dots\n\t\t\t{\"1e1e1+1i\"},       // Multiple exponents in real\n\t\t\t{\"1+1e1e1i\"},       // Multiple exponents in imaginary\n\t\t\t{\"∞\"},              // Unicode infinity\n\t\t\t{\"∞+∞i\"},           // Unicode infinity complex\n\t\t\t{\"NaΝ\"},            // Unicode NaN lookalike\n\t\t},\n\t}\n\n\t// Custom test for NaN since NaN != NaN\n\tt.Run(\"NaN\", func(t *testing.T) {\n\t\tf := StringToComplex128HookFunc()\n\n\t\t// Test real NaN\n\t\tactual, err := DecodeHookExec(f, reflect.ValueOf(\"nan\"), reflect.ValueOf(complex128(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tc := actual.(complex128)\n\t\tif !math.IsNaN(real(c)) || imag(c) != 0 {\n\t\t\tt.Fatalf(\"expected NaN+0i, got %v\", c)\n\t\t}\n\n\t\t// Test imaginary NaN\n\t\tactual, err = DecodeHookExec(f, reflect.ValueOf(\"nani\"), reflect.ValueOf(complex128(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tc = actual.(complex128)\n\t\tif real(c) != 0 || !math.IsNaN(imag(c)) {\n\t\t\tt.Fatalf(\"expected 0+NaNi, got %v\", c)\n\t\t}\n\n\t\t// Test complex NaN\n\t\tactual, err = DecodeHookExec(f, reflect.ValueOf(\"nan+nani\"), reflect.ValueOf(complex128(0)))\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t\t}\n\t\tc = actual.(complex128)\n\t\tif !math.IsNaN(real(c)) || !math.IsNaN(imag(c)) {\n\t\t\tt.Fatalf(\"expected NaN+NaNi, got %v\", c)\n\t\t}\n\t})\n\n\tsuite.Run(t)\n}\n\nfunc TestErrorLeakageDecodeHook(t *testing.T) {\n\tcases := []struct {\n\t\tvalue         any\n\t\ttarget        any\n\t\thook          DecodeHookFunc\n\t\tallowNilError bool\n\t}{\n\t\t// case 0\n\t\t{1234, []string{}, StringToSliceHookFunc(\",\"), true},\n\t\t{\"testing\", time.Second, StringToTimeDurationHookFunc(), false},\n\t\t{\":testing\", &url.URL{}, StringToURLHookFunc(), false},\n\t\t{\"testing\", net.IP{}, StringToIPHookFunc(), false},\n\t\t{\"testing\", net.IPNet{}, StringToIPNetHookFunc(), false},\n\t\t// case 5\n\t\t{\"testing\", time.Time{}, StringToTimeHookFunc(time.RFC3339), false},\n\t\t{\"testing\", time.Time{}, StringToTimeHookFunc(time.RFC3339), false},\n\t\t{true, true, WeaklyTypedHook, true},\n\t\t{true, \"string\", WeaklyTypedHook, true},\n\t\t{1.0, \"string\", WeaklyTypedHook, true},\n\t\t// case 10\n\t\t{1, \"string\", WeaklyTypedHook, true},\n\t\t{[]uint8{0x00}, \"string\", WeaklyTypedHook, true},\n\t\t{uint(0), \"string\", WeaklyTypedHook, true},\n\t\t{struct{}{}, struct{}{}, RecursiveStructToMapHookFunc(), true},\n\t\t{\"testing\", netip.Addr{}, StringToNetIPAddrHookFunc(), false},\n\t\t// case 15\n\t\t{\"testing:testing\", netip.AddrPort{}, StringToNetIPAddrPortHookFunc(), false},\n\t\t{\"testing\", netip.Prefix{}, StringToNetIPPrefixHookFunc(), false},\n\t\t{\"testing\", int8(0), StringToInt8HookFunc(), false},\n\t\t{\"testing\", uint8(0), StringToUint8HookFunc(), false},\n\t\t// case 20\n\t\t{\"testing\", int16(0), StringToInt16HookFunc(), false},\n\t\t{\"testing\", uint16(0), StringToUint16HookFunc(), false},\n\t\t{\"testing\", int32(0), StringToInt32HookFunc(), false},\n\t\t{\"testing\", uint32(0), StringToUint32HookFunc(), false},\n\t\t{\"testing\", int64(0), StringToInt64HookFunc(), false},\n\t\t// case 25\n\t\t{\"testing\", uint64(0), StringToUint64HookFunc(), false},\n\t\t{\"testing\", int(0), StringToIntHookFunc(), false},\n\t\t{\"testing\", uint(0), StringToUintHookFunc(), false},\n\t\t{\"testing\", float32(0), StringToFloat32HookFunc(), false},\n\t\t{\"testing\", float64(0), StringToFloat64HookFunc(), false},\n\t\t// case 30\n\t\t{\"testing\", true, StringToBoolHookFunc(), false},\n\t\t{\"testing\", byte(0), StringToByteHookFunc(), false},\n\t\t{\"testing\", rune(0), StringToRuneHookFunc(), false},\n\t\t{\"testing\", complex64(0), StringToComplex64HookFunc(), false},\n\t\t{\"testing\", complex128(0), StringToComplex128HookFunc(), false},\n\t}\n\n\tfor i, tc := range cases {\n\t\tvalue := reflect.ValueOf(tc.value)\n\t\ttarget := reflect.ValueOf(tc.target)\n\t\toutput, err := DecodeHookExec(tc.hook, value, target)\n\n\t\tif err == nil {\n\t\t\tif tc.allowNilError {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt.Fatalf(\"case %d: expected error from input %v:\\n\\toutput (%T): %#v\\n\\toutput (string): %v\", i, tc.value, output, output, output)\n\t\t}\n\n\t\tstrValue := fmt.Sprintf(\"%v\", tc.value)\n\t\tif strings.Contains(err.Error(), strValue) {\n\t\t\tt.Errorf(\"case %d: error contains input value\\n\\terr: %v\\n\\tinput: %v\", i, err, strValue)\n\t\t} else {\n\t\t\tt.Logf(\"case %d: got safe error: %v\", i, err)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "devenv.nix",
    "content": "{\n  pkgs,\n  ...\n}:\n\n{\n  languages = {\n    go.enable = true;\n  };\n\n  packages = with pkgs; [\n    golangci-lint\n  ];\n}\n"
  },
  {
    "path": "devenv.yaml",
    "content": "# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json\ninputs:\n  nixpkgs:\n    url: github:cachix/devenv-nixpkgs/rolling\n"
  },
  {
    "path": "errors.go",
    "content": "package mapstructure\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"net\"\n\t\"net/url\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n)\n\n// Error interface is implemented by all errors emitted by mapstructure.\n//\n// Use [errors.As] to check if an error implements this interface.\ntype Error interface {\n\terror\n\n\tmapstructure()\n}\n\n// DecodeError is a generic error type that holds information about\n// a decoding error together with the name of the field that caused the error.\ntype DecodeError struct {\n\tname string\n\terr  error\n}\n\nfunc newDecodeError(name string, err error) *DecodeError {\n\treturn &DecodeError{\n\t\tname: name,\n\t\terr:  err,\n\t}\n}\n\nfunc (e *DecodeError) Name() string {\n\treturn e.name\n}\n\nfunc (e *DecodeError) Unwrap() error {\n\treturn e.err\n}\n\nfunc (e *DecodeError) Error() string {\n\treturn fmt.Sprintf(\"'%s' %s\", e.name, e.err)\n}\n\nfunc (*DecodeError) mapstructure() {}\n\n// ParseError is an error type that indicates a value could not be parsed\n// into the expected type.\ntype ParseError struct {\n\tExpected reflect.Value\n\tValue    any\n\tErr      error\n}\n\nfunc (e *ParseError) Error() string {\n\treturn fmt.Sprintf(\"cannot parse value as '%s': %s\", e.Expected.Type(), e.Err)\n}\n\nfunc (*ParseError) mapstructure() {}\n\n// UnconvertibleTypeError is an error type that indicates a value could not be\n// converted to the expected type.\ntype UnconvertibleTypeError struct {\n\tExpected reflect.Value\n\tValue    any\n}\n\nfunc (e *UnconvertibleTypeError) Error() string {\n\treturn fmt.Sprintf(\n\t\t\"expected type '%s', got unconvertible type '%s'\",\n\t\te.Expected.Type(),\n\t\treflect.TypeOf(e.Value),\n\t)\n}\n\nfunc (*UnconvertibleTypeError) mapstructure() {}\n\nfunc wrapStrconvNumError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif err, ok := err.(*strconv.NumError); ok {\n\t\treturn &strconvNumError{Err: err}\n\t}\n\n\treturn err\n}\n\ntype strconvNumError struct {\n\tErr *strconv.NumError\n}\n\nfunc (e *strconvNumError) Error() string {\n\treturn \"strconv.\" + e.Err.Func + \": \" + e.Err.Err.Error()\n}\n\nfunc (e *strconvNumError) Unwrap() error { return e.Err }\n\nfunc wrapUrlError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif err, ok := err.(*url.Error); ok {\n\t\treturn &urlError{Err: err}\n\t}\n\n\treturn err\n}\n\ntype urlError struct {\n\tErr *url.Error\n}\n\nfunc (e *urlError) Error() string {\n\treturn fmt.Sprintf(\"%s\", e.Err.Err)\n}\n\nfunc (e *urlError) Unwrap() error { return e.Err }\n\nfunc wrapNetParseError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif err, ok := err.(*net.ParseError); ok {\n\t\treturn &netParseError{Err: err}\n\t}\n\n\treturn err\n}\n\ntype netParseError struct {\n\tErr *net.ParseError\n}\n\nfunc (e *netParseError) Error() string {\n\treturn \"invalid \" + e.Err.Type\n}\n\nfunc (e *netParseError) Unwrap() error { return e.Err }\n\nfunc wrapTimeParseError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif err, ok := err.(*time.ParseError); ok {\n\t\treturn &timeParseError{Err: err}\n\t}\n\n\treturn err\n}\n\ntype timeParseError struct {\n\tErr *time.ParseError\n}\n\nfunc (e *timeParseError) Error() string {\n\tif e.Err.Message == \"\" {\n\t\treturn fmt.Sprintf(\"parsing time as %q: cannot parse as %q\", e.Err.Layout, e.Err.LayoutElem)\n\t}\n\n\treturn \"parsing time \" + e.Err.Message\n}\n\nfunc (e *timeParseError) Unwrap() error { return e.Err }\n\nfunc wrapNetIPParseAddrError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif errMsg := err.Error(); strings.HasPrefix(errMsg, \"ParseAddr\") {\n\t\terrPieces := strings.Split(errMsg, \": \")\n\n\t\treturn fmt.Errorf(\"ParseAddr: %s\", errPieces[len(errPieces)-1])\n\t}\n\n\treturn err\n}\n\nfunc wrapNetIPParseAddrPortError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\terrMsg := err.Error()\n\tif strings.HasPrefix(errMsg, \"invalid port \") {\n\t\treturn errors.New(\"invalid port\")\n\t} else if strings.HasPrefix(errMsg, \"invalid ip:port \") {\n\t\treturn errors.New(\"invalid ip:port\")\n\t}\n\n\treturn err\n}\n\nfunc wrapNetIPParsePrefixError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\tif errMsg := err.Error(); strings.HasPrefix(errMsg, \"netip.ParsePrefix\") {\n\t\terrPieces := strings.Split(errMsg, \": \")\n\n\t\treturn fmt.Errorf(\"netip.ParsePrefix: %s\", errPieces[len(errPieces)-1])\n\t}\n\n\treturn err\n}\n\nfunc wrapTimeParseDurationError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\n\terrMsg := err.Error()\n\tif strings.HasPrefix(errMsg, \"time: unknown unit \") {\n\t\treturn errors.New(\"time: unknown unit\")\n\t} else if strings.HasPrefix(errMsg, \"time: \") {\n\t\tidx := strings.LastIndex(errMsg, \" \")\n\n\t\treturn errors.New(errMsg[:idx])\n\t}\n\n\treturn err\n}\n\nfunc wrapTimeParseLocationError(err error) error {\n\tif err == nil {\n\t\treturn nil\n\t}\n\terrMsg := err.Error()\n\tif strings.Contains(errMsg, \"unknown time zone\") || strings.HasPrefix(errMsg, \"time: unknown format\") {\n\t\treturn fmt.Errorf(\"invalid time zone format: %w\", err)\n\t}\n\n\treturn err\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/go-viper/mapstructure/v2\n\ngo 1.18\n"
  },
  {
    "path": "internal/errors/errors.go",
    "content": "package errors\n\nimport \"errors\"\n\nfunc New(text string) error {\n\treturn errors.New(text)\n}\n\nfunc As(err error, target interface{}) bool {\n\treturn errors.As(err, target)\n}\n"
  },
  {
    "path": "internal/errors/join.go",
    "content": "//go:build go1.20\n\npackage errors\n\nimport \"errors\"\n\nfunc Join(errs ...error) error {\n\treturn errors.Join(errs...)\n}\n"
  },
  {
    "path": "internal/errors/join_go1_19.go",
    "content": "//go:build !go1.20\n\n// Copyright 2022 The Go Authors. All rights reserved.\n// Use of this source code is governed by a BSD-style\n// license that can be found in the LICENSE file.\n\npackage errors\n\n// Join returns an error that wraps the given errors.\n// Any nil error values are discarded.\n// Join returns nil if every value in errs is nil.\n// The error formats as the concatenation of the strings obtained\n// by calling the Error method of each element of errs, with a newline\n// between each string.\n//\n// A non-nil error returned by Join implements the Unwrap() []error method.\nfunc Join(errs ...error) error {\n\tn := 0\n\tfor _, err := range errs {\n\t\tif err != nil {\n\t\t\tn++\n\t\t}\n\t}\n\tif n == 0 {\n\t\treturn nil\n\t}\n\te := &joinError{\n\t\terrs: make([]error, 0, n),\n\t}\n\tfor _, err := range errs {\n\t\tif err != nil {\n\t\t\te.errs = append(e.errs, err)\n\t\t}\n\t}\n\treturn e\n}\n\ntype joinError struct {\n\terrs []error\n}\n\nfunc (e *joinError) Error() string {\n\t// Since Join returns nil if every value in errs is nil,\n\t// e.errs cannot be empty.\n\tif len(e.errs) == 1 {\n\t\treturn e.errs[0].Error()\n\t}\n\n\tb := []byte(e.errs[0].Error())\n\tfor _, err := range e.errs[1:] {\n\t\tb = append(b, '\\n')\n\t\tb = append(b, err.Error()...)\n\t}\n\t// At this point, b has at least one byte '\\n'.\n\t// return unsafe.String(&b[0], len(b))\n\treturn string(b)\n}\n\nfunc (e *joinError) Unwrap() []error {\n\treturn e.errs\n}\n"
  },
  {
    "path": "mapstructure.go",
    "content": "// Package mapstructure exposes functionality to convert one arbitrary\n// Go type into another, typically to convert a map[string]any\n// into a native Go structure.\n//\n// The Go structure can be arbitrarily complex, containing slices,\n// other structs, etc. and the decoder will properly decode nested\n// maps and so on into the proper structures in the native Go struct.\n// See the examples to see what the decoder is capable of.\n//\n// The simplest function to start with is Decode.\n//\n// # Field Tags\n//\n// When decoding to a struct, mapstructure will use the field name by\n// default to perform the mapping. For example, if a struct has a field\n// \"Username\" then mapstructure will look for a key in the source value\n// of \"username\" (case insensitive).\n//\n//\ttype User struct {\n//\t    Username string\n//\t}\n//\n// You can change the behavior of mapstructure by using struct tags.\n// The default struct tag that mapstructure looks for is \"mapstructure\"\n// but you can customize it using DecoderConfig.\n//\n// # Renaming Fields\n//\n// To rename the key that mapstructure looks for, use the \"mapstructure\"\n// tag and set a value directly. For example, to change the \"username\" example\n// above to \"user\":\n//\n//\ttype User struct {\n//\t    Username string `mapstructure:\"user\"`\n//\t}\n//\n// # Embedded Structs and Squashing\n//\n// Embedded structs are treated as if they're another field with that name.\n// By default, the two structs below are equivalent when decoding with\n// mapstructure:\n//\n//\ttype Person struct {\n//\t    Name string\n//\t}\n//\n//\ttype Friend struct {\n//\t    Person\n//\t}\n//\n//\ttype Friend struct {\n//\t    Person Person\n//\t}\n//\n// This would require an input that looks like below:\n//\n//\tmap[string]any{\n//\t    \"person\": map[string]any{\"name\": \"alice\"},\n//\t}\n//\n// If your \"person\" value is NOT nested, then you can append \",squash\" to\n// your tag value and mapstructure will treat it as if the embedded struct\n// were part of the struct directly. Example:\n//\n//\ttype Friend struct {\n//\t    Person `mapstructure:\",squash\"`\n//\t}\n//\n// Now the following input would be accepted:\n//\n//\tmap[string]any{\n//\t    \"name\": \"alice\",\n//\t}\n//\n// When decoding from a struct to a map, the squash tag squashes the struct\n// fields into a single map. Using the example structs from above:\n//\n//\tFriend{Person: Person{Name: \"alice\"}}\n//\n// Will be decoded into a map:\n//\n//\tmap[string]any{\n//\t    \"name\": \"alice\",\n//\t}\n//\n// DecoderConfig has a field that changes the behavior of mapstructure\n// to always squash embedded structs.\n//\n// # Remainder Values\n//\n// If there are any unmapped keys in the source value, mapstructure by\n// default will silently ignore them. You can error by setting ErrorUnused\n// in DecoderConfig. If you're using Metadata you can also maintain a slice\n// of the unused keys.\n//\n// You can also use the \",remain\" suffix on your tag to collect all unused\n// values in a map. The field with this tag MUST be a map type and should\n// probably be a \"map[string]any\" or \"map[any]any\".\n// See example below:\n//\n//\ttype Friend struct {\n//\t    Name  string\n//\t    Other map[string]any `mapstructure:\",remain\"`\n//\t}\n//\n// Given the input below, Other would be populated with the other\n// values that weren't used (everything but \"name\"):\n//\n//\tmap[string]any{\n//\t    \"name\":    \"bob\",\n//\t    \"address\": \"123 Maple St.\",\n//\t}\n//\n// # Omit Empty Values\n//\n// When decoding from a struct to any other value, you may use the\n// \",omitempty\" suffix on your tag to omit that value if it equates to\n// the zero value, or a zero-length element. The zero value of all types is\n// specified in the Go specification.\n//\n// For example, the zero type of a numeric type is zero (\"0\"). If the struct\n// field value is zero and a numeric type, the field is empty, and it won't\n// be encoded into the destination type. And likewise for the URLs field, if the\n// slice is nil or empty, it won't be encoded into the destination type.\n//\n//\ttype Source struct {\n//\t    Age  int      `mapstructure:\",omitempty\"`\n//\t    URLs []string `mapstructure:\",omitempty\"`\n//\t}\n//\n// # Omit Zero Values\n//\n// When decoding from a struct to any other value, you may use the\n// \",omitzero\" suffix on your tag to omit that value if it equates to the zero\n// value. The zero value of all types is specified in the Go specification.\n//\n// For example, the zero type of a numeric type is zero (\"0\"). If the struct\n// field value is zero and a numeric type, the field is empty, and it won't\n// be encoded into the destination type. And likewise for the URLs field, if the\n// slice is nil, it won't be encoded into the destination type.\n//\n// Note that if the field is a slice, and it is empty but not nil, it will\n// still be encoded into the destination type.\n//\n//\ttype Source struct {\n//\t    Age  int      `mapstructure:\",omitzero\"`\n//\t    URLs []string `mapstructure:\",omitzero\"`\n//\t}\n//\n// # Unexported fields\n//\n// Since unexported (private) struct fields cannot be set outside the package\n// where they are defined, the decoder will simply skip them.\n//\n// For this output type definition:\n//\n//\ttype Exported struct {\n//\t    private string // this unexported field will be skipped\n//\t    Public string\n//\t}\n//\n// Using this map as input:\n//\n//\tmap[string]any{\n//\t    \"private\": \"I will be ignored\",\n//\t    \"Public\":  \"I made it through!\",\n//\t}\n//\n// The following struct will be decoded:\n//\n//\ttype Exported struct {\n//\t    private: \"\" // field is left with an empty string (zero value)\n//\t    Public: \"I made it through!\"\n//\t}\n//\n// # Custom Decoding with Unmarshaler\n//\n// Types can implement the Unmarshaler interface to control their own decoding. The interface\n// behaves similarly to how UnmarshalJSON does in the standard library. It can be used as an\n// alternative or companion to a DecodeHook.\n//\n//\ttype TrimmedString string\n//\n//\tfunc (t *TrimmedString) UnmarshalMapstructure(input any) error {\n//\t    str, ok := input.(string)\n//\t    if !ok {\n//\t        return fmt.Errorf(\"expected string, got %T\", input)\n//\t    }\n//\t    *t = TrimmedString(strings.TrimSpace(str))\n//\t    return nil\n//\t}\n//\n// See the Unmarshaler interface documentation for more details.\n//\n// # Other Configuration\n//\n// mapstructure is highly configurable. See the DecoderConfig struct\n// for other features and options that are supported.\npackage mapstructure\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/go-viper/mapstructure/v2/internal/errors\"\n)\n\n// DecodeHookFunc is the callback function that can be used for\n// data transformations. See \"DecodeHook\" in the DecoderConfig\n// struct.\n//\n// The type must be one of DecodeHookFuncType, DecodeHookFuncKind, or\n// DecodeHookFuncValue.\n// Values are a superset of Types (Values can return types), and Types are a\n// superset of Kinds (Types can return Kinds) and are generally a richer thing\n// to use, but Kinds are simpler if you only need those.\n//\n// The reason DecodeHookFunc is multi-typed is for backwards compatibility:\n// we started with Kinds and then realized Types were the better solution,\n// but have a promise to not break backwards compat so we now support\n// both.\ntype DecodeHookFunc any\n\n// DecodeHookFuncType is a DecodeHookFunc which has complete information about\n// the source and target types.\ntype DecodeHookFuncType func(reflect.Type, reflect.Type, any) (any, error)\n\n// DecodeHookFuncKind is a DecodeHookFunc which knows only the Kinds of the\n// source and target types.\ntype DecodeHookFuncKind func(reflect.Kind, reflect.Kind, any) (any, error)\n\n// DecodeHookFuncValue is a DecodeHookFunc which has complete access to both the source and target\n// values.\ntype DecodeHookFuncValue func(from reflect.Value, to reflect.Value) (any, error)\n\n// Unmarshaler is the interface implemented by types that can unmarshal\n// themselves. UnmarshalMapstructure receives the input data (potentially\n// transformed by DecodeHook) and should populate the receiver with the\n// decoded values.\n//\n// The Unmarshaler interface takes precedence over the default decoding\n// logic for any type (structs, slices, maps, primitives, etc.).\ntype Unmarshaler interface {\n\tUnmarshalMapstructure(any) error\n}\n\n// DecoderConfig is the configuration that is used to create a new decoder\n// and allows customization of various aspects of decoding.\ntype DecoderConfig struct {\n\t// DecodeHook, if set, will be called before any decoding and any\n\t// type conversion (if WeaklyTypedInput is on). This lets you modify\n\t// the values before they're set down onto the resulting struct. The\n\t// DecodeHook is called for every map and value in the input. This means\n\t// that if a struct has embedded fields with squash tags the decode hook\n\t// is called only once with all of the input data, not once for each\n\t// embedded struct.\n\t//\n\t// If an error is returned, the entire decode will fail with that error.\n\tDecodeHook DecodeHookFunc\n\n\t// If ErrorUnused is true, then it is an error for there to exist\n\t// keys in the original map that were unused in the decoding process\n\t// (extra keys).\n\tErrorUnused bool\n\n\t// If ErrorUnset is true, then it is an error for there to exist\n\t// fields in the result that were not set in the decoding process\n\t// (extra fields). This only applies to decoding to a struct. This\n\t// will affect all nested structs as well.\n\tErrorUnset bool\n\n\t// AllowUnsetPointer, if set to true, will prevent fields with pointer types\n\t// from being reported as unset, even if ErrorUnset is true and the field was\n\t// not present in the input data. This allows pointer fields to be optional\n\t// without triggering an error when they are missing.\n\tAllowUnsetPointer bool\n\n\t// ZeroFields, if set to true, will zero fields before writing them.\n\t// For example, a map will be emptied before decoded values are put in\n\t// it. If this is false, a map will be merged.\n\tZeroFields bool\n\n\t// If WeaklyTypedInput is true, the decoder will make the following\n\t// \"weak\" conversions:\n\t//\n\t//   - bools to string (true = \"1\", false = \"0\")\n\t//   - numbers to string (base 10)\n\t//   - bools to int/uint (true = 1, false = 0)\n\t//   - strings to int/uint (base implied by prefix)\n\t//   - int to bool (true if value != 0)\n\t//   - string to bool (accepts: 1, t, T, TRUE, true, True, 0, f, F,\n\t//     FALSE, false, False. Anything else is an error)\n\t//   - empty array = empty map and vice versa\n\t//   - negative numbers to overflowed uint values (base 10)\n\t//   - slice of maps to a merged map\n\t//   - single values are converted to slices if required. Each\n\t//     element is weakly decoded. For example: \"4\" can become []int{4}\n\t//     if the target type is an int slice.\n\t//\n\tWeaklyTypedInput bool\n\n\t// Squash will squash embedded structs.  A squash tag may also be\n\t// added to an individual struct field using a tag.  For example:\n\t//\n\t//  type Parent struct {\n\t//      Child `mapstructure:\",squash\"`\n\t//  }\n\tSquash bool\n\n\t// Deep will map structures in slices instead of copying them\n\t//\n\t//  type Parent struct {\n\t//      Children []Child `mapstructure:\",deep\"`\n\t//  }\n\tDeep bool\n\n\t// Metadata is the struct that will contain extra metadata about\n\t// the decoding. If this is nil, then no metadata will be tracked.\n\tMetadata *Metadata\n\n\t// Result is a pointer to the struct that will contain the decoded\n\t// value.\n\tResult any\n\n\t// The tag name that mapstructure reads for field names. This\n\t// defaults to \"mapstructure\". Multiple tag names can be specified\n\t// as a comma-separated list (e.g., \"yaml,json\"), and the first\n\t// matching non-empty tag will be used.\n\tTagName string\n\n\t// RootName specifies the name to use for the root element in error messages. For example:\n\t//   '<rootName>' has unset fields: <fieldName>\n\tRootName string\n\n\t// The option of the value in the tag that indicates a field should\n\t// be squashed. This defaults to \"squash\".\n\tSquashTagOption string\n\n\t// IgnoreUntaggedFields ignores all struct fields without explicit\n\t// TagName, comparable to `mapstructure:\"-\"` as default behaviour.\n\tIgnoreUntaggedFields bool\n\n\t// MatchName is the function used to match the map key to the struct\n\t// field name or tag. Defaults to `strings.EqualFold`. This can be used\n\t// to implement case-sensitive tag values, support snake casing, etc.\n\t//\n\t// MatchName is used as a fallback comparison when the direct key lookup fails.\n\t// See also MapFieldName for transforming field names before lookup.\n\tMatchName func(mapKey, fieldName string) bool\n\n\t// DecodeNil, if set to true, will cause the DecodeHook (if present) to run\n\t// even if the input is nil. This can be used to provide default values.\n\tDecodeNil bool\n\n\t// MapFieldName is the function used to convert the struct field name to the map's key name.\n\t//\n\t// This is useful for automatically converting between naming conventions without\n\t// explicitly tagging each field. For example, to convert Go's PascalCase field names\n\t// to snake_case map keys:\n\t//\n\t//\tMapFieldName: func(s string) string {\n\t//\t    return strcase.ToSnake(s)\n\t//\t}\n\t//\n\t// When decoding from a map to a struct, the transformed field name is used for\n\t// the initial lookup. If not found, MatchName is used as a fallback comparison.\n\t// Explicit struct tags always take precedence over MapFieldName.\n\tMapFieldName func(string) string\n\n\t// DisableUnmarshaler, if set to true, disables the use of the Unmarshaler\n\t// interface. Types implementing Unmarshaler will be decoded using the\n\t// standard struct decoding logic instead.\n\tDisableUnmarshaler bool\n}\n\n// A Decoder takes a raw interface value and turns it into structured\n// data, keeping track of rich error information along the way in case\n// anything goes wrong. Unlike the basic top-level Decode method, you can\n// more finely control how the Decoder behaves using the DecoderConfig\n// structure. The top-level Decode method is just a convenience that sets\n// up the most basic Decoder.\ntype Decoder struct {\n\tconfig           *DecoderConfig\n\tcachedDecodeHook func(from reflect.Value, to reflect.Value) (any, error)\n}\n\n// Metadata contains information about decoding a structure that\n// is tedious or difficult to get otherwise.\ntype Metadata struct {\n\t// Keys are the keys of the structure which were successfully decoded\n\tKeys []string\n\n\t// Unused is a slice of keys that were found in the raw value but\n\t// weren't decoded since there was no matching field in the result interface\n\tUnused []string\n\n\t// Unset is a slice of field names that were found in the result interface\n\t// but weren't set in the decoding process since there was no matching value\n\t// in the input\n\tUnset []string\n}\n\n// Decode takes an input structure and uses reflection to translate it to\n// the output structure. output must be a pointer to a map or struct.\nfunc Decode(input any, output any) error {\n\tconfig := &DecoderConfig{\n\t\tMetadata: nil,\n\t\tResult:   output,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn decoder.Decode(input)\n}\n\n// WeakDecode is the same as Decode but is shorthand to enable\n// WeaklyTypedInput. See DecoderConfig for more info.\nfunc WeakDecode(input, output any) error {\n\tconfig := &DecoderConfig{\n\t\tMetadata:         nil,\n\t\tResult:           output,\n\t\tWeaklyTypedInput: true,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn decoder.Decode(input)\n}\n\n// DecodeMetadata is the same as Decode, but is shorthand to\n// enable metadata collection. See DecoderConfig for more info.\nfunc DecodeMetadata(input any, output any, metadata *Metadata) error {\n\tconfig := &DecoderConfig{\n\t\tMetadata: metadata,\n\t\tResult:   output,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn decoder.Decode(input)\n}\n\n// WeakDecodeMetadata is the same as Decode, but is shorthand to\n// enable both WeaklyTypedInput and metadata collection. See\n// DecoderConfig for more info.\nfunc WeakDecodeMetadata(input any, output any, metadata *Metadata) error {\n\tconfig := &DecoderConfig{\n\t\tMetadata:         metadata,\n\t\tResult:           output,\n\t\tWeaklyTypedInput: true,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn decoder.Decode(input)\n}\n\n// NewDecoder returns a new decoder for the given configuration. Once\n// a decoder has been returned, the same configuration must not be used\n// again.\nfunc NewDecoder(config *DecoderConfig) (*Decoder, error) {\n\tval := reflect.ValueOf(config.Result)\n\tif val.Kind() != reflect.Ptr {\n\t\treturn nil, errors.New(\"result must be a pointer\")\n\t}\n\n\tval = val.Elem()\n\tif !val.CanAddr() {\n\t\treturn nil, errors.New(\"result must be addressable (a pointer)\")\n\t}\n\n\tif config.Metadata != nil {\n\t\tif config.Metadata.Keys == nil {\n\t\t\tconfig.Metadata.Keys = make([]string, 0)\n\t\t}\n\n\t\tif config.Metadata.Unused == nil {\n\t\t\tconfig.Metadata.Unused = make([]string, 0)\n\t\t}\n\n\t\tif config.Metadata.Unset == nil {\n\t\t\tconfig.Metadata.Unset = make([]string, 0)\n\t\t}\n\t}\n\n\tif config.TagName == \"\" {\n\t\tconfig.TagName = \"mapstructure\"\n\t}\n\n\tif config.SquashTagOption == \"\" {\n\t\tconfig.SquashTagOption = \"squash\"\n\t}\n\n\tif config.MatchName == nil {\n\t\tconfig.MatchName = strings.EqualFold\n\t}\n\n\tif config.MapFieldName == nil {\n\t\tconfig.MapFieldName = func(s string) string {\n\t\t\treturn s\n\t\t}\n\t}\n\n\tresult := &Decoder{\n\t\tconfig: config,\n\t}\n\tif config.DecodeHook != nil {\n\t\tresult.cachedDecodeHook = cachedDecodeHook(config.DecodeHook)\n\t}\n\n\treturn result, nil\n}\n\n// Decode decodes the given raw interface to the target pointer specified\n// by the configuration.\nfunc (d *Decoder) Decode(input any) error {\n\terr := d.decode(d.config.RootName, input, reflect.ValueOf(d.config.Result).Elem())\n\n\t// Retain some of the original behavior when multiple errors ocurr\n\tvar joinedErr interface{ Unwrap() []error }\n\tif errors.As(err, &joinedErr) {\n\t\treturn fmt.Errorf(\"decoding failed due to the following error(s):\\n\\n%w\", err)\n\t}\n\n\treturn err\n}\n\n// isNil returns true if the input is nil or a typed nil pointer.\nfunc isNil(input any) bool {\n\tif input == nil {\n\t\treturn true\n\t}\n\tval := reflect.ValueOf(input)\n\treturn val.Kind() == reflect.Ptr && val.IsNil()\n}\n\n// Decodes an unknown data type into a specific reflection value.\nfunc (d *Decoder) decode(name string, input any, outVal reflect.Value) error {\n\tvar (\n\t\tinputVal   = reflect.ValueOf(input)\n\t\toutputKind = getKind(outVal)\n\t\tdecodeNil  = d.config.DecodeNil && d.cachedDecodeHook != nil\n\t)\n\tif isNil(input) {\n\t\t// Typed nils won't match the \"input == nil\" below, so reset input.\n\t\tinput = nil\n\t}\n\tif input == nil {\n\t\t// If the data is nil, then we don't set anything, unless ZeroFields is set\n\t\t// to true.\n\t\tif d.config.ZeroFields {\n\t\t\toutVal.Set(reflect.Zero(outVal.Type()))\n\n\t\t\tif d.config.Metadata != nil && name != \"\" {\n\t\t\t\td.config.Metadata.Keys = append(d.config.Metadata.Keys, name)\n\t\t\t}\n\t\t}\n\t\tif !decodeNil {\n\t\t\treturn nil\n\t\t}\n\t}\n\tif !inputVal.IsValid() {\n\t\tif !decodeNil {\n\t\t\t// If the input value is invalid, then we just set the value\n\t\t\t// to be the zero value.\n\t\t\toutVal.Set(reflect.Zero(outVal.Type()))\n\t\t\tif d.config.Metadata != nil && name != \"\" {\n\t\t\t\td.config.Metadata.Keys = append(d.config.Metadata.Keys, name)\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\t// Hooks need a valid inputVal, so reset it to zero value of outVal type.\n\t\tswitch outputKind {\n\t\tcase reflect.Struct, reflect.Map:\n\t\t\tvar mapVal map[string]any\n\t\t\tinputVal = reflect.ValueOf(mapVal) // create nil map pointer\n\t\tcase reflect.Slice, reflect.Array:\n\t\t\tvar sliceVal []any\n\t\t\tinputVal = reflect.ValueOf(sliceVal) // create nil slice pointer\n\t\tdefault:\n\t\t\tinputVal = reflect.Zero(outVal.Type())\n\t\t}\n\t}\n\n\tif d.cachedDecodeHook != nil {\n\t\t// We have a DecodeHook, so let's pre-process the input.\n\t\tvar err error\n\t\tinput, err = d.cachedDecodeHook(inputVal, outVal)\n\t\tif err != nil {\n\t\t\treturn newDecodeError(name, err)\n\t\t}\n\t}\n\tif isNil(input) {\n\t\treturn nil\n\t}\n\n\tvar err error\n\taddMetaKey := true\n\n\t// Check if the target implements Unmarshaler and use it if not disabled\n\tunmarshaled := false\n\tif !d.config.DisableUnmarshaler {\n\t\tif unmarshaler, ok := getUnmarshaler(outVal); ok {\n\t\t\tif err = unmarshaler.UnmarshalMapstructure(input); err != nil {\n\t\t\t\terr = newDecodeError(name, err)\n\t\t\t}\n\t\t\tunmarshaled = true\n\t\t}\n\t}\n\n\tif !unmarshaled {\n\t\tswitch outputKind {\n\t\tcase reflect.Bool:\n\t\t\terr = d.decodeBool(name, input, outVal)\n\t\tcase reflect.Interface:\n\t\t\terr = d.decodeBasic(name, input, outVal)\n\t\tcase reflect.String:\n\t\t\terr = d.decodeString(name, input, outVal)\n\t\tcase reflect.Int:\n\t\t\terr = d.decodeInt(name, input, outVal)\n\t\tcase reflect.Uint:\n\t\t\terr = d.decodeUint(name, input, outVal)\n\t\tcase reflect.Float32:\n\t\t\terr = d.decodeFloat(name, input, outVal)\n\t\tcase reflect.Complex64:\n\t\t\terr = d.decodeComplex(name, input, outVal)\n\t\tcase reflect.Struct:\n\t\t\terr = d.decodeStruct(name, input, outVal)\n\t\tcase reflect.Map:\n\t\t\terr = d.decodeMap(name, input, outVal)\n\t\tcase reflect.Ptr:\n\t\t\taddMetaKey, err = d.decodePtr(name, input, outVal)\n\t\tcase reflect.Slice:\n\t\t\terr = d.decodeSlice(name, input, outVal)\n\t\tcase reflect.Array:\n\t\t\terr = d.decodeArray(name, input, outVal)\n\t\tcase reflect.Func:\n\t\t\terr = d.decodeFunc(name, input, outVal)\n\t\tdefault:\n\t\t\t// If we reached this point then we weren't able to decode it\n\t\t\treturn newDecodeError(name, fmt.Errorf(\"unsupported type: %s\", outputKind))\n\t\t}\n\t}\n\n\t// If we reached here, then we successfully decoded SOMETHING, so\n\t// mark the key as used if we're tracking metainput.\n\tif addMetaKey && d.config.Metadata != nil && name != \"\" {\n\t\td.config.Metadata.Keys = append(d.config.Metadata.Keys, name)\n\t}\n\n\treturn err\n}\n\n// This decodes a basic type (bool, int, string, etc.) and sets the\n// value to \"data\" of that type.\nfunc (d *Decoder) decodeBasic(name string, data any, val reflect.Value) error {\n\tif val.IsValid() && val.Elem().IsValid() {\n\t\telem := val.Elem()\n\n\t\t// If we can't address this element, then its not writable. Instead,\n\t\t// we make a copy of the value (which is a pointer and therefore\n\t\t// writable), decode into that, and replace the whole value.\n\t\tcopied := false\n\t\tif !elem.CanAddr() {\n\t\t\tcopied = true\n\n\t\t\t// Make *T\n\t\t\tcopy := reflect.New(elem.Type())\n\n\t\t\t// *T = elem\n\t\t\tcopy.Elem().Set(elem)\n\n\t\t\t// Set elem so we decode into it\n\t\t\telem = copy\n\t\t}\n\n\t\t// Decode. If we have an error then return. We also return right\n\t\t// away if we're not a copy because that means we decoded directly.\n\t\tif err := d.decode(name, data, elem); err != nil || !copied {\n\t\t\treturn err\n\t\t}\n\n\t\t// If we're a copy, we need to set te final result\n\t\tval.Set(elem.Elem())\n\t\treturn nil\n\t}\n\n\tdataVal := reflect.ValueOf(data)\n\n\t// If the input data is a pointer, and the assigned type is the dereference\n\t// of that exact pointer, then indirect it so that we can assign it.\n\t// Example: *string to string\n\tif dataVal.Kind() == reflect.Ptr && dataVal.Type().Elem() == val.Type() {\n\t\tdataVal = reflect.Indirect(dataVal)\n\t}\n\n\tif !dataVal.IsValid() {\n\t\tdataVal = reflect.Zero(val.Type())\n\t}\n\n\tdataValType := dataVal.Type()\n\tif !dataValType.AssignableTo(val.Type()) {\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\n\tval.Set(dataVal)\n\treturn nil\n}\n\nfunc (d *Decoder) decodeString(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataKind := getKind(dataVal)\n\n\tconverted := true\n\tswitch {\n\tcase dataKind == reflect.String:\n\t\tval.SetString(dataVal.String())\n\tcase dataKind == reflect.Bool && d.config.WeaklyTypedInput:\n\t\tif dataVal.Bool() {\n\t\t\tval.SetString(\"1\")\n\t\t} else {\n\t\t\tval.SetString(\"0\")\n\t\t}\n\tcase dataKind == reflect.Int && d.config.WeaklyTypedInput:\n\t\tval.SetString(strconv.FormatInt(dataVal.Int(), 10))\n\tcase dataKind == reflect.Uint && d.config.WeaklyTypedInput:\n\t\tval.SetString(strconv.FormatUint(dataVal.Uint(), 10))\n\tcase dataKind == reflect.Float32 && d.config.WeaklyTypedInput:\n\t\tval.SetString(strconv.FormatFloat(dataVal.Float(), 'f', -1, 64))\n\tcase dataKind == reflect.Slice && d.config.WeaklyTypedInput,\n\t\tdataKind == reflect.Array && d.config.WeaklyTypedInput:\n\t\tdataType := dataVal.Type()\n\t\telemKind := dataType.Elem().Kind()\n\t\tswitch elemKind {\n\t\tcase reflect.Uint8:\n\t\t\tvar uints []uint8\n\t\t\tif dataKind == reflect.Array {\n\t\t\t\tuints = make([]uint8, dataVal.Len())\n\t\t\t\tfor i := range uints {\n\t\t\t\t\tuints[i] = dataVal.Index(i).Interface().(uint8)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tuints = dataVal.Interface().([]uint8)\n\t\t\t}\n\t\t\tval.SetString(string(uints))\n\t\tdefault:\n\t\t\tconverted = false\n\t\t}\n\tdefault:\n\t\tconverted = false\n\t}\n\n\tif !converted {\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodeInt(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataKind := getKind(dataVal)\n\tdataType := dataVal.Type()\n\n\tswitch {\n\tcase dataKind == reflect.Int:\n\t\tval.SetInt(dataVal.Int())\n\tcase dataKind == reflect.Uint:\n\t\tval.SetInt(int64(dataVal.Uint()))\n\tcase dataKind == reflect.Float32:\n\t\tval.SetInt(int64(dataVal.Float()))\n\tcase dataKind == reflect.Bool && d.config.WeaklyTypedInput:\n\t\tif dataVal.Bool() {\n\t\t\tval.SetInt(1)\n\t\t} else {\n\t\t\tval.SetInt(0)\n\t\t}\n\tcase dataKind == reflect.String && d.config.WeaklyTypedInput:\n\t\tstr := dataVal.String()\n\t\tif str == \"\" {\n\t\t\tstr = \"0\"\n\t\t}\n\n\t\ti, err := strconv.ParseInt(str, 0, val.Type().Bits())\n\t\tif err == nil {\n\t\t\tval.SetInt(i)\n\t\t} else {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      wrapStrconvNumError(err),\n\t\t\t})\n\t\t}\n\tcase dataType.PkgPath() == \"encoding/json\" && dataType.Name() == \"Number\":\n\t\tjn := data.(json.Number)\n\t\ti, err := jn.Int64()\n\t\tif err != nil {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      err,\n\t\t\t})\n\t\t}\n\t\tval.SetInt(i)\n\tdefault:\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodeUint(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataKind := getKind(dataVal)\n\tdataType := dataVal.Type()\n\n\tswitch {\n\tcase dataKind == reflect.Int:\n\t\ti := dataVal.Int()\n\t\tif i < 0 && !d.config.WeaklyTypedInput {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      fmt.Errorf(\"%d overflows uint\", i),\n\t\t\t})\n\t\t}\n\t\tval.SetUint(uint64(i))\n\tcase dataKind == reflect.Uint:\n\t\tval.SetUint(dataVal.Uint())\n\tcase dataKind == reflect.Float32:\n\t\tf := dataVal.Float()\n\t\tif f < 0 && !d.config.WeaklyTypedInput {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      fmt.Errorf(\"%f overflows uint\", f),\n\t\t\t})\n\t\t}\n\t\tval.SetUint(uint64(f))\n\tcase dataKind == reflect.Bool && d.config.WeaklyTypedInput:\n\t\tif dataVal.Bool() {\n\t\t\tval.SetUint(1)\n\t\t} else {\n\t\t\tval.SetUint(0)\n\t\t}\n\tcase dataKind == reflect.String && d.config.WeaklyTypedInput:\n\t\tstr := dataVal.String()\n\t\tif str == \"\" {\n\t\t\tstr = \"0\"\n\t\t}\n\n\t\ti, err := strconv.ParseUint(str, 0, val.Type().Bits())\n\t\tif err == nil {\n\t\t\tval.SetUint(i)\n\t\t} else {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      wrapStrconvNumError(err),\n\t\t\t})\n\t\t}\n\tcase dataType.PkgPath() == \"encoding/json\" && dataType.Name() == \"Number\":\n\t\tjn := data.(json.Number)\n\t\ti, err := strconv.ParseUint(string(jn), 0, 64)\n\t\tif err != nil {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      wrapStrconvNumError(err),\n\t\t\t})\n\t\t}\n\t\tval.SetUint(i)\n\tdefault:\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodeBool(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataKind := getKind(dataVal)\n\n\tswitch {\n\tcase dataKind == reflect.Bool:\n\t\tval.SetBool(dataVal.Bool())\n\tcase dataKind == reflect.Int && d.config.WeaklyTypedInput:\n\t\tval.SetBool(dataVal.Int() != 0)\n\tcase dataKind == reflect.Uint && d.config.WeaklyTypedInput:\n\t\tval.SetBool(dataVal.Uint() != 0)\n\tcase dataKind == reflect.Float32 && d.config.WeaklyTypedInput:\n\t\tval.SetBool(dataVal.Float() != 0)\n\tcase dataKind == reflect.String && d.config.WeaklyTypedInput:\n\t\tb, err := strconv.ParseBool(dataVal.String())\n\t\tif err == nil {\n\t\t\tval.SetBool(b)\n\t\t} else if dataVal.String() == \"\" {\n\t\t\tval.SetBool(false)\n\t\t} else {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      wrapStrconvNumError(err),\n\t\t\t})\n\t\t}\n\tdefault:\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodeFloat(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataKind := getKind(dataVal)\n\tdataType := dataVal.Type()\n\n\tswitch {\n\tcase dataKind == reflect.Int:\n\t\tval.SetFloat(float64(dataVal.Int()))\n\tcase dataKind == reflect.Uint:\n\t\tval.SetFloat(float64(dataVal.Uint()))\n\tcase dataKind == reflect.Float32:\n\t\tval.SetFloat(dataVal.Float())\n\tcase dataKind == reflect.Bool && d.config.WeaklyTypedInput:\n\t\tif dataVal.Bool() {\n\t\t\tval.SetFloat(1)\n\t\t} else {\n\t\t\tval.SetFloat(0)\n\t\t}\n\tcase dataKind == reflect.String && d.config.WeaklyTypedInput:\n\t\tstr := dataVal.String()\n\t\tif str == \"\" {\n\t\t\tstr = \"0\"\n\t\t}\n\n\t\tf, err := strconv.ParseFloat(str, val.Type().Bits())\n\t\tif err == nil {\n\t\t\tval.SetFloat(f)\n\t\t} else {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      wrapStrconvNumError(err),\n\t\t\t})\n\t\t}\n\tcase dataType.PkgPath() == \"encoding/json\" && dataType.Name() == \"Number\":\n\t\tjn := data.(json.Number)\n\t\ti, err := jn.Float64()\n\t\tif err != nil {\n\t\t\treturn newDecodeError(name, &ParseError{\n\t\t\t\tExpected: val,\n\t\t\t\tValue:    data,\n\t\t\t\tErr:      err,\n\t\t\t})\n\t\t}\n\t\tval.SetFloat(i)\n\tdefault:\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodeComplex(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataKind := getKind(dataVal)\n\n\tswitch {\n\tcase dataKind == reflect.Complex64:\n\t\tval.SetComplex(dataVal.Complex())\n\tdefault:\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodeMap(name string, data any, val reflect.Value) error {\n\tvalType := val.Type()\n\tvalKeyType := valType.Key()\n\tvalElemType := valType.Elem()\n\n\t// By default we overwrite keys in the current map\n\tvalMap := val\n\n\t// If the map is nil or we're purposely zeroing fields, make a new map\n\tif valMap.IsNil() || d.config.ZeroFields {\n\t\t// Make a new map to hold our result\n\t\tmapType := reflect.MapOf(valKeyType, valElemType)\n\t\tvalMap = reflect.MakeMap(mapType)\n\t}\n\n\tdataVal := reflect.ValueOf(data)\n\n\t// Resolve any levels of indirection\n\tfor dataVal.Kind() == reflect.Pointer {\n\t\tdataVal = reflect.Indirect(dataVal)\n\t}\n\n\t// Check input type and based on the input type jump to the proper func\n\tswitch dataVal.Kind() {\n\tcase reflect.Map:\n\t\treturn d.decodeMapFromMap(name, dataVal, val, valMap)\n\n\tcase reflect.Struct:\n\t\treturn d.decodeMapFromStruct(name, dataVal, val, valMap)\n\n\tcase reflect.Array, reflect.Slice:\n\t\tif d.config.WeaklyTypedInput {\n\t\t\treturn d.decodeMapFromSlice(name, dataVal, val, valMap)\n\t\t}\n\n\t\tfallthrough\n\n\tdefault:\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n}\n\nfunc (d *Decoder) decodeMapFromSlice(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {\n\t// Special case for BC reasons (covered by tests)\n\tif dataVal.Len() == 0 {\n\t\tval.Set(valMap)\n\t\treturn nil\n\t}\n\n\tfor i := 0; i < dataVal.Len(); i++ {\n\t\terr := d.decode(\n\t\t\tname+\"[\"+strconv.Itoa(i)+\"]\",\n\t\t\tdataVal.Index(i).Interface(), val)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodeMapFromMap(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {\n\tvalType := val.Type()\n\tvalKeyType := valType.Key()\n\tvalElemType := valType.Elem()\n\n\t// Accumulate errors\n\tvar errs []error\n\n\t// If the input data is empty, then we just match what the input data is.\n\tif dataVal.Len() == 0 {\n\t\tif dataVal.IsNil() {\n\t\t\tif !val.IsNil() {\n\t\t\t\tval.Set(dataVal)\n\t\t\t}\n\t\t} else {\n\t\t\t// Set to empty allocated value\n\t\t\tval.Set(valMap)\n\t\t}\n\n\t\treturn nil\n\t}\n\n\tfor _, k := range dataVal.MapKeys() {\n\t\tfieldName := name + \"[\" + k.String() + \"]\"\n\n\t\t// First decode the key into the proper type\n\t\tcurrentKey := reflect.Indirect(reflect.New(valKeyType))\n\t\tif err := d.decode(fieldName, k.Interface(), currentKey); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t\tcontinue\n\t\t}\n\n\t\t// Next decode the data into the proper type\n\t\tv := dataVal.MapIndex(k).Interface()\n\t\tcurrentVal := reflect.Indirect(reflect.New(valElemType))\n\t\tif err := d.decode(fieldName, v, currentVal); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t\tcontinue\n\t\t}\n\n\t\tvalMap.SetMapIndex(currentKey, currentVal)\n\t}\n\n\t// Set the built up map to the value\n\tval.Set(valMap)\n\n\treturn errors.Join(errs...)\n}\n\nfunc (d *Decoder) decodeMapFromStruct(name string, dataVal reflect.Value, val reflect.Value, valMap reflect.Value) error {\n\ttyp := dataVal.Type()\n\tfor i := 0; i < typ.NumField(); i++ {\n\t\t// Get the StructField first since this is a cheap operation. If the\n\t\t// field is unexported, then ignore it.\n\t\tf := typ.Field(i)\n\t\tif f.PkgPath != \"\" {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Next get the actual value of this field and verify it is assignable\n\t\t// to the map value.\n\t\tv := dataVal.Field(i)\n\t\tif !v.Type().AssignableTo(valMap.Type().Elem()) {\n\t\t\treturn newDecodeError(\n\t\t\t\tname+\".\"+f.Name,\n\t\t\t\tfmt.Errorf(\"cannot assign type %q to map value field of type %q\", v.Type(), valMap.Type().Elem()),\n\t\t\t)\n\t\t}\n\n\t\ttagValue, _ := getTagValue(f, d.config.TagName)\n\t\tkeyName := d.config.MapFieldName(f.Name)\n\n\t\tif tagValue == \"\" && d.config.IgnoreUntaggedFields {\n\t\t\tcontinue\n\t\t}\n\n\t\t// If Squash is set in the config, we squash the field down.\n\t\tsquash := d.config.Squash && v.Kind() == reflect.Struct && f.Anonymous\n\n\t\t// If Deep is set in the config, set as default value.\n\t\tdeep := d.config.Deep\n\n\t\tv = dereferencePtrToStructIfNeeded(v, d.config.TagName)\n\n\t\t// Determine the name of the key in the map\n\t\tif index := strings.Index(tagValue, \",\"); index != -1 {\n\t\t\tif tagValue[:index] == \"-\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\t// If \"omitempty\" is specified in the tag, it ignores empty values.\n\t\t\tif strings.Contains(tagValue[index+1:], \"omitempty\") && isEmptyValue(v) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// If \"omitzero\" is specified in the tag, it ignores zero values.\n\t\t\tif strings.Contains(tagValue[index+1:], \"omitzero\") && v.IsZero() {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// If \"squash\" is specified in the tag, we squash the field down.\n\t\t\tsquash = squash || strings.Contains(tagValue[index+1:], d.config.SquashTagOption)\n\t\t\tif squash {\n\t\t\t\t// When squashing, the embedded type can be a pointer to a struct.\n\t\t\t\tif v.Kind() == reflect.Ptr && v.Elem().Kind() == reflect.Struct {\n\t\t\t\t\tv = v.Elem()\n\t\t\t\t}\n\n\t\t\t\t// The final type must be a struct\n\t\t\t\tif v.Kind() != reflect.Struct {\n\t\t\t\t\treturn newDecodeError(\n\t\t\t\t\t\tname+\".\"+f.Name,\n\t\t\t\t\t\tfmt.Errorf(\"cannot squash non-struct type %q\", v.Type()),\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif strings.Contains(tagValue[index+1:], \"remain\") {\n\t\t\t\t\tif v.Kind() != reflect.Map {\n\t\t\t\t\t\treturn newDecodeError(\n\t\t\t\t\t\t\tname+\".\"+f.Name,\n\t\t\t\t\t\t\tfmt.Errorf(\"error remain-tag field with invalid type: %q\", v.Type()),\n\t\t\t\t\t\t)\n\t\t\t\t\t}\n\n\t\t\t\t\tptr := v.MapRange()\n\t\t\t\t\tfor ptr.Next() {\n\t\t\t\t\t\tvalMap.SetMapIndex(ptr.Key(), ptr.Value())\n\t\t\t\t\t}\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdeep = deep || strings.Contains(tagValue[index+1:], \"deep\")\n\n\t\t\tif keyNameTagValue := tagValue[:index]; keyNameTagValue != \"\" {\n\t\t\t\tkeyName = keyNameTagValue\n\t\t\t}\n\t\t} else if len(tagValue) > 0 {\n\t\t\tif tagValue == \"-\" {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tkeyName = tagValue\n\t\t}\n\n\t\tswitch v.Kind() {\n\t\t// this is an embedded struct, so handle it differently\n\t\tcase reflect.Struct:\n\t\t\tx := reflect.New(v.Type())\n\t\t\tx.Elem().Set(v)\n\n\t\t\tvType := valMap.Type()\n\t\t\tvKeyType := vType.Key()\n\t\t\tvElemType := vType.Elem()\n\t\t\tmType := reflect.MapOf(vKeyType, vElemType)\n\t\t\tvMap := reflect.MakeMap(mType)\n\n\t\t\t// Creating a pointer to a map so that other methods can completely\n\t\t\t// overwrite the map if need be (looking at you decodeMapFromMap). The\n\t\t\t// indirection allows the underlying map to be settable (CanSet() == true)\n\t\t\t// where as reflect.MakeMap returns an unsettable map.\n\t\t\taddrVal := reflect.New(vMap.Type())\n\t\t\treflect.Indirect(addrVal).Set(vMap)\n\n\t\t\terr := d.decode(keyName, x.Interface(), reflect.Indirect(addrVal))\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// the underlying map may have been completely overwritten so pull\n\t\t\t// it indirectly out of the enclosing value.\n\t\t\tvMap = reflect.Indirect(addrVal)\n\n\t\t\tif squash {\n\t\t\t\tfor _, k := range vMap.MapKeys() {\n\t\t\t\t\tvalMap.SetMapIndex(k, vMap.MapIndex(k))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tvalMap.SetMapIndex(reflect.ValueOf(keyName), vMap)\n\t\t\t}\n\n\t\tcase reflect.Slice:\n\t\t\tif deep {\n\t\t\t\tvar childType reflect.Type\n\t\t\t\tswitch v.Type().Elem().Kind() {\n\t\t\t\tcase reflect.Struct:\n\t\t\t\t\tchildType = reflect.TypeOf(map[string]any{})\n\t\t\t\tdefault:\n\t\t\t\t\tchildType = v.Type().Elem()\n\t\t\t\t}\n\n\t\t\t\tsType := reflect.SliceOf(childType)\n\n\t\t\t\taddrVal := reflect.New(sType)\n\n\t\t\t\tvSlice := reflect.MakeSlice(sType, v.Len(), v.Cap())\n\n\t\t\t\tif v.Len() > 0 {\n\t\t\t\t\treflect.Indirect(addrVal).Set(vSlice)\n\n\t\t\t\t\terr := d.decode(keyName, v.Interface(), reflect.Indirect(addrVal))\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn err\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvSlice = reflect.Indirect(addrVal)\n\n\t\t\t\tvalMap.SetMapIndex(reflect.ValueOf(keyName), vSlice)\n\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// When deep mapping is not needed, fallthrough to normal copy\n\t\t\tfallthrough\n\n\t\tdefault:\n\t\t\tvalMap.SetMapIndex(reflect.ValueOf(keyName), v)\n\t\t}\n\t}\n\n\tif val.CanAddr() {\n\t\tval.Set(valMap)\n\t}\n\n\treturn nil\n}\n\nfunc (d *Decoder) decodePtr(name string, data any, val reflect.Value) (bool, error) {\n\t// If the input data is nil, then we want to just set the output\n\t// pointer to be nil as well.\n\tisNil := data == nil\n\tif !isNil {\n\t\tswitch v := reflect.Indirect(reflect.ValueOf(data)); v.Kind() {\n\t\tcase reflect.Chan,\n\t\t\treflect.Func,\n\t\t\treflect.Interface,\n\t\t\treflect.Map,\n\t\t\treflect.Ptr,\n\t\t\treflect.Slice:\n\t\t\tisNil = v.IsNil()\n\t\t}\n\t}\n\tif isNil {\n\t\tif !val.IsNil() && val.CanSet() {\n\t\t\tnilValue := reflect.New(val.Type()).Elem()\n\t\t\tval.Set(nilValue)\n\t\t}\n\n\t\treturn true, nil\n\t}\n\n\t// Create an element of the concrete (non pointer) type and decode\n\t// into that. Then set the value of the pointer to this type.\n\tvalType := val.Type()\n\tvalElemType := valType.Elem()\n\tif val.CanSet() {\n\t\trealVal := val\n\t\tif realVal.IsNil() || d.config.ZeroFields {\n\t\t\trealVal = reflect.New(valElemType)\n\t\t}\n\n\t\tif err := d.decode(name, data, reflect.Indirect(realVal)); err != nil {\n\t\t\treturn false, err\n\t\t}\n\n\t\tval.Set(realVal)\n\t} else {\n\t\tif err := d.decode(name, data, reflect.Indirect(val)); err != nil {\n\t\t\treturn false, err\n\t\t}\n\t}\n\treturn false, nil\n}\n\nfunc (d *Decoder) decodeFunc(name string, data any, val reflect.Value) error {\n\t// Create an element of the concrete (non pointer) type and decode\n\t// into that. Then set the value of the pointer to this type.\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tif val.Type() != dataVal.Type() {\n\t\treturn newDecodeError(name, &UnconvertibleTypeError{\n\t\t\tExpected: val,\n\t\t\tValue:    data,\n\t\t})\n\t}\n\tval.Set(dataVal)\n\treturn nil\n}\n\nfunc (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataValKind := dataVal.Kind()\n\tvalType := val.Type()\n\tvalElemType := valType.Elem()\n\tsliceType := reflect.SliceOf(valElemType)\n\n\t// If we have a non array/slice type then we first attempt to convert.\n\tif dataValKind != reflect.Array && dataValKind != reflect.Slice {\n\t\tif d.config.WeaklyTypedInput {\n\t\t\tswitch {\n\t\t\t// Slice and array we use the normal logic\n\t\t\tcase dataValKind == reflect.Slice, dataValKind == reflect.Array:\n\t\t\t\tbreak\n\n\t\t\t// Empty maps turn into empty slices\n\t\t\tcase dataValKind == reflect.Map:\n\t\t\t\tif dataVal.Len() == 0 {\n\t\t\t\t\tval.Set(reflect.MakeSlice(sliceType, 0, 0))\n\t\t\t\t\treturn nil\n\t\t\t\t}\n\t\t\t\t// Create slice of maps of other sizes\n\t\t\t\treturn d.decodeSlice(name, []any{data}, val)\n\n\t\t\tcase dataValKind == reflect.String && valElemType.Kind() == reflect.Uint8:\n\t\t\t\treturn d.decodeSlice(name, []byte(dataVal.String()), val)\n\n\t\t\t// All other types we try to convert to the slice type\n\t\t\t// and \"lift\" it into it. i.e. a string becomes a string slice.\n\t\t\tdefault:\n\t\t\t\t// Just re-try this function with data as a slice.\n\t\t\t\treturn d.decodeSlice(name, []any{data}, val)\n\t\t\t}\n\t\t}\n\n\t\treturn newDecodeError(name,\n\t\t\tfmt.Errorf(\"source data must be an array or slice, got %s\", dataValKind))\n\t}\n\n\t// If the input value is nil, then don't allocate since empty != nil\n\tif dataValKind != reflect.Array && dataVal.IsNil() {\n\t\treturn nil\n\t}\n\n\tvalSlice := val\n\tif valSlice.IsNil() || d.config.ZeroFields {\n\t\t// Make a new slice to hold our result, same size as the original data.\n\t\tvalSlice = reflect.MakeSlice(sliceType, dataVal.Len(), dataVal.Len())\n\t} else if valSlice.Len() > dataVal.Len() {\n\t\tvalSlice = valSlice.Slice(0, dataVal.Len())\n\t}\n\n\t// Accumulate any errors\n\tvar errs []error\n\n\tfor i := 0; i < dataVal.Len(); i++ {\n\t\tcurrentData := dataVal.Index(i).Interface()\n\t\tfor valSlice.Len() <= i {\n\t\t\tvalSlice = reflect.Append(valSlice, reflect.Zero(valElemType))\n\t\t}\n\t\tcurrentField := valSlice.Index(i)\n\n\t\tfieldName := name + \"[\" + strconv.Itoa(i) + \"]\"\n\t\tif err := d.decode(fieldName, currentData, currentField); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\n\t// Finally, set the value to the slice we built up\n\tval.Set(valSlice)\n\n\treturn errors.Join(errs...)\n}\n\nfunc (d *Decoder) decodeArray(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\tdataValKind := dataVal.Kind()\n\tvalType := val.Type()\n\tvalElemType := valType.Elem()\n\tarrayType := reflect.ArrayOf(valType.Len(), valElemType)\n\n\tvalArray := val\n\n\tif isComparable(valArray) && valArray.Interface() == reflect.Zero(valArray.Type()).Interface() || d.config.ZeroFields {\n\t\t// Check input type\n\t\tif dataValKind != reflect.Array && dataValKind != reflect.Slice {\n\t\t\tif d.config.WeaklyTypedInput {\n\t\t\t\tswitch {\n\t\t\t\t// Empty maps turn into empty arrays\n\t\t\t\tcase dataValKind == reflect.Map:\n\t\t\t\t\tif dataVal.Len() == 0 {\n\t\t\t\t\t\tval.Set(reflect.Zero(arrayType))\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t// All other types we try to convert to the array type\n\t\t\t\t// and \"lift\" it into it. i.e. a string becomes a string array.\n\t\t\t\tdefault:\n\t\t\t\t\t// Just re-try this function with data as a slice.\n\t\t\t\t\treturn d.decodeArray(name, []any{data}, val)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn newDecodeError(name,\n\t\t\t\tfmt.Errorf(\"source data must be an array or slice, got %s\", dataValKind))\n\n\t\t}\n\t\tif dataVal.Len() > arrayType.Len() {\n\t\t\treturn newDecodeError(name,\n\t\t\t\tfmt.Errorf(\"expected source data to have length less or equal to %d, got %d\", arrayType.Len(), dataVal.Len()))\n\t\t}\n\n\t\t// Make a new array to hold our result, same size as the original data.\n\t\tvalArray = reflect.New(arrayType).Elem()\n\t}\n\n\t// Accumulate any errors\n\tvar errs []error\n\n\tfor i := 0; i < dataVal.Len(); i++ {\n\t\tcurrentData := dataVal.Index(i).Interface()\n\t\tcurrentField := valArray.Index(i)\n\n\t\tfieldName := name + \"[\" + strconv.Itoa(i) + \"]\"\n\t\tif err := d.decode(fieldName, currentData, currentField); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\n\t// Finally, set the value to the array we built up\n\tval.Set(valArray)\n\n\treturn errors.Join(errs...)\n}\n\nfunc (d *Decoder) decodeStruct(name string, data any, val reflect.Value) error {\n\tdataVal := reflect.Indirect(reflect.ValueOf(data))\n\n\t// If the type of the value to write to and the data match directly,\n\t// then we just set it directly instead of recursing into the structure.\n\tif dataVal.Type() == val.Type() {\n\t\tval.Set(dataVal)\n\t\treturn nil\n\t}\n\n\tdataValKind := dataVal.Kind()\n\tswitch dataValKind {\n\tcase reflect.Map:\n\t\treturn d.decodeStructFromMap(name, dataVal, val)\n\n\tcase reflect.Struct:\n\t\t// Not the most efficient way to do this but we can optimize later if\n\t\t// we want to. To convert from struct to struct we go to map first\n\t\t// as an intermediary.\n\n\t\t// Make a new map to hold our result\n\t\tmapType := reflect.TypeOf((map[string]any)(nil))\n\t\tmval := reflect.MakeMap(mapType)\n\n\t\t// Creating a pointer to a map so that other methods can completely\n\t\t// overwrite the map if need be (looking at you decodeMapFromMap). The\n\t\t// indirection allows the underlying map to be settable (CanSet() == true)\n\t\t// where as reflect.MakeMap returns an unsettable map.\n\t\taddrVal := reflect.New(mval.Type())\n\n\t\treflect.Indirect(addrVal).Set(mval)\n\t\tif err := d.decodeMapFromStruct(name, dataVal, reflect.Indirect(addrVal), mval); err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tresult := d.decodeStructFromMap(name, reflect.Indirect(addrVal), val)\n\t\treturn result\n\n\tdefault:\n\t\treturn newDecodeError(name,\n\t\t\tfmt.Errorf(\"expected a map or struct, got %q\", dataValKind))\n\t}\n}\n\nfunc (d *Decoder) decodeStructFromMap(name string, dataVal, val reflect.Value) error {\n\tdataValType := dataVal.Type()\n\tif kind := dataValType.Key().Kind(); kind != reflect.String && kind != reflect.Interface {\n\t\treturn newDecodeError(name,\n\t\t\tfmt.Errorf(\"needs a map with string keys, has %q keys\", kind))\n\t}\n\n\tdataValKeys := make(map[reflect.Value]struct{})\n\tdataValKeysUnused := make(map[any]struct{})\n\tfor _, dataValKey := range dataVal.MapKeys() {\n\t\tdataValKeys[dataValKey] = struct{}{}\n\t\tdataValKeysUnused[dataValKey.Interface()] = struct{}{}\n\t}\n\n\ttargetValKeysUnused := make(map[any]struct{})\n\n\tvar errs []error\n\n\t// This slice will keep track of all the structs we'll be decoding.\n\t// There can be more than one struct if there are embedded structs\n\t// that are squashed.\n\tstructs := make([]reflect.Value, 1, 5)\n\tstructs[0] = val\n\n\t// Compile the list of all the fields that we're going to be decoding\n\t// from all the structs.\n\ttype field struct {\n\t\tfield reflect.StructField\n\t\tval   reflect.Value\n\t}\n\n\t// remainField is set to a valid field set with the \"remain\" tag if\n\t// we are keeping track of remaining values.\n\tvar remainField *field\n\n\tfields := []field{}\n\tfor len(structs) > 0 {\n\t\tstructVal := structs[0]\n\t\tstructs = structs[1:]\n\n\t\tstructType := structVal.Type()\n\n\t\tfor i := 0; i < structType.NumField(); i++ {\n\t\t\tfieldType := structType.Field(i)\n\t\t\tfieldVal := structVal.Field(i)\n\t\t\tif fieldVal.Kind() == reflect.Ptr && fieldVal.Elem().Kind() == reflect.Struct {\n\t\t\t\t// Handle embedded struct pointers as embedded structs.\n\t\t\t\tfieldVal = fieldVal.Elem()\n\t\t\t}\n\n\t\t\t// If \"squash\" is specified in the tag, we squash the field down.\n\t\t\tsquash := d.config.Squash && fieldVal.Kind() == reflect.Struct && fieldType.Anonymous\n\t\t\tremain := false\n\n\t\t\t// We always parse the tags cause we're looking for other tags too\n\t\t\ttagParts := getTagParts(fieldType, d.config.TagName)\n\t\t\tif len(tagParts) == 0 {\n\t\t\t\ttagParts = []string{\"\"}\n\t\t\t}\n\t\t\tfor _, tag := range tagParts[1:] {\n\t\t\t\tif tag == d.config.SquashTagOption {\n\t\t\t\t\tsquash = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\tif tag == \"remain\" {\n\t\t\t\t\tremain = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif squash {\n\t\t\t\tswitch fieldVal.Kind() {\n\t\t\t\tcase reflect.Struct:\n\t\t\t\t\tstructs = append(structs, fieldVal)\n\t\t\t\tcase reflect.Interface:\n\t\t\t\t\tif !fieldVal.IsNil() {\n\t\t\t\t\t\tstructs = append(structs, fieldVal.Elem().Elem())\n\t\t\t\t\t}\n\t\t\t\tcase reflect.Ptr:\n\t\t\t\t\tif fieldVal.Type().Elem().Kind() == reflect.Struct {\n\t\t\t\t\t\tif fieldVal.IsNil() {\n\t\t\t\t\t\t\tfieldVal.Set(reflect.New(fieldVal.Type().Elem()))\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstructs = append(structs, fieldVal.Elem())\n\t\t\t\t\t} else {\n\t\t\t\t\t\terrs = append(errs, newDecodeError(\n\t\t\t\t\t\t\tname+\".\"+fieldType.Name,\n\t\t\t\t\t\t\tfmt.Errorf(\"unsupported type for squashed pointer: %s\", fieldVal.Type().Elem().Kind()),\n\t\t\t\t\t\t))\n\t\t\t\t\t}\n\t\t\t\tdefault:\n\t\t\t\t\terrs = append(errs, newDecodeError(\n\t\t\t\t\t\tname+\".\"+fieldType.Name,\n\t\t\t\t\t\tfmt.Errorf(\"unsupported type for squash: %s\", fieldVal.Kind()),\n\t\t\t\t\t))\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Build our field\n\t\t\tif remain {\n\t\t\t\tremainField = &field{fieldType, fieldVal}\n\t\t\t} else {\n\t\t\t\t// Normal struct field, store it away\n\t\t\t\tfields = append(fields, field{fieldType, fieldVal})\n\t\t\t}\n\t\t}\n\t}\n\n\t// for fieldType, field := range fields {\n\tfor _, f := range fields {\n\t\tfield, fieldValue := f.field, f.val\n\t\tfieldName := field.Name\n\n\t\ttagValue, _ := getTagValue(field, d.config.TagName)\n\t\tif tagValue == \"\" && d.config.IgnoreUntaggedFields {\n\t\t\tcontinue\n\t\t}\n\t\ttagValue = strings.SplitN(tagValue, \",\", 2)[0]\n\t\tif tagValue != \"\" {\n\t\t\tfieldName = tagValue\n\t\t} else {\n\t\t\tfieldName = d.config.MapFieldName(fieldName)\n\t\t}\n\n\t\trawMapKey := reflect.ValueOf(fieldName)\n\t\trawMapVal := dataVal.MapIndex(rawMapKey)\n\t\tif !rawMapVal.IsValid() {\n\t\t\t// Do a slower search by iterating over each key and\n\t\t\t// doing case-insensitive search.\n\t\t\tfor dataValKey := range dataValKeys {\n\t\t\t\tmK, ok := dataValKey.Interface().(string)\n\t\t\t\tif !ok {\n\t\t\t\t\t// Not a string key\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif d.config.MatchName(mK, fieldName) {\n\t\t\t\t\trawMapKey = dataValKey\n\t\t\t\t\trawMapVal = dataVal.MapIndex(dataValKey)\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif !rawMapVal.IsValid() {\n\t\t\t\t// There was no matching key in the map for the value in\n\t\t\t\t// the struct. Remember it for potential errors and metadata.\n\t\t\t\tif !(d.config.AllowUnsetPointer && fieldValue.Kind() == reflect.Ptr) {\n\t\t\t\t\ttargetValKeysUnused[fieldName] = struct{}{}\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t}\n\n\t\tif !fieldValue.IsValid() {\n\t\t\t// This should never happen\n\t\t\tpanic(\"field is not valid\")\n\t\t}\n\n\t\t// If we can't set the field, then it is unexported or something,\n\t\t// and we just continue onwards.\n\t\tif !fieldValue.CanSet() {\n\t\t\tcontinue\n\t\t}\n\n\t\t// Delete the key we're using from the unused map so we stop tracking\n\t\tdelete(dataValKeysUnused, rawMapKey.Interface())\n\n\t\t// If the name is empty string, then we're at the root, and we\n\t\t// don't dot-join the fields.\n\t\tif name != \"\" {\n\t\t\tfieldName = name + \".\" + fieldName\n\t\t}\n\n\t\tif err := d.decode(fieldName, rawMapVal.Interface(), fieldValue); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\t}\n\n\t// If we have a \"remain\"-tagged field and we have unused keys then\n\t// we put the unused keys directly into the remain field.\n\tif remainField != nil && len(dataValKeysUnused) > 0 {\n\t\t// Build a map of only the unused values\n\t\tremain := map[any]any{}\n\t\tfor key := range dataValKeysUnused {\n\t\t\tremain[key] = dataVal.MapIndex(reflect.ValueOf(key)).Interface()\n\t\t}\n\n\t\t// Decode it as-if we were just decoding this map onto our map.\n\t\tif err := d.decodeMap(name, remain, remainField.val); err != nil {\n\t\t\terrs = append(errs, err)\n\t\t}\n\n\t\t// Set the map to nil so we have none so that the next check will\n\t\t// not error (ErrorUnused)\n\t\tdataValKeysUnused = nil\n\t}\n\n\tif d.config.ErrorUnused && len(dataValKeysUnused) > 0 {\n\t\tkeys := make([]string, 0, len(dataValKeysUnused))\n\t\tfor rawKey := range dataValKeysUnused {\n\t\t\tkeys = append(keys, rawKey.(string))\n\t\t}\n\t\tsort.Strings(keys)\n\n\t\t// Improve error message when name is empty by showing the target struct type\n\t\t// in the case where it is empty for embedded structs.\n\t\terrorName := name\n\t\tif errorName == \"\" {\n\t\t\terrorName = val.Type().String()\n\t\t}\n\t\terrs = append(errs, newDecodeError(\n\t\t\terrorName,\n\t\t\tfmt.Errorf(\"has invalid keys: %s\", strings.Join(keys, \", \")),\n\t\t))\n\t}\n\n\tif d.config.ErrorUnset && len(targetValKeysUnused) > 0 {\n\t\tkeys := make([]string, 0, len(targetValKeysUnused))\n\t\tfor rawKey := range targetValKeysUnused {\n\t\t\tkeys = append(keys, rawKey.(string))\n\t\t}\n\t\tsort.Strings(keys)\n\n\t\terrs = append(errs, newDecodeError(\n\t\t\tname,\n\t\t\tfmt.Errorf(\"has unset fields: %s\", strings.Join(keys, \", \")),\n\t\t))\n\t}\n\n\tif err := errors.Join(errs...); err != nil {\n\t\treturn err\n\t}\n\n\t// Add the unused keys to the list of unused keys if we're tracking metadata\n\tif d.config.Metadata != nil {\n\t\tfor rawKey := range dataValKeysUnused {\n\t\t\tkey := rawKey.(string)\n\t\t\tif name != \"\" {\n\t\t\t\tkey = name + \".\" + key\n\t\t\t}\n\n\t\t\td.config.Metadata.Unused = append(d.config.Metadata.Unused, key)\n\t\t}\n\t\tfor rawKey := range targetValKeysUnused {\n\t\t\tkey := rawKey.(string)\n\t\t\tif name != \"\" {\n\t\t\t\tkey = name + \".\" + key\n\t\t\t}\n\n\t\t\td.config.Metadata.Unset = append(d.config.Metadata.Unset, key)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc isEmptyValue(v reflect.Value) bool {\n\tswitch getKind(v) {\n\tcase reflect.Array, reflect.Map, reflect.Slice, reflect.String:\n\t\treturn v.Len() == 0\n\tcase reflect.Bool:\n\t\treturn !v.Bool()\n\tcase reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:\n\t\treturn v.Int() == 0\n\tcase reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:\n\t\treturn v.Uint() == 0\n\tcase reflect.Float32, reflect.Float64:\n\t\treturn v.Float() == 0\n\tcase reflect.Interface, reflect.Ptr:\n\t\treturn v.IsNil()\n\t}\n\treturn false\n}\n\nfunc getKind(val reflect.Value) reflect.Kind {\n\tkind := val.Kind()\n\n\tswitch {\n\tcase kind >= reflect.Int && kind <= reflect.Int64:\n\t\treturn reflect.Int\n\tcase kind >= reflect.Uint && kind <= reflect.Uint64:\n\t\treturn reflect.Uint\n\tcase kind >= reflect.Float32 && kind <= reflect.Float64:\n\t\treturn reflect.Float32\n\tcase kind >= reflect.Complex64 && kind <= reflect.Complex128:\n\t\treturn reflect.Complex64\n\tdefault:\n\t\treturn kind\n\t}\n}\n\nfunc isStructTypeConvertibleToMap(typ reflect.Type, checkMapstructureTags bool, tagName string) bool {\n\tfor i := 0; i < typ.NumField(); i++ {\n\t\tf := typ.Field(i)\n\t\tif f.PkgPath == \"\" && !checkMapstructureTags { // check for unexported fields\n\t\t\treturn true\n\t\t}\n\t\tif checkMapstructureTags && hasAnyTag(f, tagName) { // check for mapstructure tags inside\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nfunc dereferencePtrToStructIfNeeded(v reflect.Value, tagName string) reflect.Value {\n\tif v.Kind() != reflect.Ptr {\n\t\treturn v\n\t}\n\n\tswitch v.Elem().Kind() {\n\tcase reflect.Slice:\n\t\treturn v.Elem()\n\n\tcase reflect.Struct:\n\t\tderef := v.Elem()\n\t\tderefT := deref.Type()\n\t\tif isStructTypeConvertibleToMap(derefT, true, tagName) {\n\t\t\treturn deref\n\t\t}\n\t\treturn v\n\n\tdefault:\n\t\treturn v\n\t}\n}\n\nfunc hasAnyTag(field reflect.StructField, tagName string) bool {\n\t_, ok := getTagValue(field, tagName)\n\treturn ok\n}\n\nfunc getTagParts(field reflect.StructField, tagName string) []string {\n\ttagValue, ok := getTagValue(field, tagName)\n\tif !ok {\n\t\treturn nil\n\t}\n\treturn strings.Split(tagValue, \",\")\n}\n\nfunc getTagValue(field reflect.StructField, tagName string) (string, bool) {\n\tfor _, name := range splitTagNames(tagName) {\n\t\tif tag := field.Tag.Get(name); tag != \"\" {\n\t\t\treturn tag, true\n\t\t}\n\t}\n\treturn \"\", false\n}\n\nfunc splitTagNames(tagName string) []string {\n\tif tagName == \"\" {\n\t\treturn []string{\"mapstructure\"}\n\t}\n\tparts := strings.Split(tagName, \",\")\n\tresult := make([]string, 0, len(parts))\n\n\tfor _, name := range parts {\n\t\tname = strings.TrimSpace(name)\n\t\tif name != \"\" {\n\t\t\tresult = append(result, name)\n\t\t}\n\t}\n\n\treturn result\n}\n\n// unmarshalerType is cached for performance\nvar unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()\n\n// getUnmarshaler checks if the value implements Unmarshaler and returns\n// the Unmarshaler and a boolean indicating if it was found. It handles both\n// pointer and value receivers.\nfunc getUnmarshaler(val reflect.Value) (Unmarshaler, bool) {\n\t// Skip invalid or nil values\n\tif !val.IsValid() {\n\t\treturn nil, false\n\t}\n\n\tswitch val.Kind() {\n\tcase reflect.Pointer, reflect.Interface:\n\t\tif val.IsNil() {\n\t\t\treturn nil, false\n\t\t}\n\t}\n\n\t// Check pointer receiver first (most common case)\n\tif val.CanAddr() {\n\t\tptrVal := val.Addr()\n\t\t// Quick check: if no methods, can't implement any interface\n\t\tif ptrVal.Type().NumMethod() > 0 && ptrVal.Type().Implements(unmarshalerType) {\n\t\t\treturn ptrVal.Interface().(Unmarshaler), true\n\t\t}\n\t}\n\n\t// Check value receiver\n\t// Quick check: if no methods, can't implement any interface\n\tif val.Type().NumMethod() > 0 && val.CanInterface() && val.Type().Implements(unmarshalerType) {\n\t\treturn val.Interface().(Unmarshaler), true\n\t}\n\n\treturn nil, false\n}\n"
  },
  {
    "path": "mapstructure_benchmark_test.go",
    "content": "package mapstructure\n\nimport (\n\t\"encoding/json\"\n\t\"testing\"\n)\n\ntype Person struct {\n\tName   string\n\tAge    int\n\tEmails []string\n\tExtra  map[string]string\n}\n\nfunc Benchmark_Decode(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"name\":   \"Mitchell\",\n\t\t\"age\":    91,\n\t\t\"emails\": []string{\"one\", \"two\", \"three\"},\n\t\t\"extra\": map[string]string{\n\t\t\t\"twitter\": \"mitchellh\",\n\t\t},\n\t}\n\n\tvar result Person\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &result)\n\t}\n}\n\n// decodeViaJSON takes the map data and passes it through encoding/json to convert it into the\n// given Go native structure pointed to by v. v must be a pointer to a struct.\nfunc decodeViaJSON(data any, v any) error {\n\t// Perform the task by simply marshalling the input into JSON,\n\t// then unmarshalling it into target native Go struct.\n\tb, err := json.Marshal(data)\n\tif err != nil {\n\t\treturn err\n\t}\n\treturn json.Unmarshal(b, v)\n}\n\nfunc Benchmark_DecodeViaJSON(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"name\":   \"Mitchell\",\n\t\t\"age\":    91,\n\t\t\"emails\": []string{\"one\", \"two\", \"three\"},\n\t\t\"extra\": map[string]string{\n\t\t\t\"twitter\": \"mitchellh\",\n\t\t},\n\t}\n\n\tvar result Person\n\tfor i := 0; i < b.N; i++ {\n\t\tdecodeViaJSON(input, &result)\n\t}\n}\n\nfunc Benchmark_JSONUnmarshal(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"name\":   \"Mitchell\",\n\t\t\"age\":    91,\n\t\t\"emails\": []string{\"one\", \"two\", \"three\"},\n\t\t\"extra\": map[string]string{\n\t\t\t\"twitter\": \"mitchellh\",\n\t\t},\n\t}\n\n\tinputB, err := json.Marshal(input)\n\tif err != nil {\n\t\tb.Fatal(\"Failed to marshal test input:\", err)\n\t}\n\n\tvar result Person\n\tfor i := 0; i < b.N; i++ {\n\t\tjson.Unmarshal(inputB, &result)\n\t}\n}\n\nfunc Benchmark_DecodeBasic(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"vstring\":     \"foo\",\n\t\t\"vint\":        42,\n\t\t\"Vuint\":       42,\n\t\t\"vbool\":       true,\n\t\t\"Vfloat\":      42.42,\n\t\t\"vsilent\":     true,\n\t\t\"vdata\":       42,\n\t\t\"vjsonInt\":    json.Number(\"1234\"),\n\t\t\"vjsonFloat\":  json.Number(\"1234.5\"),\n\t\t\"vjsonNumber\": json.Number(\"1234.5\"),\n\t}\n\n\tfor i := 0; i < b.N; i++ {\n\t\tvar result Basic\n\t\tDecode(input, &result)\n\t}\n}\n\nfunc Benchmark_DecodeEmbedded(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"Basic\": map[string]any{\n\t\t\t\"vstring\": \"innerfoo\",\n\t\t},\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tvar result Embedded\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &result)\n\t}\n}\n\nfunc Benchmark_DecodeTypeConversion(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"IntToFloat\":    42,\n\t\t\"IntToUint\":     42,\n\t\t\"IntToBool\":     1,\n\t\t\"IntToString\":   42,\n\t\t\"UintToInt\":     42,\n\t\t\"UintToFloat\":   42,\n\t\t\"UintToBool\":    42,\n\t\t\"UintToString\":  42,\n\t\t\"BoolToInt\":     true,\n\t\t\"BoolToUint\":    true,\n\t\t\"BoolToFloat\":   true,\n\t\t\"BoolToString\":  true,\n\t\t\"FloatToInt\":    42.42,\n\t\t\"FloatToUint\":   42.42,\n\t\t\"FloatToBool\":   42.42,\n\t\t\"FloatToString\": 42.42,\n\t\t\"StringToInt\":   \"42\",\n\t\t\"StringToUint\":  \"42\",\n\t\t\"StringToBool\":  \"1\",\n\t\t\"StringToFloat\": \"42.42\",\n\t\t\"SliceToMap\":    []any{},\n\t\t\"MapToSlice\":    map[string]any{},\n\t}\n\n\tvar resultStrict TypeConversionResult\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &resultStrict)\n\t}\n}\n\nfunc Benchmark_DecodeMap(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vother\": map[any]any{\n\t\t\t\"foo\": \"foo\",\n\t\t\t\"bar\": \"bar\",\n\t\t},\n\t}\n\n\tvar result Map\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &result)\n\t}\n}\n\nfunc Benchmark_DecodeMapOfStruct(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"value\": map[string]any{\n\t\t\t\"foo\": map[string]string{\"vstring\": \"one\"},\n\t\t\t\"bar\": map[string]string{\"vstring\": \"two\"},\n\t\t},\n\t}\n\n\tvar result MapOfStruct\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &result)\n\t}\n}\n\nfunc Benchmark_DecodeSlice(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": []string{\"foo\", \"bar\", \"baz\"},\n\t}\n\n\tvar result Slice\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &result)\n\t}\n}\n\nfunc Benchmark_DecodeSliceOfStruct(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"value\": []map[string]any{\n\t\t\t{\"vstring\": \"one\"},\n\t\t\t{\"vstring\": \"two\"},\n\t\t},\n\t}\n\n\tvar result SliceOfStruct\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &result)\n\t}\n}\n\nfunc Benchmark_DecodeWeaklyTypedInput(b *testing.B) {\n\t// This input can come from anywhere, but typically comes from\n\t// something like decoding JSON, generated by a weakly typed language\n\t// such as PHP.\n\tinput := map[string]any{\n\t\t\"name\":   123,              // number => string\n\t\t\"age\":    \"42\",             // string => number\n\t\t\"emails\": map[string]any{}, // empty map => empty array\n\t}\n\n\tvar result Person\n\tconfig := &DecoderConfig{\n\t\tWeaklyTypedInput: true,\n\t\tResult:           &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfor i := 0; i < b.N; i++ {\n\t\tdecoder.Decode(input)\n\t}\n}\n\nfunc Benchmark_DecodeMetadata(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"name\":  \"Mitchell\",\n\t\t\"age\":   91,\n\t\t\"email\": \"foo@bar.com\",\n\t}\n\n\tvar md Metadata\n\tvar result Person\n\tconfig := &DecoderConfig{\n\t\tMetadata: &md,\n\t\tResult:   &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfor i := 0; i < b.N; i++ {\n\t\tdecoder.Decode(input)\n\t}\n}\n\nfunc Benchmark_DecodeMetadataEmbedded(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tvar md Metadata\n\tvar result EmbeddedSquash\n\tconfig := &DecoderConfig{\n\t\tMetadata: &md,\n\t\tResult:   &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tb.Fatalf(\"err: %s\", err)\n\t}\n\n\tfor i := 0; i < b.N; i++ {\n\t\tdecoder.Decode(input)\n\t}\n}\n\nfunc Benchmark_DecodeTagged(b *testing.B) {\n\tinput := map[string]any{\n\t\t\"foo\": \"bar\",\n\t\t\"bar\": \"value\",\n\t}\n\n\tvar result Tagged\n\tfor i := 0; i < b.N; i++ {\n\t\tDecode(input, &result)\n\t}\n}\n\nfunc Benchmark_DecodeWithRemainingFields(b *testing.B) {\n\ttype Person struct {\n\t\tName  string\n\t\tOther map[string]any `mapstructure:\",remain\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"name\": \"Luffy\",\n\t\t\"age\":  19,\n\t\t\"powers\": []string{\n\t\t\t\"Rubber Man\",\n\t\t\t\"Conqueror Haki\",\n\t\t},\n\t}\n\n\tfor i := 0; i < b.N; i++ {\n\t\t// Decoding Map -> Struct\n\t\tvar person Person\n\t\t_ = Decode(input, &person)\n\n\t\t// Decoding Struct -> Map\n\t\tresult := make(map[string]any)\n\t\t_ = Decode(&person, &result)\n\t}\n}\n"
  },
  {
    "path": "mapstructure_bugs_test.go",
    "content": "package mapstructure\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n)\n\n// GH-1, GH-10, GH-96\nfunc TestDecode_NilValue(t *testing.T) {\n\tt.Parallel()\n\n\ttests := []struct {\n\t\tname       string\n\t\tin         any\n\t\ttarget     any\n\t\tout        any\n\t\tmetaKeys   []string\n\t\tmetaUnused []string\n\t}{\n\t\t{\n\t\t\t\"all nil\",\n\t\t\t&map[string]any{\n\t\t\t\t\"vfoo\":   nil,\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"\", Vother: nil},\n\t\t\t[]string{\"Vfoo\", \"Vother\"},\n\t\t\t[]string{},\n\t\t},\n\t\t{\n\t\t\t\"partial nil\",\n\t\t\t&map[string]any{\n\t\t\t\t\"vfoo\":   \"baz\",\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"baz\", Vother: nil},\n\t\t\t[]string{\"Vfoo\", \"Vother\"},\n\t\t\t[]string{},\n\t\t},\n\t\t{\n\t\t\t\"partial decode\",\n\t\t\t&map[string]any{\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"foo\", Vother: nil},\n\t\t\t[]string{\"Vother\"},\n\t\t\t[]string{},\n\t\t},\n\t\t{\n\t\t\t\"unused values\",\n\t\t\t&map[string]any{\n\t\t\t\t\"vbar\":   \"bar\",\n\t\t\t\t\"vfoo\":   nil,\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"\", Vother: nil},\n\t\t\t[]string{\"Vfoo\", \"Vother\"},\n\t\t\t[]string{\"vbar\"},\n\t\t},\n\t\t{\n\t\t\t\"map interface all nil\",\n\t\t\t&map[any]any{\n\t\t\t\t\"vfoo\":   nil,\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"\", Vother: nil},\n\t\t\t[]string{\"Vfoo\", \"Vother\"},\n\t\t\t[]string{},\n\t\t},\n\t\t{\n\t\t\t\"map interface partial nil\",\n\t\t\t&map[any]any{\n\t\t\t\t\"vfoo\":   \"baz\",\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"baz\", Vother: nil},\n\t\t\t[]string{\"Vfoo\", \"Vother\"},\n\t\t\t[]string{},\n\t\t},\n\t\t{\n\t\t\t\"map interface partial decode\",\n\t\t\t&map[any]any{\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"foo\", Vother: nil},\n\t\t\t[]string{\"Vother\"},\n\t\t\t[]string{},\n\t\t},\n\t\t{\n\t\t\t\"map interface unused values\",\n\t\t\t&map[any]any{\n\t\t\t\t\"vbar\":   \"bar\",\n\t\t\t\t\"vfoo\":   nil,\n\t\t\t\t\"vother\": nil,\n\t\t\t},\n\t\t\t&Map{Vfoo: \"foo\", Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&Map{Vfoo: \"\", Vother: nil},\n\t\t\t[]string{\"Vfoo\", \"Vother\"},\n\t\t\t[]string{\"vbar\"},\n\t\t},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tconfig := &DecoderConfig{\n\t\t\t\tMetadata:   new(Metadata),\n\t\t\t\tResult:     tc.target,\n\t\t\t\tZeroFields: true,\n\t\t\t}\n\n\t\t\tdecoder, err := NewDecoder(config)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"should not error: %s\", err)\n\t\t\t}\n\n\t\t\terr = decoder.Decode(tc.in)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"should not error: %s\", err)\n\t\t\t}\n\n\t\t\tif !reflect.DeepEqual(tc.out, tc.target) {\n\t\t\t\tt.Fatalf(\"%q: TestDecode_NilValue() expected: %#v, got: %#v\", tc.name, tc.out, tc.target)\n\t\t\t}\n\n\t\t\tif !reflect.DeepEqual(tc.metaKeys, config.Metadata.Keys) {\n\t\t\t\tt.Fatalf(\"%q: Metadata.Keys mismatch expected: %#v, got: %#v\", tc.name, tc.metaKeys, config.Metadata.Keys)\n\t\t\t}\n\n\t\t\tif !reflect.DeepEqual(tc.metaUnused, config.Metadata.Unused) {\n\t\t\t\tt.Fatalf(\"%q: Metadata.Unused mismatch expected: %#v, got: %#v\", tc.name, tc.metaUnused, config.Metadata.Unused)\n\t\t\t}\n\t\t})\n\t}\n}\n\n// #48\nfunc TestNestedTypePointerWithDefaults(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t\t\"vint\":    42,\n\t\t\t\"vbool\":   true,\n\t\t},\n\t}\n\n\tresult := NestedPointer{\n\t\tVbar: &Basic{\n\t\t\tVuint: 42,\n\t\t},\n\t}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\tif result.Vbar.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vbar.Vstring)\n\t}\n\n\tif result.Vbar.Vint != 42 {\n\t\tt.Errorf(\"vint value should be 42: %#v\", result.Vbar.Vint)\n\t}\n\n\tif result.Vbar.Vbool != true {\n\t\tt.Errorf(\"vbool value should be true: %#v\", result.Vbar.Vbool)\n\t}\n\n\tif result.Vbar.Vextra != \"\" {\n\t\tt.Errorf(\"vextra value should be empty: %#v\", result.Vbar.Vextra)\n\t}\n\n\t// this is the error\n\tif result.Vbar.Vuint != 42 {\n\t\tt.Errorf(\"vuint value should be 42: %#v\", result.Vbar.Vuint)\n\t}\n}\n\ntype NestedSlice struct {\n\tVfoo   string\n\tVbars  []Basic\n\tVempty []Basic\n}\n\n// #48\nfunc TestNestedTypeSliceWithDefaults(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbars\": []map[string]any{\n\t\t\t{\"vstring\": \"foo\", \"vint\": 42, \"vbool\": true},\n\t\t\t{\"vint\": 42, \"vbool\": true},\n\t\t},\n\t\t\"vempty\": []map[string]any{\n\t\t\t{\"vstring\": \"foo\", \"vint\": 42, \"vbool\": true},\n\t\t\t{\"vint\": 42, \"vbool\": true},\n\t\t},\n\t}\n\n\tresult := NestedSlice{\n\t\tVbars: []Basic{\n\t\t\t{Vuint: 42},\n\t\t\t{Vstring: \"foo\"},\n\t\t},\n\t}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\tif result.Vbars[0].Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vbars[0].Vstring)\n\t}\n\t// this is the error\n\tif result.Vbars[0].Vuint != 42 {\n\t\tt.Errorf(\"vuint value should be 42: %#v\", result.Vbars[0].Vuint)\n\t}\n}\n\n// #48 workaround\nfunc TestNestedTypeWithDefaults(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t\t\"vint\":    42,\n\t\t\t\"vbool\":   true,\n\t\t},\n\t}\n\n\tresult := Nested{\n\t\tVbar: Basic{\n\t\t\tVuint: 42,\n\t\t},\n\t}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\tif result.Vbar.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vbar.Vstring)\n\t}\n\n\tif result.Vbar.Vint != 42 {\n\t\tt.Errorf(\"vint value should be 42: %#v\", result.Vbar.Vint)\n\t}\n\n\tif result.Vbar.Vbool != true {\n\t\tt.Errorf(\"vbool value should be true: %#v\", result.Vbar.Vbool)\n\t}\n\n\tif result.Vbar.Vextra != \"\" {\n\t\tt.Errorf(\"vextra value should be empty: %#v\", result.Vbar.Vextra)\n\t}\n\n\t// this is the error\n\tif result.Vbar.Vuint != 42 {\n\t\tt.Errorf(\"vuint value should be 42: %#v\", result.Vbar.Vuint)\n\t}\n}\n\n// #67 panic() on extending slices (decodeSlice with disabled ZeroValues)\nfunc TestDecodeSliceToEmptySliceWOZeroing(t *testing.T) {\n\tt.Parallel()\n\n\ttype TestStruct struct {\n\t\tVfoo []string\n\t}\n\n\tdecode := func(m any, rawVal any) error {\n\t\tconfig := &DecoderConfig{\n\t\t\tMetadata:   nil,\n\t\t\tResult:     rawVal,\n\t\t\tZeroFields: false,\n\t\t}\n\n\t\tdecoder, err := NewDecoder(config)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\treturn decoder.Decode(m)\n\t}\n\n\t{\n\t\tinput := map[string]any{\n\t\t\t\"vfoo\": []string{\"1\"},\n\t\t}\n\n\t\tresult := &TestStruct{}\n\n\t\terr := decode(input, &result)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t\t}\n\t}\n\n\t{\n\t\tinput := map[string]any{\n\t\t\t\"vfoo\": []string{\"1\"},\n\t\t}\n\n\t\tresult := &TestStruct{\n\t\t\tVfoo: []string{},\n\t\t}\n\n\t\terr := decode(input, &result)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t\t}\n\t}\n\n\t{\n\t\tinput := map[string]any{\n\t\t\t\"vfoo\": []string{\"2\", \"3\"},\n\t\t}\n\n\t\tresult := &TestStruct{\n\t\t\tVfoo: []string{\"1\"},\n\t\t}\n\n\t\terr := decode(input, &result)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t\t}\n\t}\n}\n\n// #70\nfunc TestNextSquashMapstructure(t *testing.T) {\n\tdata := &struct {\n\t\tLevel1 struct {\n\t\t\tLevel2 struct {\n\t\t\t\tFoo string\n\t\t\t} `mapstructure:\",squash\"`\n\t\t} `mapstructure:\",squash\"`\n\t}{}\n\terr := Decode(map[any]any{\"foo\": \"baz\"}, &data)\n\tif err != nil {\n\t\tt.Fatalf(\"should not error: %s\", err)\n\t}\n\tif data.Level1.Level2.Foo != \"baz\" {\n\t\tt.Fatal(\"value should be baz\")\n\t}\n}\n\ntype ImplementsInterfacePointerReceiver struct {\n\tName string\n}\n\nfunc (i *ImplementsInterfacePointerReceiver) DoStuff() {}\n\ntype ImplementsInterfaceValueReceiver string\n\nfunc (i ImplementsInterfaceValueReceiver) DoStuff() {}\n\n// GH-140 Type error when using DecodeHook to decode into interface\nfunc TestDecode_DecodeHookInterface(t *testing.T) {\n\tt.Parallel()\n\n\ttype Interface interface {\n\t\tDoStuff()\n\t}\n\ttype DecodeIntoInterface struct {\n\t\tTest Interface\n\t}\n\n\ttestData := map[string]string{\"test\": \"test\"}\n\n\tstringToPointerInterfaceDecodeHook := func(from, to reflect.Type, data any) (any, error) {\n\t\tif from.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\n\t\tif to != reflect.TypeOf((*Interface)(nil)).Elem() {\n\t\t\treturn data, nil\n\t\t}\n\t\t// Ensure interface is satisfied\n\t\tvar impl Interface = &ImplementsInterfacePointerReceiver{data.(string)}\n\t\treturn impl, nil\n\t}\n\n\tstringToValueInterfaceDecodeHook := func(from, to reflect.Type, data any) (any, error) {\n\t\tif from.Kind() != reflect.String {\n\t\t\treturn data, nil\n\t\t}\n\n\t\tif to != reflect.TypeOf((*Interface)(nil)).Elem() {\n\t\t\treturn data, nil\n\t\t}\n\t\t// Ensure interface is satisfied\n\t\tvar impl Interface = ImplementsInterfaceValueReceiver(data.(string))\n\t\treturn impl, nil\n\t}\n\n\t{\n\t\tdecodeInto := new(DecodeIntoInterface)\n\n\t\tdecoder, _ := NewDecoder(&DecoderConfig{\n\t\t\tDecodeHook: stringToPointerInterfaceDecodeHook,\n\t\t\tResult:     decodeInto,\n\t\t})\n\n\t\terr := decoder.Decode(testData)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Decode returned error: %s\", err)\n\t\t}\n\n\t\texpected := &ImplementsInterfacePointerReceiver{\"test\"}\n\t\tif !reflect.DeepEqual(decodeInto.Test, expected) {\n\t\t\tt.Fatalf(\"expected: %#v (%T), got: %#v (%T)\", decodeInto.Test, decodeInto.Test, expected, expected)\n\t\t}\n\t}\n\n\t{\n\t\tdecodeInto := new(DecodeIntoInterface)\n\n\t\tdecoder, _ := NewDecoder(&DecoderConfig{\n\t\t\tDecodeHook: stringToValueInterfaceDecodeHook,\n\t\t\tResult:     decodeInto,\n\t\t})\n\n\t\terr := decoder.Decode(testData)\n\t\tif err != nil {\n\t\t\tt.Fatalf(\"Decode returned error: %s\", err)\n\t\t}\n\n\t\texpected := ImplementsInterfaceValueReceiver(\"test\")\n\t\tif !reflect.DeepEqual(decodeInto.Test, expected) {\n\t\t\tt.Fatalf(\"expected: %#v (%T), got: %#v (%T)\", decodeInto.Test, decodeInto.Test, expected, expected)\n\t\t}\n\t}\n}\n\n// #103 Check for data type before trying to access its composants prevent a panic error\n// in decodeSlice\nfunc TestDecodeBadDataTypeInSlice(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"Toto\": \"titi\",\n\t}\n\tresult := []struct {\n\t\tToto string\n\t}{}\n\n\tif err := Decode(input, &result); err == nil {\n\t\tt.Error(\"An error was expected, got nil\")\n\t}\n}\n\n// #202 Ensure that intermediate maps in the struct -> struct decode process are settable\n// and not just the elements within them.\nfunc TestDecodeIntermediateMapsSettable(t *testing.T) {\n\ttype Timestamp struct {\n\t\tSeconds int64\n\t\tNanos   int32\n\t}\n\n\ttype TsWrapper struct {\n\t\tTimestamp *Timestamp\n\t}\n\n\ttype TimeWrapper struct {\n\t\tTimestamp time.Time\n\t}\n\n\tinput := TimeWrapper{\n\t\tTimestamp: time.Unix(123456789, 987654),\n\t}\n\n\texpected := TsWrapper{\n\t\tTimestamp: &Timestamp{\n\t\t\tSeconds: 123456789,\n\t\t\tNanos:   987654,\n\t\t},\n\t}\n\n\ttimePtrType := reflect.TypeOf((*time.Time)(nil))\n\tmapStrInfType := reflect.TypeOf((map[string]any)(nil))\n\n\tvar actual TsWrapper\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tResult: &actual,\n\t\tDecodeHook: func(from, to reflect.Type, data any) (any, error) {\n\t\t\tif from == timePtrType && to == mapStrInfType {\n\t\t\t\tts := data.(*time.Time)\n\t\t\t\tnanos := ts.UnixNano()\n\n\t\t\t\tseconds := nanos / 1000000000\n\t\t\t\tnanos = nanos % 1000000000\n\n\t\t\t\treturn &map[string]any{\n\t\t\t\t\t\"Seconds\": seconds,\n\t\t\t\t\t\"Nanos\":   int32(nanos),\n\t\t\t\t}, nil\n\t\t\t}\n\t\t\treturn data, nil\n\t\t},\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create decoder: %v\", err)\n\t}\n\n\tif err := decoder.Decode(&input); err != nil {\n\t\tt.Fatalf(\"failed to decode input: %v\", err)\n\t}\n\n\tif !reflect.DeepEqual(expected, actual) {\n\t\tt.Fatalf(\"expected: %#[1]v (%[1]T), got: %#[2]v (%[2]T)\", expected, actual)\n\t}\n}\n\n// GH-206: decodeInt throws an error for an empty string\nfunc TestDecode_weakEmptyStringToInt(t *testing.T) {\n\tinput := map[string]any{\n\t\t\"StringToInt\":   \"\",\n\t\t\"StringToUint\":  \"\",\n\t\t\"StringToBool\":  \"\",\n\t\t\"StringToFloat\": \"\",\n\t}\n\n\texpectedResultWeak := TypeConversionResult{\n\t\tStringToInt:   0,\n\t\tStringToUint:  0,\n\t\tStringToBool:  false,\n\t\tStringToFloat: 0,\n\t}\n\n\t// Test weak type conversion\n\tvar resultWeak TypeConversionResult\n\terr := WeakDecode(input, &resultWeak)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif !reflect.DeepEqual(resultWeak, expectedResultWeak) {\n\t\tt.Errorf(\"expected \\n%#v, got: \\n%#v\", expectedResultWeak, resultWeak)\n\t}\n}\n\n// GH-228: Squash cause *time.Time set to zero\nfunc TestMapSquash(t *testing.T) {\n\ttype AA struct {\n\t\tT *time.Time\n\t}\n\ttype A struct {\n\t\tAA\n\t}\n\n\tv := time.Now()\n\tin := &AA{\n\t\tT: &v,\n\t}\n\tout := &A{}\n\td, err := NewDecoder(&DecoderConfig{\n\t\tSquash: true,\n\t\tResult: out,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\tif err := d.Decode(in); err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\t// these failed\n\tif !v.Equal(*out.T) {\n\t\tt.Fatal(\"expected equal\")\n\t}\n\tif out.T.IsZero() {\n\t\tt.Fatal(\"expected false\")\n\t}\n}\n\n// GH-238: Empty key name when decoding map from struct with only omitempty flag\nfunc TestMapOmitEmptyWithEmptyFieldnameInTag(t *testing.T) {\n\ttype Struct struct {\n\t\tUsername string `mapstructure:\",omitempty\"`\n\t\tAge      int    `mapstructure:\",omitempty\"`\n\t}\n\n\ts := Struct{\n\t\tUsername: \"Joe\",\n\t}\n\tvar m map[string]any\n\n\tif err := Decode(s, &m); err != nil {\n\t\tt.Fatal(err)\n\t}\n\n\tif len(m) != 1 {\n\t\tt.Fatalf(\"fail: %#v\", m)\n\t}\n\tif m[\"Username\"] != \"Joe\" {\n\t\tt.Fatalf(\"fail: %#v\", m)\n\t}\n}\n\n// GH-340: Decoding array of slices causes panic\ntype HasNonComparableType struct {\n\tNonComparableType [2][]byte\n}\n\nfunc TestDecode_nonComparableType(t *testing.T) {\n\tdecodeTo := &HasNonComparableType{}\n\texpected := [2][]byte{{1, 2}, {3, 4, 5}}\n\tif err := Decode(map[string]any{\"NonComparableType\": expected}, &decodeTo); err != nil {\n\t\tt.Fatal(err)\n\t}\n\tif !reflect.DeepEqual(expected, decodeTo.NonComparableType) {\n\t\tt.Fatalf(\"fail: %#v\", decodeTo.NonComparableType)\n\t}\n}\n\n// GH-347: Decoding maps with multiple indirection results in an error\nfunc TestDecodeToMapWithMultipleIndirection(t *testing.T) {\n\tt.Run(\"Struct\", func(t *testing.T) {\n\t\ttype Struct struct {\n\t\t\tFoo string `mapstructure:\"foo\"`\n\t\t}\n\n\t\tv := Struct{\n\t\t\tFoo: \"bar\",\n\t\t}\n\n\t\ti := &v\n\t\tii := &i\n\t\tiii := &ii\n\n\t\tvar actual map[string]any\n\n\t\tif err := Decode(iii, &actual); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\texpected := map[string]any{\n\t\t\t\"foo\": \"bar\",\n\t\t}\n\n\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\tt.Fatalf(\"expected: %#v, got: %#v\", expected, actual)\n\t\t}\n\t})\n\n\tt.Run(\"Map\", func(t *testing.T) {\n\t\tv := map[string]any{\n\t\t\t\"foo\": \"bar\",\n\t\t}\n\n\t\ti := &v\n\t\tii := &i\n\t\tiii := &ii\n\n\t\tvar actual map[string]any\n\n\t\tif err := Decode(iii, &actual); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\texpected := map[string]any{\n\t\t\t\"foo\": \"bar\",\n\t\t}\n\n\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\tt.Fatalf(\"expected: %#v, got: %#v\", expected, actual)\n\t\t}\n\t})\n\n\tt.Run(\"Array\", func(t *testing.T) {\n\t\tv := [1]map[string]any{\n\t\t\t{\n\t\t\t\t\"foo\": \"bar\",\n\t\t\t},\n\t\t}\n\n\t\ti := &v\n\t\tii := &i\n\t\tiii := &ii\n\n\t\tvar actual map[string]any\n\n\t\tif err := WeakDecode(iii, &actual); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\texpected := map[string]any{\n\t\t\t\"foo\": \"bar\",\n\t\t}\n\n\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\tt.Fatalf(\"expected: %#v, got: %#v\", expected, actual)\n\t\t}\n\t})\n\n\tt.Run(\"Slice\", func(t *testing.T) {\n\t\tv := []map[string]any{\n\t\t\t{\n\t\t\t\t\"foo\": \"bar\",\n\t\t\t},\n\t\t}\n\n\t\ti := &v\n\t\tii := &i\n\t\tiii := &ii\n\n\t\tvar actual map[string]any\n\n\t\tif err := WeakDecode(iii, &actual); err != nil {\n\t\t\tt.Fatal(err)\n\t\t}\n\n\t\texpected := map[string]any{\n\t\t\t\"foo\": \"bar\",\n\t\t}\n\n\t\tif !reflect.DeepEqual(actual, expected) {\n\t\t\tt.Fatalf(\"expected: %#v, got: %#v\", expected, actual)\n\t\t}\n\t})\n}\n"
  },
  {
    "path": "mapstructure_examples_test.go",
    "content": "package mapstructure\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc ExampleDecode() {\n\ttype Person struct {\n\t\tName   string\n\t\tAge    int\n\t\tEmails []string\n\t\tExtra  map[string]string\n\t}\n\n\t// This input can come from anywhere, but typically comes from\n\t// something like decoding JSON where we're not quite sure of the\n\t// struct initially.\n\tinput := map[string]any{\n\t\t\"name\":   \"Mitchell\",\n\t\t\"age\":    91,\n\t\t\"emails\": []string{\"one\", \"two\", \"three\"},\n\t\t\"extra\": map[string]string{\n\t\t\t\"twitter\": \"mitchellh\",\n\t\t},\n\t}\n\n\tvar result Person\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%#v\", result)\n\t// Output:\n\t// mapstructure.Person{Name:\"Mitchell\", Age:91, Emails:[]string{\"one\", \"two\", \"three\"}, Extra:map[string]string{\"twitter\":\"mitchellh\"}}\n}\n\nfunc ExampleDecode_errors() {\n\ttype Person struct {\n\t\tName   string\n\t\tAge    int\n\t\tEmails []string\n\t\tExtra  map[string]string\n\t}\n\n\t// This input can come from anywhere, but typically comes from\n\t// something like decoding JSON where we're not quite sure of the\n\t// struct initially.\n\tinput := map[string]any{\n\t\t\"name\":   123,\n\t\t\"age\":    \"bad value\",\n\t\t\"emails\": []int{1, 2, 3},\n\t}\n\n\tvar result Person\n\terr := Decode(input, &result)\n\tif err == nil {\n\t\tpanic(\"should have an error\")\n\t}\n\n\tfmt.Println(err.Error())\n\t// Output:\n\t// decoding failed due to the following error(s):\n\t//\n\t// 'Name' expected type 'string', got unconvertible type 'int'\n\t// 'Age' expected type 'int', got unconvertible type 'string'\n\t// 'Emails[0]' expected type 'string', got unconvertible type 'int'\n\t// 'Emails[1]' expected type 'string', got unconvertible type 'int'\n\t// 'Emails[2]' expected type 'string', got unconvertible type 'int'\n}\n\nfunc ExampleDecode_metadata() {\n\ttype Person struct {\n\t\tName string\n\t\tAge  int\n\t}\n\n\t// This input can come from anywhere, but typically comes from\n\t// something like decoding JSON where we're not quite sure of the\n\t// struct initially.\n\tinput := map[string]any{\n\t\t\"name\":  \"Mitchell\",\n\t\t\"age\":   91,\n\t\t\"email\": \"foo@bar.com\",\n\t}\n\n\t// For metadata, we make a more advanced DecoderConfig so we can\n\t// more finely configure the decoder that is used. In this case, we\n\t// just tell the decoder we want to track metadata.\n\tvar md Metadata\n\tvar result Person\n\tconfig := &DecoderConfig{\n\t\tMetadata: &md,\n\t\tResult:   &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tif err := decoder.Decode(input); err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"Unused keys: %#v\", md.Unused)\n\t// Output:\n\t// Unused keys: []string{\"email\"}\n}\n\nfunc ExampleDecode_weaklyTypedInput() {\n\ttype Person struct {\n\t\tName   string\n\t\tAge    int\n\t\tEmails []string\n\t}\n\n\t// This input can come from anywhere, but typically comes from\n\t// something like decoding JSON, generated by a weakly typed language\n\t// such as PHP.\n\tinput := map[string]any{\n\t\t\"name\":   123,              // number => string\n\t\t\"age\":    \"42\",             // string => number\n\t\t\"emails\": map[string]any{}, // empty map => empty array\n\t}\n\n\tvar result Person\n\tconfig := &DecoderConfig{\n\t\tWeaklyTypedInput: true,\n\t\tResult:           &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%#v\", result)\n\t// Output: mapstructure.Person{Name:\"123\", Age:42, Emails:[]string{}}\n}\n\nfunc ExampleDecode_tags() {\n\t// Note that the mapstructure tags defined in the struct type\n\t// can indicate which fields the values are mapped to.\n\ttype Person struct {\n\t\tName string `mapstructure:\"person_name\"`\n\t\tAge  int    `mapstructure:\"person_age\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"person_name\": \"Mitchell\",\n\t\t\"person_age\":  91,\n\t}\n\n\tvar result Person\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%#v\", result)\n\t// Output:\n\t// mapstructure.Person{Name:\"Mitchell\", Age:91}\n}\n\nfunc ExampleDecode_embeddedStruct() {\n\t// Squashing multiple embedded structs is allowed using the squash tag.\n\t// This is demonstrated by creating a composite struct of multiple types\n\t// and decoding into it. In this case, a person can carry with it both\n\t// a Family and a Location, as well as their own FirstName.\n\ttype Family struct {\n\t\tLastName string\n\t}\n\ttype Location struct {\n\t\tCity string\n\t}\n\ttype Person struct {\n\t\tFamily    `mapstructure:\",squash\"`\n\t\tLocation  `mapstructure:\",squash\"`\n\t\tFirstName string\n\t}\n\n\tinput := map[string]any{\n\t\t\"FirstName\": \"Mitchell\",\n\t\t\"LastName\":  \"Hashimoto\",\n\t\t\"City\":      \"San Francisco\",\n\t}\n\n\tvar result Person\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%s %s, %s\", result.FirstName, result.LastName, result.City)\n\t// Output:\n\t// Mitchell Hashimoto, San Francisco\n}\n\nfunc ExampleDecode_remainingData() {\n\t// Note that the mapstructure tags defined in the struct type\n\t// can indicate which fields the values are mapped to.\n\ttype Person struct {\n\t\tName  string\n\t\tAge   int\n\t\tOther map[string]any `mapstructure:\",remain\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"name\":  \"Mitchell\",\n\t\t\"age\":   91,\n\t\t\"email\": \"mitchell@example.com\",\n\t}\n\n\tvar result Person\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%#v\", result)\n\t// Output:\n\t// mapstructure.Person{Name:\"Mitchell\", Age:91, Other:map[string]interface {}{\"email\":\"mitchell@example.com\"}}\n}\n\nfunc ExampleDecode_remainingDataDecodeBackToMapInFlatFormat() {\n\t// Note that the mapstructure tags defined in the struct type\n\t// can indicate which fields the values are mapped to.\n\ttype Person struct {\n\t\tName  string\n\t\tAge   int\n\t\tOther map[string]any `mapstructure:\",remain\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"name\": \"Luffy\",\n\t\t\"age\":  19,\n\t\t\"powers\": []string{\n\t\t\t\"Rubber Man\",\n\t\t\t\"Conqueror Haki\",\n\t\t},\n\t}\n\n\tvar person Person\n\terr := Decode(input, &person)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tresult := make(map[string]any)\n\terr = Decode(&person, &result)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%#v\", result)\n\t// Output:\n\t// map[string]interface {}{\"Age\":19, \"Name\":\"Luffy\", \"powers\":[]string{\"Rubber Man\", \"Conqueror Haki\"}}\n}\n\nfunc ExampleDecode_omitempty() {\n\t// Add omitempty annotation to avoid map keys for empty values\n\ttype Family struct {\n\t\tLastName string\n\t}\n\ttype Location struct {\n\t\tCity string\n\t}\n\ttype Person struct {\n\t\t*Family   `mapstructure:\",omitempty\"`\n\t\t*Location `mapstructure:\",omitempty\"`\n\t\tAge       int\n\t\tFirstName string\n\t}\n\n\tresult := &map[string]any{}\n\tinput := Person{FirstName: \"Somebody\"}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%+v\", result)\n\t// Output:\n\t// &map[Age:0 FirstName:Somebody]\n}\n\nfunc ExampleDecode_decodeHookFunc() {\n\ttype PersonLocation struct {\n\t\tLatitude   float64\n\t\tLongtitude float64\n\t}\n\n\ttype Person struct {\n\t\tName     string\n\t\tLocation PersonLocation\n\t}\n\n\t// Example of parsing messy input: here we have latitude, longitude squashed into\n\t// a single string field. We write a custom DecodeHookFunc to parse the '#' separated\n\t// values into a PersonLocation struct.\n\tinput := map[string]any{\n\t\t\"name\":     \"Mitchell\",\n\t\t\"location\": \"-35.2809#149.1300\",\n\t}\n\n\ttoPersonLocationHookFunc := func() DecodeHookFunc {\n\t\treturn func(f reflect.Type, t reflect.Type, data any) (any, error) {\n\t\t\tif t != reflect.TypeOf(PersonLocation{}) {\n\t\t\t\treturn data, nil\n\t\t\t}\n\n\t\t\tswitch f.Kind() {\n\t\t\tcase reflect.String:\n\t\t\t\txs := strings.Split(data.(string), \"#\")\n\n\t\t\t\tif len(xs) == 2 {\n\t\t\t\t\tlat, errLat := strconv.ParseFloat(xs[0], 64)\n\t\t\t\t\tlon, errLon := strconv.ParseFloat(xs[1], 64)\n\n\t\t\t\t\tif errLat == nil && errLon == nil {\n\t\t\t\t\t\treturn PersonLocation{Latitude: lat, Longtitude: lon}, nil\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\treturn data, nil\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn data, nil\n\t\t}\n\t}\n\n\tvar result Person\n\n\tdecoder, errDecoder := NewDecoder(&DecoderConfig{\n\t\tMetadata:   nil,\n\t\tDecodeHook: toPersonLocationHookFunc(), // Here, use ComposeDecodeHookFunc to run multiple hooks.\n\t\tResult:     &result,\n\t})\n\tif errDecoder != nil {\n\t\tpanic(errDecoder)\n\t}\n\n\terr := decoder.Decode(input)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Printf(\"%#v\", result)\n\t// Output:\n\t// mapstructure.Person{Name:\"Mitchell\", Location:mapstructure.PersonLocation{Latitude:-35.2809, Longtitude:149.13}}\n}\n\n// ExampleServerConfig is used by ExampleDecode_unmarshaler.\n// It implements the Unmarshaler interface to apply custom decoding logic.\ntype ExampleServerConfig struct {\n\tHost string\n\tPort int\n}\n\n// UnmarshalMapstructure implements the Unmarshaler interface.\n// It applies default values when fields are missing from the input.\nfunc (s *ExampleServerConfig) UnmarshalMapstructure(data any) error {\n\tm, ok := data.(map[string]any)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected map[string]any, got %T\", data)\n\t}\n\n\t// Apply defaults first\n\ts.Host = \"localhost\"\n\ts.Port = 8080\n\n\t// Override with provided values\n\tif host, ok := m[\"host\"].(string); ok {\n\t\ts.Host = host\n\t}\n\tif port, ok := m[\"port\"].(int); ok {\n\t\ts.Port = port\n\t}\n\n\treturn nil\n}\n\nfunc ExampleDecode_unmarshaler() {\n\t// Types that implement the Unmarshaler interface can control how they\n\t// are decoded from map data. This is useful for applying defaults,\n\t// custom validation, or complex transformation logic.\n\n\tinput := map[string]any{\n\t\t\"host\": \"example.com\",\n\t\t// Note: port is intentionally omitted to demonstrate default handling\n\t}\n\n\tvar result ExampleServerConfig\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\t// The Unmarshaler applied the default port value since it wasn't in the input\n\tfmt.Printf(\"Host: %s, Port: %d\", result.Host, result.Port)\n\n\t// Output:\n\t// Host: example.com, Port: 8080\n}\n"
  },
  {
    "path": "mapstructure_test.go",
    "content": "package mapstructure\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n)\n\ntype Basic struct {\n\tVstring     string\n\tVint        int\n\tVint8       int8\n\tVint16      int16\n\tVint32      int32\n\tVint64      int64\n\tVuint       uint\n\tVbool       bool\n\tVfloat      float64\n\tVextra      string\n\tvsilent     bool\n\tVdata       any\n\tVjsonInt    int\n\tVjsonUint   uint\n\tVjsonUint64 uint64\n\tVjsonFloat  float64\n\tVjsonNumber json.Number\n\tVcomplex64  complex64\n\tVcomplex128 complex128\n}\n\ntype BasicPointer struct {\n\tVstring     *string\n\tVint        *int\n\tVuint       *uint\n\tVbool       *bool\n\tVfloat      *float64\n\tVextra      *string\n\tvsilent     *bool\n\tVdata       *any\n\tVjsonInt    *int\n\tVjsonFloat  *float64\n\tVjsonNumber *json.Number\n}\n\ntype BasicSquash struct {\n\tTest Basic `mapstructure:\",squash\"`\n}\n\ntype BasicJSONInline struct {\n\tTest Basic `json:\",inline\"`\n}\n\ntype Embedded struct {\n\tBasic\n\tVunique string\n}\n\ntype EmbeddedPointer struct {\n\t*Basic\n\tVunique string\n}\n\ntype EmbeddedSquash struct {\n\tBasic   `mapstructure:\",squash\"`\n\tVunique string\n}\n\ntype EmbeddedPointerSquash struct {\n\t*Basic  `mapstructure:\",squash\"`\n\tVunique string\n}\n\ntype BasicMapStructure struct {\n\tVunique string     `mapstructure:\"vunique\"`\n\tVtime   *time.Time `mapstructure:\"time\"`\n}\n\ntype NestedPointerWithMapstructure struct {\n\tVbar *BasicMapStructure `mapstructure:\"vbar\"`\n}\n\ntype EmbeddedPointerSquashWithNestedMapstructure struct {\n\t*NestedPointerWithMapstructure `mapstructure:\",squash\"`\n\tVunique                        string\n}\n\ntype EmbeddedAndNamed struct {\n\tBasic\n\tNamed   Basic\n\tVunique string\n}\n\ntype SliceAlias []string\n\ntype EmbeddedSlice struct {\n\tSliceAlias `mapstructure:\"slice_alias\"`\n\tVunique    string\n}\n\ntype ArrayAlias [2]string\n\ntype EmbeddedArray struct {\n\tArrayAlias `mapstructure:\"array_alias\"`\n\tVunique    string\n}\n\ntype SquashOnNonStructType struct {\n\tInvalidSquashType int `mapstructure:\",squash\"`\n}\n\ntype TestInterface interface {\n\tGetVfoo() string\n\tGetVbarfoo() string\n\tGetVfoobar() string\n}\n\ntype TestInterfaceImpl struct {\n\tVfoo string\n}\n\nfunc (t *TestInterfaceImpl) GetVfoo() string {\n\treturn t.Vfoo\n}\n\nfunc (t *TestInterfaceImpl) GetVbarfoo() string {\n\treturn \"\"\n}\n\nfunc (t *TestInterfaceImpl) GetVfoobar() string {\n\treturn \"\"\n}\n\ntype TestNestedInterfaceImpl struct {\n\tSquashOnNestedInterfaceType `mapstructure:\",squash\"`\n\tVfoo                        string\n}\n\nfunc (t *TestNestedInterfaceImpl) GetVfoo() string {\n\treturn t.Vfoo\n}\n\nfunc (t *TestNestedInterfaceImpl) GetVbarfoo() string {\n\treturn t.Vbarfoo\n}\n\nfunc (t *TestNestedInterfaceImpl) GetVfoobar() string {\n\treturn t.NestedSquash.Vfoobar\n}\n\ntype SquashOnInterfaceType struct {\n\tTestInterface `mapstructure:\",squash\"`\n\tVbar          string\n}\n\ntype NestedSquash struct {\n\tSquashOnInterfaceType `mapstructure:\",squash\"`\n\tVfoobar               string\n}\n\ntype SquashOnNestedInterfaceType struct {\n\tNestedSquash NestedSquash `mapstructure:\",squash\"`\n\tVbarfoo      string\n}\n\ntype Map struct {\n\tVfoo   string\n\tVother map[string]string\n}\n\ntype MapOfStruct struct {\n\tValue map[string]Basic\n}\n\ntype Nested struct {\n\tVfoo string\n\tVbar Basic\n}\n\ntype NestedPointer struct {\n\tVfoo string\n\tVbar *Basic\n}\n\ntype NilInterface struct {\n\tW io.Writer\n}\n\ntype NilPointer struct {\n\tValue *string\n}\n\ntype Slice struct {\n\tVfoo string\n\tVbar []string\n}\n\ntype SliceOfByte struct {\n\tVfoo string\n\tVbar []byte\n}\n\ntype SliceOfAlias struct {\n\tVfoo string\n\tVbar SliceAlias\n}\n\ntype SliceOfStruct struct {\n\tValue []Basic\n}\n\ntype SlicePointer struct {\n\tVbar *[]string\n}\n\ntype Array struct {\n\tVfoo string\n\tVbar [2]string\n}\n\ntype ArrayOfStruct struct {\n\tValue [2]Basic\n}\n\ntype Func struct {\n\tFoo func() string\n}\n\ntype Tagged struct {\n\tExtra string `mapstructure:\"bar,what,what\"`\n\tValue string `mapstructure:\"foo\"`\n}\n\ntype Remainder struct {\n\tA     string\n\tExtra map[string]any `mapstructure:\",remain\"`\n}\n\ntype StructWithOmitEmpty struct {\n\tVisibleStringField string         `mapstructure:\"visible-string\"`\n\tOmitStringField    string         `mapstructure:\"omittable-string,omitempty\"`\n\tVisibleIntField    int            `mapstructure:\"visible-int\"`\n\tOmitIntField       int            `mapstructure:\"omittable-int,omitempty\"`\n\tVisibleFloatField  float64        `mapstructure:\"visible-float\"`\n\tOmitFloatField     float64        `mapstructure:\"omittable-float,omitempty\"`\n\tVisibleSliceField  []any          `mapstructure:\"visible-slice\"`\n\tOmitSliceField     []any          `mapstructure:\"omittable-slice,omitempty\"`\n\tVisibleMapField    map[string]any `mapstructure:\"visible-map\"`\n\tOmitMapField       map[string]any `mapstructure:\"omittable-map,omitempty\"`\n\tNestedField        *Nested        `mapstructure:\"visible-nested\"`\n\tOmitNestedField    *Nested        `mapstructure:\"omittable-nested,omitempty\"`\n}\n\ntype StructWithOmitZero struct {\n\tVisibleStringField string         `mapstructure:\"visible-string\"`\n\tOmitStringField    string         `mapstructure:\"omittable-string,omitzero\"`\n\tVisibleIntField    int            `mapstructure:\"visible-int\"`\n\tOmitIntField       int            `mapstructure:\"omittable-int,omitzero\"`\n\tVisibleFloatField  float64        `mapstructure:\"visible-float\"`\n\tOmitFloatField     float64        `mapstructure:\"omittable-float,omitzero\"`\n\tVisibleSliceField  []any          `mapstructure:\"visible-slice\"`\n\tOmitSliceField     []any          `mapstructure:\"omittable-slice,omitzero\"`\n\tVisibleMapField    map[string]any `mapstructure:\"visible-map\"`\n\tOmitMapField       map[string]any `mapstructure:\"omittable-map,omitzero\"`\n\tNestedField        *Nested        `mapstructure:\"visible-nested\"`\n\tOmitNestedField    *Nested        `mapstructure:\"omittable-nested,omitzero\"`\n}\n\ntype TypeConversionResult struct {\n\tIntToFloat         float32\n\tIntToUint          uint\n\tIntToBool          bool\n\tIntToString        string\n\tUintToInt          int\n\tUintToFloat        float32\n\tUintToBool         bool\n\tUintToString       string\n\tBoolToInt          int\n\tBoolToUint         uint\n\tBoolToFloat        float32\n\tBoolToString       string\n\tFloatToInt         int\n\tFloatToUint        uint\n\tFloatToBool        bool\n\tFloatToString      string\n\tSliceUint8ToString string\n\tStringToSliceUint8 []byte\n\tArrayUint8ToString string\n\tStringToInt        int\n\tStringToUint       uint\n\tStringToBool       bool\n\tStringToFloat      float32\n\tStringToStrSlice   []string\n\tStringToIntSlice   []int\n\tStringToStrArray   [1]string\n\tStringToIntArray   [1]int\n\tSliceToMap         map[string]any\n\tMapToSlice         []any\n\tArrayToMap         map[string]any\n\tMapToArray         [1]any\n}\n\nfunc TestBasicTypes(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\":     \"foo\",\n\t\t\"vint\":        42,\n\t\t\"vint8\":       42,\n\t\t\"vint16\":      42,\n\t\t\"vint32\":      42,\n\t\t\"vint64\":      42,\n\t\t\"Vuint\":       42,\n\t\t\"vbool\":       true,\n\t\t\"Vfloat\":      42.42,\n\t\t\"vsilent\":     true,\n\t\t\"vdata\":       42,\n\t\t\"vjsonInt\":    json.Number(\"1234\"),\n\t\t\"vjsonUint\":   json.Number(\"1234\"),\n\t\t\"vjsonUint64\": json.Number(\"9223372036854775809\"), // 2^63 + 1\n\t\t\"vjsonFloat\":  json.Number(\"1234.5\"),\n\t\t\"vjsonNumber\": json.Number(\"1234.5\"),\n\t\t\"vcomplex64\":  complex(float32(42), float32(42)),\n\t\t\"vcomplex128\": complex(42, 42),\n\t}\n\n\tvar result Basic\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Errorf(\"got an err: %s\", err.Error())\n\t\tt.FailNow()\n\t}\n\n\tif result.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vstring)\n\t}\n\n\tif result.Vint != 42 {\n\t\tt.Errorf(\"vint value should be 42: %#v\", result.Vint)\n\t}\n\tif result.Vint8 != 42 {\n\t\tt.Errorf(\"vint8 value should be 42: %#v\", result.Vint)\n\t}\n\tif result.Vint16 != 42 {\n\t\tt.Errorf(\"vint16 value should be 42: %#v\", result.Vint)\n\t}\n\tif result.Vint32 != 42 {\n\t\tt.Errorf(\"vint32 value should be 42: %#v\", result.Vint)\n\t}\n\tif result.Vint64 != 42 {\n\t\tt.Errorf(\"vint64 value should be 42: %#v\", result.Vint)\n\t}\n\n\tif result.Vuint != 42 {\n\t\tt.Errorf(\"vuint value should be 42: %#v\", result.Vuint)\n\t}\n\n\tif result.Vbool != true {\n\t\tt.Errorf(\"vbool value should be true: %#v\", result.Vbool)\n\t}\n\n\tif result.Vfloat != 42.42 {\n\t\tt.Errorf(\"vfloat value should be 42.42: %#v\", result.Vfloat)\n\t}\n\n\tif result.Vextra != \"\" {\n\t\tt.Errorf(\"vextra value should be empty: %#v\", result.Vextra)\n\t}\n\n\tif result.vsilent != false {\n\t\tt.Error(\"vsilent should not be set, it is unexported\")\n\t}\n\n\tif result.Vdata != 42 {\n\t\tt.Error(\"vdata should be valid\")\n\t}\n\n\tif result.VjsonInt != 1234 {\n\t\tt.Errorf(\"vjsonint value should be 1234: %#v\", result.VjsonInt)\n\t}\n\n\tif result.VjsonUint != 1234 {\n\t\tt.Errorf(\"vjsonuint value should be 1234: %#v\", result.VjsonUint)\n\t}\n\n\tif result.VjsonUint64 != 9223372036854775809 {\n\t\tt.Errorf(\"vjsonuint64 value should be 9223372036854775809: %#v\", result.VjsonUint64)\n\t}\n\n\tif result.VjsonFloat != 1234.5 {\n\t\tt.Errorf(\"vjsonfloat value should be 1234.5: %#v\", result.VjsonFloat)\n\t}\n\n\tif !reflect.DeepEqual(result.VjsonNumber, json.Number(\"1234.5\")) {\n\t\tt.Errorf(\"vjsonnumber value should be '1234.5': %T, %#v\", result.VjsonNumber, result.VjsonNumber)\n\t}\n\n\tif real(result.Vcomplex64) != 42 || imag(result.Vcomplex64) != 42 {\n\t\tt.Errorf(\"vcomplex64 value shou be 42+42i: %#v\", result.Vcomplex64)\n\t}\n\n\tif real(result.Vcomplex128) != 42 || imag(result.Vcomplex128) != 42 {\n\t\tt.Errorf(\"vcomplex64 value shou be 42+42i: %#v\", result.Vcomplex128)\n\t}\n}\n\nfunc TestBasic_IntWithFloat(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vint\": float64(42),\n\t}\n\n\tvar result Basic\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n}\n\nfunc TestBasic_Merge(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vint\": 42,\n\t}\n\n\tvar result Basic\n\tresult.Vuint = 100\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\texpected := Basic{\n\t\tVint:  42,\n\t\tVuint: 100,\n\t}\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\n// Test for issue #46.\nfunc TestBasic_Struct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vdata\": map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t},\n\t}\n\n\tvar result, inner Basic\n\tresult.Vdata = &inner\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\texpected := Basic{\n\t\tVdata: &Basic{\n\t\t\tVstring: \"foo\",\n\t\t},\n\t}\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestBasic_interfaceStruct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t}\n\n\tvar iface any = &Basic{}\n\terr := Decode(input, &iface)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\texpected := &Basic{\n\t\tVstring: \"foo\",\n\t}\n\tif !reflect.DeepEqual(iface, expected) {\n\t\tt.Fatalf(\"bad: %#v\", iface)\n\t}\n}\n\n// Issue 187\nfunc TestBasic_interfaceStructNonPtr(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t}\n\n\tvar iface any = Basic{}\n\terr := Decode(input, &iface)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\texpected := Basic{\n\t\tVstring: \"foo\",\n\t}\n\tif !reflect.DeepEqual(iface, expected) {\n\t\tt.Fatalf(\"bad: %#v\", iface)\n\t}\n}\n\nfunc TestDecode_BasicSquash(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t}\n\n\tvar result BasicSquash\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Test.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Test.Vstring)\n\t}\n}\n\nfunc TestDecodeFrom_BasicSquash(t *testing.T) {\n\tt.Parallel()\n\n\tvar v any\n\tvar ok bool\n\n\tinput := BasicSquash{\n\t\tTest: Basic{\n\t\t\tVstring: \"foo\",\n\t\t},\n\t}\n\n\tvar result map[string]any\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif _, ok = result[\"Test\"]; ok {\n\t\tt.Error(\"test should not be present in map\")\n\t}\n\n\tv, ok = result[\"Vstring\"]\n\tif !ok {\n\t\tt.Error(\"vstring should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"foo\") {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", v)\n\t}\n}\n\nfunc TestDecode_BasicJSONInline(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t}\n\n\tvar result BasicJSONInline\n\td, err := NewDecoder(&DecoderConfig{TagName: \"json\", SquashTagOption: \"inline\", Result: &result})\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif err := d.Decode(input); err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Test.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Test.Vstring)\n\t}\n}\n\nfunc TestDecodeFrom_BasicJSONInline(t *testing.T) {\n\tt.Parallel()\n\n\tvar v any\n\tvar ok bool\n\n\tinput := BasicJSONInline{\n\t\tTest: Basic{\n\t\t\tVstring: \"foo\",\n\t\t},\n\t}\n\n\tvar result map[string]any\n\td, err := NewDecoder(&DecoderConfig{TagName: \"json\", SquashTagOption: \"inline\", Result: &result})\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif err := d.Decode(input); err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif _, ok = result[\"Test\"]; ok {\n\t\tt.Error(\"test should not be present in map\")\n\t}\n\n\tv, ok = result[\"Vstring\"]\n\tif !ok {\n\t\tt.Error(\"vstring should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"foo\") {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", v)\n\t}\n}\n\nfunc TestDecode_Embedded(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"Basic\": map[string]any{\n\t\t\t\"vstring\": \"innerfoo\",\n\t\t},\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tvar result Embedded\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vstring != \"innerfoo\" {\n\t\tt.Errorf(\"vstring value should be 'innerfoo': %#v\", result.Vstring)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecode_EmbeddedPointer(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"Basic\": map[string]any{\n\t\t\t\"vstring\": \"innerfoo\",\n\t\t},\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tvar result EmbeddedPointer\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\texpected := EmbeddedPointer{\n\t\tBasic: &Basic{\n\t\t\tVstring: \"innerfoo\",\n\t\t},\n\t\tVunique: \"bar\",\n\t}\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestDecode_EmbeddedSlice(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"slice_alias\": []string{\"foo\", \"bar\"},\n\t\t\"vunique\":     \"bar\",\n\t}\n\n\tvar result EmbeddedSlice\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif !reflect.DeepEqual(result.SliceAlias, SliceAlias([]string{\"foo\", \"bar\"})) {\n\t\tt.Errorf(\"slice value: %#v\", result.SliceAlias)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecode_EmbeddedArray(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"array_alias\": [2]string{\"foo\", \"bar\"},\n\t\t\"vunique\":     \"bar\",\n\t}\n\n\tvar result EmbeddedArray\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif !reflect.DeepEqual(result.ArrayAlias, ArrayAlias([2]string{\"foo\", \"bar\"})) {\n\t\tt.Errorf(\"array value: %#v\", result.ArrayAlias)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecode_decodeSliceWithArray(t *testing.T) {\n\tt.Parallel()\n\n\tvar result []int\n\tinput := [1]int{1}\n\texpected := []int{1}\n\tif err := Decode(input, &result); err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif !reflect.DeepEqual(expected, result) {\n\t\tt.Errorf(\"wanted %+v, got %+v\", expected, result)\n\t}\n}\n\nfunc TestDecode_EmbeddedNoSquash(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tvar result Embedded\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vstring != \"\" {\n\t\tt.Errorf(\"vstring value should be empty: %#v\", result.Vstring)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecode_EmbeddedPointerNoSquash(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tresult := EmbeddedPointer{\n\t\tBasic: &Basic{},\n\t}\n\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tif result.Vstring != \"\" {\n\t\tt.Errorf(\"vstring value should be empty: %#v\", result.Vstring)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecode_EmbeddedSquash(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tvar result EmbeddedSquash\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vstring)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecodeFrom_EmbeddedSquash(t *testing.T) {\n\tt.Parallel()\n\n\tvar v any\n\tvar ok bool\n\n\tinput := EmbeddedSquash{\n\t\tBasic: Basic{\n\t\t\tVstring: \"foo\",\n\t\t},\n\t\tVunique: \"bar\",\n\t}\n\n\tvar result map[string]any\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif _, ok = result[\"Basic\"]; ok {\n\t\tt.Error(\"basic should not be present in map\")\n\t}\n\n\tv, ok = result[\"Vstring\"]\n\tif !ok {\n\t\tt.Error(\"vstring should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"foo\") {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", v)\n\t}\n\n\tv, ok = result[\"Vunique\"]\n\tif !ok {\n\t\tt.Error(\"vunique should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"bar\") {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", v)\n\t}\n}\n\nfunc TestDecode_EmbeddedPointerSquash_FromStructToMap(t *testing.T) {\n\tt.Parallel()\n\n\tinput := EmbeddedPointerSquash{\n\t\tBasic: &Basic{\n\t\t\tVstring: \"foo\",\n\t\t},\n\t\tVunique: \"bar\",\n\t}\n\n\tvar result map[string]any\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result[\"Vstring\"] != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result[\"Vstring\"])\n\t}\n\n\tif result[\"Vunique\"] != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result[\"Vunique\"])\n\t}\n}\n\nfunc TestDecode_EmbeddedPointerSquash_FromMapToStruct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"Vstring\": \"foo\",\n\t\t\"Vunique\": \"bar\",\n\t}\n\n\tresult := EmbeddedPointerSquash{\n\t\tBasic: &Basic{},\n\t}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vstring)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecode_EmbeddedPointerSquash_WithoutPreInitializedStructs_FromMapToStruct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"Vstring\": \"foo\",\n\t\t\"Vunique\": \"bar\",\n\t}\n\n\tresult := EmbeddedPointerSquash{}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vstring)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n}\n\nfunc TestDecode_EmbeddedPointerSquashWithNestedMapstructure_FromStructToMap(t *testing.T) {\n\tt.Parallel()\n\n\tvTime := time.Now()\n\n\tinput := EmbeddedPointerSquashWithNestedMapstructure{\n\t\tNestedPointerWithMapstructure: &NestedPointerWithMapstructure{\n\t\t\tVbar: &BasicMapStructure{\n\t\t\t\tVunique: \"bar\",\n\t\t\t\tVtime:   &vTime,\n\t\t\t},\n\t\t},\n\t\tVunique: \"foo\",\n\t}\n\n\tvar result map[string]any\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\texpected := map[string]any{\n\t\t\"vbar\": map[string]any{\n\t\t\t\"vunique\": \"bar\",\n\t\t\t\"time\":    &vTime,\n\t\t},\n\t\t\"Vunique\": \"foo\",\n\t}\n\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Errorf(\"result should be %#v: got %#v\", expected, result)\n\t}\n}\n\nfunc TestDecode_EmbeddedPointerSquashWithNestedMapstructure_FromMapToStruct(t *testing.T) {\n\tt.Parallel()\n\n\tvTime := time.Now()\n\n\tinput := map[string]any{\n\t\t\"vbar\": map[string]any{\n\t\t\t\"vunique\": \"bar\",\n\t\t\t\"time\":    &vTime,\n\t\t},\n\t\t\"Vunique\": \"foo\",\n\t}\n\n\tresult := EmbeddedPointerSquashWithNestedMapstructure{\n\t\tNestedPointerWithMapstructure: &NestedPointerWithMapstructure{},\n\t}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\texpected := EmbeddedPointerSquashWithNestedMapstructure{\n\t\tNestedPointerWithMapstructure: &NestedPointerWithMapstructure{\n\t\t\tVbar: &BasicMapStructure{\n\t\t\t\tVunique: \"bar\",\n\t\t\t\tVtime:   &vTime,\n\t\t\t},\n\t\t},\n\t\tVunique: \"foo\",\n\t}\n\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Errorf(\"result should be %#v: got %#v\", expected, result)\n\t}\n}\n\nfunc TestDecode_EmbeddedSquashConfig(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"vunique\": \"bar\",\n\t\t\"Named\": map[string]any{\n\t\t\t\"vstring\": \"baz\",\n\t\t},\n\t}\n\n\tvar result EmbeddedAndNamed\n\tconfig := &DecoderConfig{\n\t\tSquash: true,\n\t\tResult: &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif result.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vstring)\n\t}\n\n\tif result.Vunique != \"bar\" {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", result.Vunique)\n\t}\n\n\tif result.Named.Vstring != \"baz\" {\n\t\tt.Errorf(\"Named.vstring value should be 'baz': %#v\", result.Named.Vstring)\n\t}\n}\n\nfunc TestDecodeFrom_EmbeddedSquashConfig(t *testing.T) {\n\tt.Parallel()\n\n\tinput := EmbeddedAndNamed{\n\t\tBasic:   Basic{Vstring: \"foo\"},\n\t\tNamed:   Basic{Vstring: \"baz\"},\n\t\tVunique: \"bar\",\n\t}\n\n\tresult := map[string]any{}\n\tconfig := &DecoderConfig{\n\t\tSquash: true,\n\t\tResult: &result,\n\t}\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif _, ok := result[\"Basic\"]; ok {\n\t\tt.Error(\"basic should not be present in map\")\n\t}\n\n\tv, ok := result[\"Vstring\"]\n\tif !ok {\n\t\tt.Error(\"vstring should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"foo\") {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", v)\n\t}\n\n\tv, ok = result[\"Vunique\"]\n\tif !ok {\n\t\tt.Error(\"vunique should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"bar\") {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", v)\n\t}\n\n\tv, ok = result[\"Named\"]\n\tif !ok {\n\t\tt.Error(\"Named should be present in map\")\n\t} else {\n\t\tnamed := v.(map[string]any)\n\t\tv, ok := named[\"Vstring\"]\n\t\tif !ok {\n\t\t\tt.Error(\"Named: vstring should be present in map\")\n\t\t} else if !reflect.DeepEqual(v, \"baz\") {\n\t\t\tt.Errorf(\"Named: vstring should be 'baz': %#v\", v)\n\t\t}\n\t}\n}\n\nfunc TestDecodeFrom_EmbeddedSquashConfig_WithTags(t *testing.T) {\n\tt.Parallel()\n\n\tvar v any\n\tvar ok bool\n\n\tinput := EmbeddedSquash{\n\t\tBasic: Basic{\n\t\t\tVstring: \"foo\",\n\t\t},\n\t\tVunique: \"bar\",\n\t}\n\n\tresult := map[string]any{}\n\tconfig := &DecoderConfig{\n\t\tSquash: true,\n\t\tResult: &result,\n\t}\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif _, ok = result[\"Basic\"]; ok {\n\t\tt.Error(\"basic should not be present in map\")\n\t}\n\n\tv, ok = result[\"Vstring\"]\n\tif !ok {\n\t\tt.Error(\"vstring should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"foo\") {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", v)\n\t}\n\n\tv, ok = result[\"Vunique\"]\n\tif !ok {\n\t\tt.Error(\"vunique should be present in map\")\n\t} else if !reflect.DeepEqual(v, \"bar\") {\n\t\tt.Errorf(\"vunique value should be 'bar': %#v\", v)\n\t}\n}\n\nfunc TestDecode_SquashOnNonStructType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"InvalidSquashType\": 42,\n\t}\n\n\tvar result SquashOnNonStructType\n\terr := Decode(input, &result)\n\tif err == nil {\n\t\tt.Fatal(\"unexpected success decoding invalid squash field type\")\n\t} else if !strings.Contains(err.Error(), \"unsupported type for squash\") {\n\t\tt.Fatalf(\"unexpected error message for invalid squash field type: %s\", err)\n\t}\n}\n\nfunc TestDecode_SquashOnInterfaceType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"VFoo\": \"42\",\n\t\t\"VBar\": \"43\",\n\t}\n\n\tresult := SquashOnInterfaceType{\n\t\tTestInterface: &TestInterfaceImpl{},\n\t}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tres := result.GetVfoo()\n\tif res != \"42\" {\n\t\tt.Errorf(\"unexpected value for VFoo: %s\", res)\n\t}\n\n\tres = result.Vbar\n\tif res != \"43\" {\n\t\tt.Errorf(\"unexpected value for Vbar: %s\", res)\n\t}\n}\n\nfunc TestDecode_SquashOnOuterNestedInterfaceType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"VFoo\":    \"42\",\n\t\t\"VBar\":    \"43\",\n\t\t\"Vfoobar\": \"44\",\n\t\t\"Vbarfoo\": \"45\",\n\t}\n\n\tresult := SquashOnNestedInterfaceType{\n\t\tNestedSquash: NestedSquash{\n\t\t\tSquashOnInterfaceType: SquashOnInterfaceType{\n\t\t\t\tTestInterface: &TestInterfaceImpl{},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tres := result.NestedSquash.GetVfoo()\n\tif res != \"42\" {\n\t\tt.Errorf(\"unexpected value for VFoo: %s\", res)\n\t}\n\n\tres = result.NestedSquash.Vbar\n\tif res != \"43\" {\n\t\tt.Errorf(\"unexpected value for Vbar: %s\", res)\n\t}\n\n\tres = result.NestedSquash.Vfoobar\n\tif res != \"44\" {\n\t\tt.Errorf(\"unexpected value for Vfoobar: %s\", res)\n\t}\n\n\tres = result.Vbarfoo\n\tif res != \"45\" {\n\t\tt.Errorf(\"unexpected value for Vbarfoo: %s\", res)\n\t}\n}\n\nfunc TestDecode_SquashOnInnerNestedInterfaceType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"VFoo\":    \"42\",\n\t\t\"VBar\":    \"43\",\n\t\t\"Vfoobar\": \"44\",\n\t\t\"Vbarfoo\": \"45\",\n\t}\n\n\tresult := SquashOnInterfaceType{\n\t\tTestInterface: &TestNestedInterfaceImpl{\n\t\t\tSquashOnNestedInterfaceType: SquashOnNestedInterfaceType{\n\t\t\t\tNestedSquash: NestedSquash{\n\t\t\t\t\tSquashOnInterfaceType: SquashOnInterfaceType{\n\t\t\t\t\t\tTestInterface: &TestInterfaceImpl{},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t}\n\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tres := result.GetVfoo()\n\tif res != \"42\" {\n\t\tt.Errorf(\"unexpected value for VFoo: %s\", res)\n\t}\n\n\tres = result.Vbar\n\tif res != \"43\" {\n\t\tt.Errorf(\"unexpected value for Vbar: %s\", res)\n\t}\n\n\tres = result.GetVfoobar()\n\tif res != \"44\" {\n\t\tt.Errorf(\"unexpected value for Vfoobar: %s\", res)\n\t}\n\n\tres = result.GetVbarfoo()\n\tif res != \"45\" {\n\t\tt.Errorf(\"unexpected value for Vbarfoo: %s\", res)\n\t}\n}\n\nfunc TestDecode_SquashOnNilInterfaceType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"VFoo\": \"42\",\n\t\t\"VBar\": \"43\",\n\t}\n\n\tresult := SquashOnInterfaceType{\n\t\tTestInterface: nil,\n\t}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tres := result.Vbar\n\tif res != \"43\" {\n\t\tt.Errorf(\"unexpected value for Vbar: %s\", res)\n\t}\n}\n\nfunc TestDecode_DecodeHook(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vint\": \"WHAT\",\n\t}\n\n\tdecodeHook := func(from reflect.Kind, to reflect.Kind, v any) (any, error) {\n\t\tif from == reflect.String && to != reflect.String {\n\t\t\treturn 5, nil\n\t\t}\n\n\t\treturn v, nil\n\t}\n\n\tvar result Basic\n\tconfig := &DecoderConfig{\n\t\tDecodeHook: decodeHook,\n\t\tResult:     &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif result.Vint != 5 {\n\t\tt.Errorf(\"vint should be 5: %#v\", result.Vint)\n\t}\n}\n\nfunc TestDecode_DecodeHookType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vint\": \"WHAT\",\n\t}\n\n\tdecodeHook := func(from reflect.Type, to reflect.Type, v any) (any, error) {\n\t\tif from.Kind() == reflect.String &&\n\t\t\tto.Kind() != reflect.String {\n\t\t\treturn 5, nil\n\t\t}\n\n\t\treturn v, nil\n\t}\n\n\tvar result Basic\n\tconfig := &DecoderConfig{\n\t\tDecodeHook: decodeHook,\n\t\tResult:     &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif result.Vint != 5 {\n\t\tt.Errorf(\"vint should be 5: %#v\", result.Vint)\n\t}\n}\n\nfunc TestDecode_Nil(t *testing.T) {\n\tt.Parallel()\n\n\tvar input any\n\tresult := Basic{\n\t\tVstring: \"foo\",\n\t}\n\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tif result.Vstring != \"foo\" {\n\t\tt.Fatalf(\"bad: %#v\", result.Vstring)\n\t}\n}\n\nfunc TestDecode_NilInterfaceHook(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"w\": \"\",\n\t}\n\n\tdecodeHook := func(f, t reflect.Type, v any) (any, error) {\n\t\tif t.String() == \"io.Writer\" {\n\t\t\treturn nil, nil\n\t\t}\n\n\t\treturn v, nil\n\t}\n\n\tvar result NilInterface\n\tconfig := &DecoderConfig{\n\t\tDecodeHook: decodeHook,\n\t\tResult:     &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif result.W != nil {\n\t\tt.Errorf(\"W should be nil: %#v\", result.W)\n\t}\n}\n\nfunc TestDecode_NilPointerHook(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"value\": \"\",\n\t}\n\n\tdecodeHook := func(f, t reflect.Type, v any) (any, error) {\n\t\tif typed, ok := v.(string); ok {\n\t\t\tif typed == \"\" {\n\t\t\t\treturn nil, nil\n\t\t\t}\n\t\t}\n\t\treturn v, nil\n\t}\n\n\tvar result NilPointer\n\tconfig := &DecoderConfig{\n\t\tDecodeHook: decodeHook,\n\t\tResult:     &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif result.Value != nil {\n\t\tt.Errorf(\"W should be nil: %#v\", result.Value)\n\t}\n}\n\nfunc TestDecode_FuncHook(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"foo\": \"baz\",\n\t}\n\n\tdecodeHook := func(f, t reflect.Type, v any) (any, error) {\n\t\tif t.Kind() != reflect.Func {\n\t\t\treturn v, nil\n\t\t}\n\t\tval := v.(string)\n\t\treturn func() string { return val }, nil\n\t}\n\n\tvar result Func\n\tconfig := &DecoderConfig{\n\t\tDecodeHook: decodeHook,\n\t\tResult:     &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif result.Foo() != \"baz\" {\n\t\tt.Errorf(\"Foo call result should be 'baz': %s\", result.Foo())\n\t}\n}\n\nfunc TestDecode_NonStruct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"foo\": \"bar\",\n\t\t\"bar\": \"baz\",\n\t}\n\n\tvar result map[string]string\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tif result[\"foo\"] != \"bar\" {\n\t\tt.Fatal(\"foo is not bar\")\n\t}\n}\n\nfunc TestDecode_StructMatch(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vbar\": Basic{\n\t\t\tVstring: \"foo\",\n\t\t},\n\t}\n\n\tvar result Nested\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vbar.Vstring != \"foo\" {\n\t\tt.Errorf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestDecode_TypeConversion(t *testing.T) {\n\tinput := map[string]any{\n\t\t\"IntToFloat\":         42,\n\t\t\"IntToUint\":          42,\n\t\t\"IntToBool\":          1,\n\t\t\"IntToString\":        42,\n\t\t\"UintToInt\":          42,\n\t\t\"UintToFloat\":        42,\n\t\t\"UintToBool\":         42,\n\t\t\"UintToString\":       42,\n\t\t\"BoolToInt\":          true,\n\t\t\"BoolToUint\":         true,\n\t\t\"BoolToFloat\":        true,\n\t\t\"BoolToString\":       true,\n\t\t\"FloatToInt\":         42.42,\n\t\t\"FloatToUint\":        42.42,\n\t\t\"FloatToBool\":        42.42,\n\t\t\"FloatToString\":      42.42,\n\t\t\"SliceUint8ToString\": []uint8(\"foo\"),\n\t\t\"StringToSliceUint8\": \"foo\",\n\t\t\"ArrayUint8ToString\": [3]uint8{'f', 'o', 'o'},\n\t\t\"StringToInt\":        \"42\",\n\t\t\"StringToUint\":       \"42\",\n\t\t\"StringToBool\":       \"1\",\n\t\t\"StringToFloat\":      \"42.42\",\n\t\t\"StringToStrSlice\":   \"A\",\n\t\t\"StringToIntSlice\":   \"42\",\n\t\t\"StringToStrArray\":   \"A\",\n\t\t\"StringToIntArray\":   \"42\",\n\t\t\"SliceToMap\":         []any{},\n\t\t\"MapToSlice\":         map[string]any{},\n\t\t\"ArrayToMap\":         []any{},\n\t\t\"MapToArray\":         map[string]any{},\n\t}\n\n\texpectedResultStrict := TypeConversionResult{\n\t\tIntToFloat:  42.0,\n\t\tIntToUint:   42,\n\t\tUintToInt:   42,\n\t\tUintToFloat: 42,\n\t\tBoolToInt:   0,\n\t\tBoolToUint:  0,\n\t\tBoolToFloat: 0,\n\t\tFloatToInt:  42,\n\t\tFloatToUint: 42,\n\t}\n\n\texpectedResultWeak := TypeConversionResult{\n\t\tIntToFloat:         42.0,\n\t\tIntToUint:          42,\n\t\tIntToBool:          true,\n\t\tIntToString:        \"42\",\n\t\tUintToInt:          42,\n\t\tUintToFloat:        42,\n\t\tUintToBool:         true,\n\t\tUintToString:       \"42\",\n\t\tBoolToInt:          1,\n\t\tBoolToUint:         1,\n\t\tBoolToFloat:        1,\n\t\tBoolToString:       \"1\",\n\t\tFloatToInt:         42,\n\t\tFloatToUint:        42,\n\t\tFloatToBool:        true,\n\t\tFloatToString:      \"42.42\",\n\t\tSliceUint8ToString: \"foo\",\n\t\tStringToSliceUint8: []byte(\"foo\"),\n\t\tArrayUint8ToString: \"foo\",\n\t\tStringToInt:        42,\n\t\tStringToUint:       42,\n\t\tStringToBool:       true,\n\t\tStringToFloat:      42.42,\n\t\tStringToStrSlice:   []string{\"A\"},\n\t\tStringToIntSlice:   []int{42},\n\t\tStringToStrArray:   [1]string{\"A\"},\n\t\tStringToIntArray:   [1]int{42},\n\t\tSliceToMap:         map[string]any{},\n\t\tMapToSlice:         []any{},\n\t\tArrayToMap:         map[string]any{},\n\t\tMapToArray:         [1]any{},\n\t}\n\n\t// Test strict type conversion\n\tvar resultStrict TypeConversionResult\n\terr := Decode(input, &resultStrict)\n\tif err == nil {\n\t\tt.Errorf(\"should return an error\")\n\t}\n\tif !reflect.DeepEqual(resultStrict, expectedResultStrict) {\n\t\tt.Errorf(\"expected %v, got: %v\", expectedResultStrict, resultStrict)\n\t}\n\n\t// Test weak type conversion\n\tvar decoder *Decoder\n\tvar resultWeak TypeConversionResult\n\n\tconfig := &DecoderConfig{\n\t\tWeaklyTypedInput: true,\n\t\tResult:           &resultWeak,\n\t}\n\n\tdecoder, err = NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif !reflect.DeepEqual(resultWeak, expectedResultWeak) {\n\t\tt.Errorf(\"expected \\n%#v, got: \\n%#v\", expectedResultWeak, resultWeak)\n\t}\n}\n\nfunc TestDecoder_ErrorUnused(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"hello\",\n\t\t\"foo\":     \"bar\",\n\t}\n\n\tvar result Basic\n\tconfig := &DecoderConfig{\n\t\tErrorUnused: true,\n\t\tResult:      &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err == nil {\n\t\tt.Fatal(\"expected error\")\n\t}\n}\n\nfunc TestDecoder_ErrorUnused_NotSetable(t *testing.T) {\n\tt.Parallel()\n\n\t// lowercase vsilent is unexported and cannot be set\n\tinput := map[string]any{\n\t\t\"vsilent\": \"false\",\n\t}\n\n\tvar result Basic\n\tconfig := &DecoderConfig{\n\t\tErrorUnused: true,\n\t\tResult:      &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err == nil {\n\t\tt.Fatal(\"expected error\")\n\t}\n}\n\nfunc TestDecoder_ErrorUnset(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"hello\",\n\t\t\"foo\":     \"bar\",\n\t}\n\n\tvar result Basic\n\tconfig := &DecoderConfig{\n\t\tErrorUnset: true,\n\t\tResult:     &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err == nil {\n\t\tt.Fatal(\"expected error\")\n\t}\n}\n\nfunc TestDecoder_ErrorUnset_AllowUnsetPointer(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"hello\",\n\t\t\"foo\":     \"bar\",\n\t}\n\n\tvar result BasicPointer\n\tconfig := &DecoderConfig{\n\t\tErrorUnset:        true,\n\t\tAllowUnsetPointer: true,\n\t\tResult:            &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatal(\"error not expected\")\n\t}\n}\n\nfunc TestMap(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vother\": map[any]any{\n\t\t\t\"foo\": \"foo\",\n\t\t\t\"bar\": \"bar\",\n\t\t},\n\t}\n\n\tvar result Map\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an error: %s\", err)\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\tif result.Vother == nil {\n\t\tt.Fatal(\"vother should not be nil\")\n\t}\n\n\tif len(result.Vother) != 2 {\n\t\tt.Error(\"vother should have two items\")\n\t}\n\n\tif result.Vother[\"foo\"] != \"foo\" {\n\t\tt.Errorf(\"'foo' key should be foo, got: %#v\", result.Vother[\"foo\"])\n\t}\n\n\tif result.Vother[\"bar\"] != \"bar\" {\n\t\tt.Errorf(\"'bar' key should be bar, got: %#v\", result.Vother[\"bar\"])\n\t}\n}\n\nfunc TestMapMerge(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vother\": map[any]any{\n\t\t\t\"foo\": \"foo\",\n\t\t\t\"bar\": \"bar\",\n\t\t},\n\t}\n\n\tvar result Map\n\tresult.Vother = map[string]string{\"hello\": \"world\"}\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an error: %s\", err)\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\texpected := map[string]string{\n\t\t\"foo\":   \"foo\",\n\t\t\"bar\":   \"bar\",\n\t\t\"hello\": \"world\",\n\t}\n\tif !reflect.DeepEqual(result.Vother, expected) {\n\t\tt.Errorf(\"bad: %#v\", result.Vother)\n\t}\n}\n\nfunc TestMapOfStruct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"value\": map[string]any{\n\t\t\t\"foo\": map[string]string{\"vstring\": \"one\"},\n\t\t\t\"bar\": map[string]string{\"vstring\": \"two\"},\n\t\t},\n\t}\n\n\tvar result MapOfStruct\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\n\tif result.Value == nil {\n\t\tt.Fatal(\"value should not be nil\")\n\t}\n\n\tif len(result.Value) != 2 {\n\t\tt.Error(\"value should have two items\")\n\t}\n\n\tif result.Value[\"foo\"].Vstring != \"one\" {\n\t\tt.Errorf(\"foo value should be 'one', got: %s\", result.Value[\"foo\"].Vstring)\n\t}\n\n\tif result.Value[\"bar\"].Vstring != \"two\" {\n\t\tt.Errorf(\"bar value should be 'two', got: %s\", result.Value[\"bar\"].Vstring)\n\t}\n}\n\nfunc TestNestedType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t\t\"vint\":    42,\n\t\t\t\"vbool\":   true,\n\t\t},\n\t}\n\n\tvar result Nested\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\tif result.Vbar.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vbar.Vstring)\n\t}\n\n\tif result.Vbar.Vint != 42 {\n\t\tt.Errorf(\"vint value should be 42: %#v\", result.Vbar.Vint)\n\t}\n\n\tif result.Vbar.Vbool != true {\n\t\tt.Errorf(\"vbool value should be true: %#v\", result.Vbar.Vbool)\n\t}\n\n\tif result.Vbar.Vextra != \"\" {\n\t\tt.Errorf(\"vextra value should be empty: %#v\", result.Vbar.Vextra)\n\t}\n}\n\nfunc TestNestedTypePointer(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": &map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t\t\"vint\":    42,\n\t\t\t\"vbool\":   true,\n\t\t},\n\t}\n\n\tvar result NestedPointer\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\tif result.Vbar.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vbar.Vstring)\n\t}\n\n\tif result.Vbar.Vint != 42 {\n\t\tt.Errorf(\"vint value should be 42: %#v\", result.Vbar.Vint)\n\t}\n\n\tif result.Vbar.Vbool != true {\n\t\tt.Errorf(\"vbool value should be true: %#v\", result.Vbar.Vbool)\n\t}\n\n\tif result.Vbar.Vextra != \"\" {\n\t\tt.Errorf(\"vextra value should be empty: %#v\", result.Vbar.Vextra)\n\t}\n}\n\n// Test for issue #46.\nfunc TestNestedTypeInterface(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": &map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t\t\"vint\":    42,\n\t\t\t\"vbool\":   true,\n\n\t\t\t\"vdata\": map[string]any{\n\t\t\t\t\"vstring\": \"bar\",\n\t\t\t},\n\t\t},\n\t}\n\n\tvar result NestedPointer\n\tresult.Vbar = new(Basic)\n\tresult.Vbar.Vdata = new(Basic)\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err.Error())\n\t}\n\n\tif result.Vfoo != \"foo\" {\n\t\tt.Errorf(\"vfoo value should be 'foo': %#v\", result.Vfoo)\n\t}\n\n\tif result.Vbar.Vstring != \"foo\" {\n\t\tt.Errorf(\"vstring value should be 'foo': %#v\", result.Vbar.Vstring)\n\t}\n\n\tif result.Vbar.Vint != 42 {\n\t\tt.Errorf(\"vint value should be 42: %#v\", result.Vbar.Vint)\n\t}\n\n\tif result.Vbar.Vbool != true {\n\t\tt.Errorf(\"vbool value should be true: %#v\", result.Vbar.Vbool)\n\t}\n\n\tif result.Vbar.Vextra != \"\" {\n\t\tt.Errorf(\"vextra value should be empty: %#v\", result.Vbar.Vextra)\n\t}\n\n\tif result.Vbar.Vdata.(*Basic).Vstring != \"bar\" {\n\t\tt.Errorf(\"vstring value should be 'bar': %#v\", result.Vbar.Vdata.(*Basic).Vstring)\n\t}\n}\n\nfunc TestSlice(t *testing.T) {\n\tt.Parallel()\n\n\tinputStringSlice := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": []string{\"foo\", \"bar\", \"baz\"},\n\t}\n\n\tinputStringSlicePointer := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": &[]string{\"foo\", \"bar\", \"baz\"},\n\t}\n\n\toutputStringSlice := &Slice{\n\t\t\"foo\",\n\t\t[]string{\"foo\", \"bar\", \"baz\"},\n\t}\n\n\ttestSliceInput(t, inputStringSlice, outputStringSlice)\n\ttestSliceInput(t, inputStringSlicePointer, outputStringSlice)\n}\n\nfunc TestNotEmptyByteSlice(t *testing.T) {\n\tt.Parallel()\n\n\tinputByteSlice := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": []byte(`{\"bar\": \"bar\"}`),\n\t}\n\n\tresult := SliceOfByte{\n\t\tVfoo: \"another foo\",\n\t\tVbar: []byte(`{\"bar\": \"bar bar bar bar bar bar bar bar\"}`),\n\t}\n\n\terr := Decode(inputByteSlice, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got unexpected error: %s\", err)\n\t}\n\n\texpected := SliceOfByte{\n\t\tVfoo: \"foo\",\n\t\tVbar: []byte(`{\"bar\": \"bar\"}`),\n\t}\n\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Errorf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestInvalidSlice(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": 42,\n\t}\n\n\tresult := Slice{}\n\terr := Decode(input, &result)\n\tif err == nil {\n\t\tt.Errorf(\"expected failure\")\n\t}\n}\n\nfunc TestSliceOfStruct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"value\": []map[string]any{\n\t\t\t{\"vstring\": \"one\"},\n\t\t\t{\"vstring\": \"two\"},\n\t\t},\n\t}\n\n\tvar result SliceOfStruct\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got unexpected error: %s\", err)\n\t}\n\n\tif len(result.Value) != 2 {\n\t\tt.Fatalf(\"expected two values, got %d\", len(result.Value))\n\t}\n\n\tif result.Value[0].Vstring != \"one\" {\n\t\tt.Errorf(\"first value should be 'one', got: %s\", result.Value[0].Vstring)\n\t}\n\n\tif result.Value[1].Vstring != \"two\" {\n\t\tt.Errorf(\"second value should be 'two', got: %s\", result.Value[1].Vstring)\n\t}\n}\n\nfunc TestSliceCornerCases(t *testing.T) {\n\tt.Parallel()\n\n\t// Input with a map with zero values\n\tinput := map[string]any{}\n\tvar resultWeak []Basic\n\n\terr := WeakDecode(input, &resultWeak)\n\tif err != nil {\n\t\tt.Fatalf(\"got unexpected error: %s\", err)\n\t}\n\n\tif len(resultWeak) != 0 {\n\t\tt.Errorf(\"length should be 0\")\n\t}\n\t// Input with more values\n\tinput = map[string]any{\n\t\t\"Vstring\": \"foo\",\n\t}\n\n\tresultWeak = nil\n\terr = WeakDecode(input, &resultWeak)\n\tif err != nil {\n\t\tt.Fatalf(\"got unexpected error: %s\", err)\n\t}\n\n\tif resultWeak[0].Vstring != \"foo\" {\n\t\tt.Errorf(\"value does not match\")\n\t}\n}\n\nfunc TestSliceToMap(t *testing.T) {\n\tt.Parallel()\n\n\tinput := []map[string]any{\n\t\t{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\t{\n\t\t\t\"bar\": \"baz\",\n\t\t},\n\t}\n\n\tvar result map[string]any\n\terr := WeakDecode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an error: %s\", err)\n\t}\n\n\texpected := map[string]any{\n\t\t\"foo\": \"bar\",\n\t\t\"bar\": \"baz\",\n\t}\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Errorf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestArray(t *testing.T) {\n\tt.Parallel()\n\n\tinputStringArray := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": [2]string{\"foo\", \"bar\"},\n\t}\n\n\tinputStringArrayPointer := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": &[2]string{\"foo\", \"bar\"},\n\t}\n\n\toutputStringArray := &Array{\n\t\t\"foo\",\n\t\t[2]string{\"foo\", \"bar\"},\n\t}\n\n\ttestArrayInput(t, inputStringArray, outputStringArray)\n\ttestArrayInput(t, inputStringArrayPointer, outputStringArray)\n}\n\nfunc TestInvalidArray(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": 42,\n\t}\n\n\tresult := Array{}\n\terr := Decode(input, &result)\n\tif err == nil {\n\t\tt.Errorf(\"expected failure\")\n\t}\n}\n\nfunc TestArrayOfStruct(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"value\": []map[string]any{\n\t\t\t{\"vstring\": \"one\"},\n\t\t\t{\"vstring\": \"two\"},\n\t\t},\n\t}\n\n\tvar result ArrayOfStruct\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got unexpected error: %s\", err)\n\t}\n\n\tif len(result.Value) != 2 {\n\t\tt.Fatalf(\"expected two values, got %d\", len(result.Value))\n\t}\n\n\tif result.Value[0].Vstring != \"one\" {\n\t\tt.Errorf(\"first value should be 'one', got: %s\", result.Value[0].Vstring)\n\t}\n\n\tif result.Value[1].Vstring != \"two\" {\n\t\tt.Errorf(\"second value should be 'two', got: %s\", result.Value[1].Vstring)\n\t}\n}\n\nfunc TestArrayToMap(t *testing.T) {\n\tt.Parallel()\n\n\tinput := []map[string]any{\n\t\t{\n\t\t\t\"foo\": \"bar\",\n\t\t},\n\t\t{\n\t\t\t\"bar\": \"baz\",\n\t\t},\n\t}\n\n\tvar result map[string]any\n\terr := WeakDecode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got an error: %s\", err)\n\t}\n\n\texpected := map[string]any{\n\t\t\"foo\": \"bar\",\n\t\t\"bar\": \"baz\",\n\t}\n\tif !reflect.DeepEqual(result, expected) {\n\t\tt.Errorf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestDecodeTable(t *testing.T) {\n\tt.Parallel()\n\n\t// We need to make new types so that we don't get the short-circuit\n\t// copy functionality. We want to test the deep copying functionality.\n\ttype BasicCopy Basic\n\ttype NestedPointerCopy NestedPointer\n\ttype MapCopy Map\n\n\ttests := []struct {\n\t\tname    string\n\t\tin      any\n\t\ttarget  any\n\t\tout     any\n\t\twantErr bool\n\t}{\n\t\t{\n\t\t\t\"basic struct input\",\n\t\t\t&Basic{\n\t\t\t\tVstring: \"vstring\",\n\t\t\t\tVint:    2,\n\t\t\t\tVint8:   2,\n\t\t\t\tVint16:  2,\n\t\t\t\tVint32:  2,\n\t\t\t\tVint64:  2,\n\t\t\t\tVuint:   3,\n\t\t\t\tVbool:   true,\n\t\t\t\tVfloat:  4.56,\n\t\t\t\tVextra:  \"vextra\",\n\t\t\t\tvsilent: true,\n\t\t\t\tVdata:   []byte(\"data\"),\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\n\t\t\t\t\"Vstring\":     \"vstring\",\n\t\t\t\t\"Vint\":        2,\n\t\t\t\t\"Vint8\":       int8(2),\n\t\t\t\t\"Vint16\":      int16(2),\n\t\t\t\t\"Vint32\":      int32(2),\n\t\t\t\t\"Vint64\":      int64(2),\n\t\t\t\t\"Vuint\":       uint(3),\n\t\t\t\t\"Vbool\":       true,\n\t\t\t\t\"Vfloat\":      4.56,\n\t\t\t\t\"Vextra\":      \"vextra\",\n\t\t\t\t\"Vdata\":       []byte(\"data\"),\n\t\t\t\t\"VjsonInt\":    0,\n\t\t\t\t\"VjsonUint\":   uint(0),\n\t\t\t\t\"VjsonUint64\": uint64(0),\n\t\t\t\t\"VjsonFloat\":  0.0,\n\t\t\t\t\"VjsonNumber\": json.Number(\"\"),\n\t\t\t\t\"Vcomplex64\":  complex64(0),\n\t\t\t\t\"Vcomplex128\": complex128(0),\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"embedded struct input\",\n\t\t\t&Embedded{\n\t\t\t\tVunique: \"vunique\",\n\t\t\t\tBasic: Basic{\n\t\t\t\t\tVstring: \"vstring\",\n\t\t\t\t\tVint:    2,\n\t\t\t\t\tVint8:   2,\n\t\t\t\t\tVint16:  2,\n\t\t\t\t\tVint32:  2,\n\t\t\t\t\tVint64:  2,\n\t\t\t\t\tVuint:   3,\n\t\t\t\t\tVbool:   true,\n\t\t\t\t\tVfloat:  4.56,\n\t\t\t\t\tVextra:  \"vextra\",\n\t\t\t\t\tvsilent: true,\n\t\t\t\t\tVdata:   []byte(\"data\"),\n\t\t\t\t},\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\n\t\t\t\t\"Vunique\": \"vunique\",\n\t\t\t\t\"Basic\": map[string]any{\n\t\t\t\t\t\"Vstring\":     \"vstring\",\n\t\t\t\t\t\"Vint\":        2,\n\t\t\t\t\t\"Vint8\":       int8(2),\n\t\t\t\t\t\"Vint16\":      int16(2),\n\t\t\t\t\t\"Vint32\":      int32(2),\n\t\t\t\t\t\"Vint64\":      int64(2),\n\t\t\t\t\t\"Vuint\":       uint(3),\n\t\t\t\t\t\"Vbool\":       true,\n\t\t\t\t\t\"Vfloat\":      4.56,\n\t\t\t\t\t\"Vextra\":      \"vextra\",\n\t\t\t\t\t\"Vdata\":       []byte(\"data\"),\n\t\t\t\t\t\"VjsonInt\":    0,\n\t\t\t\t\t\"VjsonUint\":   uint(0),\n\t\t\t\t\t\"VjsonUint64\": uint64(0),\n\t\t\t\t\t\"VjsonFloat\":  0.0,\n\t\t\t\t\t\"VjsonNumber\": json.Number(\"\"),\n\t\t\t\t\t\"Vcomplex64\":  complex64(0),\n\t\t\t\t\t\"Vcomplex128\": complex128(0),\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"struct => struct\",\n\t\t\t&Basic{\n\t\t\t\tVstring: \"vstring\",\n\t\t\t\tVint:    2,\n\t\t\t\tVuint:   3,\n\t\t\t\tVbool:   true,\n\t\t\t\tVfloat:  4.56,\n\t\t\t\tVextra:  \"vextra\",\n\t\t\t\tVdata:   []byte(\"data\"),\n\t\t\t\tvsilent: true,\n\t\t\t},\n\t\t\t&BasicCopy{},\n\t\t\t&BasicCopy{\n\t\t\t\tVstring: \"vstring\",\n\t\t\t\tVint:    2,\n\t\t\t\tVuint:   3,\n\t\t\t\tVbool:   true,\n\t\t\t\tVfloat:  4.56,\n\t\t\t\tVextra:  \"vextra\",\n\t\t\t\tVdata:   []byte(\"data\"),\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"struct => struct with pointers\",\n\t\t\t&NestedPointer{\n\t\t\t\tVfoo: \"hello\",\n\t\t\t\tVbar: nil,\n\t\t\t},\n\t\t\t&NestedPointerCopy{},\n\t\t\t&NestedPointerCopy{\n\t\t\t\tVfoo: \"hello\",\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"basic pointer to non-pointer\",\n\t\t\t&BasicPointer{\n\t\t\t\tVstring: stringPtr(\"vstring\"),\n\t\t\t\tVint:    intPtr(2),\n\t\t\t\tVuint:   uintPtr(3),\n\t\t\t\tVbool:   boolPtr(true),\n\t\t\t\tVfloat:  floatPtr(4.56),\n\t\t\t\tVdata:   interfacePtr([]byte(\"data\")),\n\t\t\t},\n\t\t\t&Basic{},\n\t\t\t&Basic{\n\t\t\t\tVstring: \"vstring\",\n\t\t\t\tVint:    2,\n\t\t\t\tVuint:   3,\n\t\t\t\tVbool:   true,\n\t\t\t\tVfloat:  4.56,\n\t\t\t\tVdata:   []byte(\"data\"),\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"slice non-pointer to pointer\",\n\t\t\t&Slice{},\n\t\t\t&SlicePointer{},\n\t\t\t&SlicePointer{},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"slice non-pointer to pointer, zero field\",\n\t\t\t&Slice{},\n\t\t\t&SlicePointer{\n\t\t\t\tVbar: &[]string{\"yo\"},\n\t\t\t},\n\t\t\t&SlicePointer{},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"slice to slice alias\",\n\t\t\t&Slice{},\n\t\t\t&SliceOfAlias{},\n\t\t\t&SliceOfAlias{},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"nil map to map\",\n\t\t\t&Map{},\n\t\t\t&MapCopy{},\n\t\t\t&MapCopy{},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"nil map to non-empty map\",\n\t\t\t&Map{},\n\t\t\t&MapCopy{Vother: map[string]string{\"foo\": \"bar\"}},\n\t\t\t&MapCopy{},\n\t\t\tfalse,\n\t\t},\n\n\t\t{\n\t\t\t\"slice input - should error\",\n\t\t\t[]string{\"foo\", \"bar\"},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{},\n\t\t\ttrue,\n\t\t},\n\t\t{\n\t\t\t\"struct with slice property\",\n\t\t\t&Slice{\n\t\t\t\tVfoo: \"vfoo\",\n\t\t\t\tVbar: []string{\"foo\", \"bar\"},\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\n\t\t\t\t\"Vfoo\": \"vfoo\",\n\t\t\t\t\"Vbar\": []string{\"foo\", \"bar\"},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"struct with empty slice\",\n\t\t\t&map[string]any{\n\t\t\t\t\"Vbar\": []string{},\n\t\t\t},\n\t\t\t&Slice{},\n\t\t\t&Slice{\n\t\t\t\tVbar: []string{},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"struct with slice of struct property\",\n\t\t\t&SliceOfStruct{\n\t\t\t\tValue: []Basic{\n\t\t\t\t\t{\n\t\t\t\t\t\tVstring: \"vstring\",\n\t\t\t\t\t\tVint:    2,\n\t\t\t\t\t\tVuint:   3,\n\t\t\t\t\t\tVbool:   true,\n\t\t\t\t\t\tVfloat:  4.56,\n\t\t\t\t\t\tVextra:  \"vextra\",\n\t\t\t\t\t\tvsilent: true,\n\t\t\t\t\t\tVdata:   []byte(\"data\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\n\t\t\t\t\"Value\": []Basic{\n\t\t\t\t\t{\n\t\t\t\t\t\tVstring: \"vstring\",\n\t\t\t\t\t\tVint:    2,\n\t\t\t\t\t\tVuint:   3,\n\t\t\t\t\t\tVbool:   true,\n\t\t\t\t\t\tVfloat:  4.56,\n\t\t\t\t\t\tVextra:  \"vextra\",\n\t\t\t\t\t\tvsilent: true,\n\t\t\t\t\t\tVdata:   []byte(\"data\"),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"struct with map property\",\n\t\t\t&Map{\n\t\t\t\tVfoo:   \"vfoo\",\n\t\t\t\tVother: map[string]string{\"vother\": \"vother\"},\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\n\t\t\t\t\"Vfoo\": \"vfoo\",\n\t\t\t\t\"Vother\": map[string]string{\n\t\t\t\t\t\"vother\": \"vother\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"tagged struct\",\n\t\t\t&Tagged{\n\t\t\t\tExtra: \"extra\",\n\t\t\t\tValue: \"value\",\n\t\t\t},\n\t\t\t&map[string]string{},\n\t\t\t&map[string]string{\n\t\t\t\t\"bar\": \"extra\",\n\t\t\t\t\"foo\": \"value\",\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"omit tag struct\",\n\t\t\t&struct {\n\t\t\t\tValue string `mapstructure:\"value\"`\n\t\t\t\tOmit  string `mapstructure:\"-\"`\n\t\t\t}{\n\t\t\t\tValue: \"value\",\n\t\t\t\tOmit:  \"omit\",\n\t\t\t},\n\t\t\t&map[string]string{},\n\t\t\t&map[string]string{\n\t\t\t\t\"value\": \"value\",\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"decode to wrong map type\",\n\t\t\t&struct {\n\t\t\t\tValue string\n\t\t\t}{\n\t\t\t\tValue: \"string\",\n\t\t\t},\n\t\t\t&map[string]int{},\n\t\t\t&map[string]int{},\n\t\t\ttrue,\n\t\t},\n\t\t{\n\t\t\t\"remainder\",\n\t\t\tmap[string]any{\n\t\t\t\t\"A\": \"hello\",\n\t\t\t\t\"B\": \"goodbye\",\n\t\t\t\t\"C\": \"yo\",\n\t\t\t},\n\t\t\t&Remainder{},\n\t\t\t&Remainder{\n\t\t\t\tA: \"hello\",\n\t\t\t\tExtra: map[string]any{\n\t\t\t\t\t\"B\": \"goodbye\",\n\t\t\t\t\t\"C\": \"yo\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"remainder with no extra\",\n\t\t\tmap[string]any{\n\t\t\t\t\"A\": \"hello\",\n\t\t\t},\n\t\t\t&Remainder{},\n\t\t\t&Remainder{\n\t\t\t\tA:     \"hello\",\n\t\t\t\tExtra: nil,\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"struct with omitempty tag return non-empty values\",\n\t\t\t&struct {\n\t\t\t\tVisibleField any `mapstructure:\"visible\"`\n\t\t\t\tOmitField    any `mapstructure:\"omittable,omitempty\"`\n\t\t\t}{\n\t\t\t\tVisibleField: nil,\n\t\t\t\tOmitField:    \"string\",\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\"visible\": nil, \"omittable\": \"string\"},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"struct with omitempty tag ignore empty values\",\n\t\t\t&struct {\n\t\t\t\tVisibleField any `mapstructure:\"visible\"`\n\t\t\t\tOmitField    any `mapstructure:\"omittable,omitempty\"`\n\t\t\t}{\n\t\t\t\tVisibleField: nil,\n\t\t\t\tOmitField:    nil,\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\"visible\": nil},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"remainder with decode to map\",\n\t\t\t&Remainder{\n\t\t\t\tA: \"Alabasta\",\n\t\t\t\tExtra: map[string]any{\n\t\t\t\t\t\"B\": \"Baratie\",\n\t\t\t\t\t\"C\": \"Cocoyasi\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\n\t\t\t\t\"A\": \"Alabasta\",\n\t\t\t\t\"B\": \"Baratie\",\n\t\t\t\t\"C\": \"Cocoyasi\",\n\t\t\t},\n\t\t\tfalse,\n\t\t},\n\t\t{\n\t\t\t\"remainder with decode to map with non-map field\",\n\t\t\t&struct {\n\t\t\t\tA     string\n\t\t\t\tExtra *struct{} `mapstructure:\",remain\"`\n\t\t\t}{\n\t\t\t\tA:     \"Alabasta\",\n\t\t\t\tExtra: nil,\n\t\t\t},\n\t\t\t&map[string]any{},\n\t\t\t&map[string]any{\n\t\t\t\t\"A\": \"Alabasta\",\n\t\t\t},\n\t\t\ttrue,\n\t\t},\n\t}\n\n\tfor _, tt := range tests {\n\t\tt.Run(tt.name, func(t *testing.T) {\n\t\t\tif err := Decode(tt.in, tt.target); (err != nil) != tt.wantErr {\n\t\t\t\tt.Fatalf(\"%q: TestMapOutputForStructuredInputs() unexpected error: %s\", tt.name, err)\n\t\t\t}\n\n\t\t\tif !reflect.DeepEqual(tt.out, tt.target) {\n\t\t\t\tt.Fatalf(\"%q: TestMapOutputForStructuredInputs() expected: %#v, got: %#v\", tt.name, tt.out, tt.target)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestInvalidType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": 42,\n\t}\n\n\tvar result Basic\n\terr := Decode(input, &result)\n\tif err == nil {\n\t\tt.Fatal(\"error should exist\")\n\t}\n\n\tvar derr interface {\n\t\tUnwrap() []error\n\t}\n\n\tif !errors.As(err, &derr) {\n\t\tt.Fatalf(\"error should be a type implementing Unwrap() []error, instead: %#v\", err)\n\t}\n\n\terrs := derr.Unwrap()\n\n\tvar decoderErr *DecodeError\n\tif !errors.As(errs[0], &decoderErr) {\n\t\tt.Errorf(\"got unexpected error: %s\", err)\n\t} else if errors.Is(decoderErr.Unwrap(), &UnconvertibleTypeError{}) {\n\t\tt.Errorf(\"error should be UnconvertibleTypeError, got: %s\", decoderErr.Unwrap())\n\t}\n\n\tinputNegIntUint := map[string]any{\n\t\t\"vuint\": -42,\n\t}\n\n\terr = Decode(inputNegIntUint, &result)\n\tif err == nil {\n\t\tt.Fatal(\"error should exist\")\n\t}\n\n\tif !errors.As(err, &derr) {\n\t\tt.Fatalf(\"error should be a type implementing Unwrap() []error, instead: %#v\", err)\n\t}\n\n\terrs = derr.Unwrap()\n\n\tif !errors.As(errs[0], &decoderErr) {\n\t\tt.Errorf(\"got unexpected error: %s\", err)\n\t} else if errors.Is(decoderErr.Unwrap(), &ParseError{}) {\n\t\tt.Errorf(\"error should be ParseError, got: %s\", decoderErr.Unwrap())\n\t}\n\n\tinputNegFloatUint := map[string]any{\n\t\t\"vuint\": -42.0,\n\t}\n\n\terr = Decode(inputNegFloatUint, &result)\n\tif err == nil {\n\t\tt.Fatal(\"error should exist\")\n\t}\n\n\tif !errors.As(err, &derr) {\n\t\tt.Fatalf(\"error should be a type implementing Unwrap() []error, instead: %#v\", err)\n\t}\n\n\terrs = derr.Unwrap()\n\n\tif !errors.As(errs[0], &decoderErr) {\n\t\tt.Errorf(\"got unexpected error: %s\", err)\n\t}\n}\n\nfunc TestDecodeMetadata(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t\t\"Vuint\":   42,\n\t\t\t\"vsilent\": \"false\",\n\t\t\t\"foo\":     \"bar\",\n\t\t},\n\t\t\"bar\": \"nil\",\n\t}\n\n\tvar md Metadata\n\tvar result Nested\n\n\terr := DecodeMetadata(input, &result, &md)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err.Error())\n\t}\n\n\texpectedKeys := []string{\"Vbar\", \"Vbar.Vstring\", \"Vbar.Vuint\", \"Vfoo\"}\n\tsort.Strings(md.Keys)\n\tif !reflect.DeepEqual(md.Keys, expectedKeys) {\n\t\tt.Fatalf(\"bad keys: %#v\", md.Keys)\n\t}\n\n\texpectedUnused := []string{\"Vbar.foo\", \"Vbar.vsilent\", \"bar\"}\n\tsort.Strings(md.Unused)\n\tif !reflect.DeepEqual(md.Unused, expectedUnused) {\n\t\tt.Fatalf(\"bad unused: %#v\", md.Unused)\n\t}\n}\n\nfunc TestMetadata(t *testing.T) {\n\tt.Parallel()\n\n\ttype testResult struct {\n\t\tVfoo string\n\t\tVbar BasicPointer\n\t}\n\n\tinput := map[string]any{\n\t\t\"vfoo\": \"foo\",\n\t\t\"vbar\": map[string]any{\n\t\t\t\"vstring\": \"foo\",\n\t\t\t\"Vuint\":   42,\n\t\t\t\"vsilent\": \"false\",\n\t\t\t\"foo\":     \"bar\",\n\t\t},\n\t\t\"bar\": \"nil\",\n\t}\n\n\tvar md Metadata\n\tvar result testResult\n\tconfig := &DecoderConfig{\n\t\tMetadata: &md,\n\t\tResult:   &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err.Error())\n\t}\n\n\texpectedKeys := []string{\"Vbar\", \"Vbar.Vstring\", \"Vbar.Vuint\", \"Vfoo\"}\n\tsort.Strings(md.Keys)\n\tif !reflect.DeepEqual(md.Keys, expectedKeys) {\n\t\tt.Fatalf(\"bad keys: %#v\", md.Keys)\n\t}\n\n\texpectedUnused := []string{\"Vbar.foo\", \"Vbar.vsilent\", \"bar\"}\n\tsort.Strings(md.Unused)\n\tif !reflect.DeepEqual(md.Unused, expectedUnused) {\n\t\tt.Fatalf(\"bad unused: %#v\", md.Unused)\n\t}\n\n\texpectedUnset := []string{\n\t\t\"Vbar.Vbool\", \"Vbar.Vdata\", \"Vbar.Vextra\", \"Vbar.Vfloat\", \"Vbar.Vint\",\n\t\t\"Vbar.VjsonFloat\", \"Vbar.VjsonInt\", \"Vbar.VjsonNumber\",\n\t}\n\tsort.Strings(md.Unset)\n\tif !reflect.DeepEqual(md.Unset, expectedUnset) {\n\t\tt.Fatalf(\"bad unset: %#v\", md.Unset)\n\t}\n}\n\nfunc TestMetadata_Embedded(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"vstring\": \"foo\",\n\t\t\"vunique\": \"bar\",\n\t}\n\n\tvar md Metadata\n\tvar result EmbeddedSquash\n\tconfig := &DecoderConfig{\n\t\tMetadata: &md,\n\t\tResult:   &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err.Error())\n\t}\n\n\texpectedKeys := []string{\"Vstring\", \"Vunique\"}\n\n\tsort.Strings(md.Keys)\n\tif !reflect.DeepEqual(md.Keys, expectedKeys) {\n\t\tt.Fatalf(\"bad keys: %#v\", md.Keys)\n\t}\n\n\texpectedUnused := []string{}\n\tif !reflect.DeepEqual(md.Unused, expectedUnused) {\n\t\tt.Fatalf(\"bad unused: %#v\", md.Unused)\n\t}\n}\n\nfunc TestNonPtrValue(t *testing.T) {\n\tt.Parallel()\n\n\terr := Decode(map[string]any{}, Basic{})\n\tif err == nil {\n\t\tt.Fatal(\"error should exist\")\n\t}\n\n\tif err.Error() != \"result must be a pointer\" {\n\t\tt.Errorf(\"got unexpected error: %s\", err)\n\t}\n}\n\nfunc TestTagged(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"foo\": \"bar\",\n\t\t\"bar\": \"value\",\n\t}\n\n\tvar result Tagged\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Value != \"bar\" {\n\t\tt.Errorf(\"value should be 'bar', got: %#v\", result.Value)\n\t}\n\n\tif result.Extra != \"value\" {\n\t\tt.Errorf(\"extra should be 'value', got: %#v\", result.Extra)\n\t}\n}\n\nfunc TestWeakDecode(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"foo\": \"4\",\n\t\t\"bar\": \"value\",\n\t}\n\n\tvar result struct {\n\t\tFoo int\n\t\tBar string\n\t}\n\n\tif err := WeakDecode(input, &result); err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\tif result.Foo != 4 {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n\tif result.Bar != \"value\" {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n}\n\nfunc TestWeakDecodeMetadata(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"foo\":        \"4\",\n\t\t\"bar\":        \"value\",\n\t\t\"unused\":     \"value\",\n\t\t\"unexported\": \"value\",\n\t}\n\n\tvar md Metadata\n\tvar result struct {\n\t\tFoo        int\n\t\tBar        string\n\t\tunexported string\n\t}\n\n\tif err := WeakDecodeMetadata(input, &result, &md); err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\tif result.Foo != 4 {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n\tif result.Bar != \"value\" {\n\t\tt.Fatalf(\"bad: %#v\", result)\n\t}\n\n\texpectedKeys := []string{\"Bar\", \"Foo\"}\n\tsort.Strings(md.Keys)\n\tif !reflect.DeepEqual(md.Keys, expectedKeys) {\n\t\tt.Fatalf(\"bad keys: %#v\", md.Keys)\n\t}\n\n\texpectedUnused := []string{\"unexported\", \"unused\"}\n\tsort.Strings(md.Unused)\n\tif !reflect.DeepEqual(md.Unused, expectedUnused) {\n\t\tt.Fatalf(\"bad unused: %#v\", md.Unused)\n\t}\n}\n\nfunc TestDecode_StructTaggedWithOmitempty_OmitEmptyValues(t *testing.T) {\n\tt.Parallel()\n\n\tinput := &StructWithOmitEmpty{}\n\n\tvar emptySlice []any\n\tvar emptyMap map[string]any\n\tvar emptyNested *Nested\n\texpected := &map[string]any{\n\t\t\"visible-string\": \"\",\n\t\t\"visible-int\":    0,\n\t\t\"visible-float\":  0.0,\n\t\t\"visible-slice\":  emptySlice,\n\t\t\"visible-map\":    emptyMap,\n\t\t\"visible-nested\": emptyNested,\n\t}\n\n\tactual := &map[string]any{}\n\tDecode(input, actual)\n\n\tif !reflect.DeepEqual(actual, expected) {\n\t\tt.Fatalf(\"Decode() expected: %#v, got: %#v\", expected, actual)\n\t}\n}\n\nfunc TestDecode_StructTaggedWithOmitempty_KeepNonEmptyValues(t *testing.T) {\n\tt.Parallel()\n\n\tinput := &StructWithOmitEmpty{\n\t\tVisibleStringField: \"\",\n\t\tOmitStringField:    \"string\",\n\t\tVisibleIntField:    0,\n\t\tOmitIntField:       1,\n\t\tVisibleFloatField:  0.0,\n\t\tOmitFloatField:     1.0,\n\t\tVisibleSliceField:  nil,\n\t\tOmitSliceField:     []any{1},\n\t\tVisibleMapField:    nil,\n\t\tOmitMapField:       map[string]any{\"k\": \"v\"},\n\t\tNestedField:        nil,\n\t\tOmitNestedField:    &Nested{},\n\t}\n\n\tvar emptySlice []any\n\tvar emptyMap map[string]any\n\tvar emptyNested *Nested\n\texpected := &map[string]any{\n\t\t\"visible-string\":   \"\",\n\t\t\"omittable-string\": \"string\",\n\t\t\"visible-int\":      0,\n\t\t\"omittable-int\":    1,\n\t\t\"visible-float\":    0.0,\n\t\t\"omittable-float\":  1.0,\n\t\t\"visible-slice\":    emptySlice,\n\t\t\"omittable-slice\":  []any{1},\n\t\t\"visible-map\":      emptyMap,\n\t\t\"omittable-map\":    map[string]any{\"k\": \"v\"},\n\t\t\"visible-nested\":   emptyNested,\n\t\t\"omittable-nested\": &Nested{},\n\t}\n\n\tactual := &map[string]any{}\n\tDecode(input, actual)\n\n\tif !reflect.DeepEqual(actual, expected) {\n\t\tt.Fatalf(\"Decode() expected: %#v, got: %#v\", expected, actual)\n\t}\n}\n\nfunc TestDecode_StructTaggedWithOmitzero_KeepNonZeroValues(t *testing.T) {\n\tt.Parallel()\n\n\tinput := &StructWithOmitZero{\n\t\tVisibleStringField: \"\",\n\t\tOmitStringField:    \"string\",\n\t\tVisibleIntField:    0,\n\t\tOmitIntField:       1,\n\t\tVisibleFloatField:  0.0,\n\t\tOmitFloatField:     1.0,\n\t\tVisibleSliceField:  nil,\n\t\tOmitSliceField:     []any{},\n\t\tVisibleMapField:    nil,\n\t\tOmitMapField:       map[string]any{},\n\t\tNestedField:        nil,\n\t\tOmitNestedField:    &Nested{},\n\t}\n\n\tvar emptySlice []any\n\tvar emptyMap map[string]any\n\tvar emptyNested *Nested\n\texpected := &map[string]any{\n\t\t\"visible-string\":   \"\",\n\t\t\"omittable-string\": \"string\",\n\t\t\"visible-int\":      0,\n\t\t\"omittable-int\":    1,\n\t\t\"visible-float\":    0.0,\n\t\t\"omittable-float\":  1.0,\n\t\t\"visible-slice\":    emptySlice,\n\t\t\"omittable-slice\":  []any{},\n\t\t\"visible-map\":      emptyMap,\n\t\t\"omittable-map\":    map[string]any{},\n\t\t\"visible-nested\":   emptyNested,\n\t\t\"omittable-nested\": &Nested{},\n\t}\n\n\tactual := &map[string]any{}\n\tDecode(input, actual)\n\n\tif !reflect.DeepEqual(actual, expected) {\n\t\tt.Fatalf(\"Decode() expected: %#v, got: %#v\", expected, actual)\n\t}\n}\n\nfunc TestDecode_StructTaggedWithOmitzero_DropZeroValues(t *testing.T) {\n\tt.Parallel()\n\n\tinput := &StructWithOmitZero{\n\t\tVisibleStringField: \"\",\n\t\tOmitStringField:    \"\",\n\t\tVisibleIntField:    0,\n\t\tOmitIntField:       0,\n\t\tVisibleFloatField:  0.0,\n\t\tOmitFloatField:     0.0,\n\t\tVisibleSliceField:  nil,\n\t\tOmitSliceField:     nil,\n\t\tVisibleMapField:    nil,\n\t\tOmitMapField:       nil,\n\t\tNestedField:        nil,\n\t\tOmitNestedField:    nil,\n\t}\n\n\tvar emptySlice []any\n\tvar emptyMap map[string]any\n\tvar emptyNested *Nested\n\texpected := &map[string]any{\n\t\t\"visible-string\": \"\",\n\t\t\"visible-int\":    0,\n\t\t\"visible-float\":  0.0,\n\t\t\"visible-slice\":  emptySlice,\n\t\t\"visible-map\":    emptyMap,\n\t\t\"visible-nested\": emptyNested,\n\t}\n\n\tactual := &map[string]any{}\n\tDecode(input, actual)\n\n\tif !reflect.DeepEqual(actual, expected) {\n\t\tt.Fatalf(\"Decode() expected: %#v, got: %#v\", expected, actual)\n\t}\n}\n\nfunc TestDecode_mapToStruct(t *testing.T) {\n\ttype Target struct {\n\t\tString    string\n\t\tStringPtr *string\n\t}\n\n\texpected := Target{\n\t\tString: \"hello\",\n\t}\n\n\tvar target Target\n\terr := Decode(map[string]any{\n\t\t\"string\":    \"hello\",\n\t\t\"StringPtr\": \"goodbye\",\n\t}, &target)\n\tif err != nil {\n\t\tt.Fatalf(\"got error: %s\", err)\n\t}\n\n\t// Pointers fail reflect test so do those manually\n\tif target.StringPtr == nil || *target.StringPtr != \"goodbye\" {\n\t\tt.Fatalf(\"bad: %#v\", target)\n\t}\n\ttarget.StringPtr = nil\n\n\tif !reflect.DeepEqual(target, expected) {\n\t\tt.Fatalf(\"bad: %#v\", target)\n\t}\n}\n\nfunc TestDecoder_MatchName(t *testing.T) {\n\tt.Parallel()\n\n\ttype Target struct {\n\t\tFirstMatch  string `mapstructure:\"first_match\"`\n\t\tSecondMatch string\n\t\tNoMatch     string `mapstructure:\"no_match\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"first_match\": \"foo\",\n\t\t\"SecondMatch\": \"bar\",\n\t\t\"NO_MATCH\":    \"baz\",\n\t}\n\n\texpected := Target{\n\t\tFirstMatch:  \"foo\",\n\t\tSecondMatch: \"bar\",\n\t}\n\n\tvar actual Target\n\tconfig := &DecoderConfig{\n\t\tResult: &actual,\n\t\tMatchName: func(mapKey, fieldName string) bool {\n\t\t\treturn mapKey == fieldName\n\t\t},\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tif !reflect.DeepEqual(expected, actual) {\n\t\tt.Fatalf(\"Decode() expected: %#v, got: %#v\", expected, actual)\n\t}\n}\n\nfunc TestDecoder_IgnoreUntaggedFields(t *testing.T) {\n\ttype Input struct {\n\t\tUntaggedNumber int\n\t\tTaggedNumber   int `mapstructure:\"tagged_number\"`\n\t\tUntaggedString string\n\t\tTaggedString   string `mapstructure:\"tagged_string\"`\n\t}\n\tinput := &Input{\n\t\tUntaggedNumber: 31,\n\t\tTaggedNumber:   42,\n\t\tUntaggedString: \"hidden\",\n\t\tTaggedString:   \"visible\",\n\t}\n\n\tactual := make(map[string]any)\n\tconfig := &DecoderConfig{\n\t\tResult:               &actual,\n\t\tIgnoreUntaggedFields: true,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\texpected := map[string]any{\n\t\t\"tagged_number\": 42,\n\t\t\"tagged_string\": \"visible\",\n\t}\n\n\tif !reflect.DeepEqual(expected, actual) {\n\t\tt.Fatalf(\"Decode() expected: %#v\\ngot: %#v\", expected, actual)\n\t}\n}\n\nfunc TestDecoder_IgnoreUntaggedFieldsWithStruct(t *testing.T) {\n\ttype Output struct {\n\t\tUntaggedInt    int\n\t\tTaggedNumber   int `mapstructure:\"tagged_number\"`\n\t\tUntaggedString string\n\t\tTaggedString   string `mapstructure:\"tagged_string\"`\n\t}\n\tinput := map[any]any{\n\t\t\"untaggedint\":     31,\n\t\t\"tagged_number\":   41,\n\t\t\"untagged_string\": \"hidden\",\n\t\t\"tagged_string\":   \"visible\",\n\t}\n\tactual := Output{}\n\tconfig := &DecoderConfig{\n\t\tResult:               &actual,\n\t\tIgnoreUntaggedFields: true,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\texpected := Output{\n\t\tTaggedNumber: 41,\n\t\tTaggedString: \"visible\",\n\t}\n\tif !reflect.DeepEqual(expected, actual) {\n\t\tt.Fatalf(\"Decode() expected: %#v\\ngot: %#v\", expected, actual)\n\t}\n}\n\nfunc TestDecoder_MultiTagInline(t *testing.T) {\n\ttype Inner struct {\n\t\tA int `yaml:\"a\"`\n\t}\n\n\ttype Wrap struct {\n\t\tInner `yaml:\",inline\"`\n\t}\n\n\tinput := map[string]any{\"a\": 1}\n\tvar result Wrap\n\n\tdec, err := NewDecoder(&DecoderConfig{\n\t\tTagName:          \"config,yaml\",\n\t\tSquashTagOption:  \"inline\",\n\t\tWeaklyTypedInput: true,\n\t\tResult:           &result,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"NewDecoder error: %v\", err)\n\t}\n\n\tif err := dec.Decode(input); err != nil {\n\t\tt.Fatalf(\"Decode error: %v\", err)\n\t}\n\n\tif result.Inner.A != 1 {\n\t\tt.Fatalf(\"expected inline field A=1, got %d\", result.Inner.A)\n\t}\n}\n\nfunc TestDecoder_MultiTagRemain(t *testing.T) {\n\ttype Wrap struct {\n\t\tKnown string         `yaml:\"known\"`\n\t\tExtra map[string]any `yaml:\",remain\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"known\":  \"ok\",\n\t\t\"extra1\": \"v1\",\n\t\t\"extra2\": 2,\n\t}\n\tvar result Wrap\n\n\tdec, err := NewDecoder(&DecoderConfig{\n\t\tTagName:          \"config,yaml\",\n\t\tWeaklyTypedInput: true,\n\t\tResult:           &result,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"NewDecoder error: %v\", err)\n\t}\n\n\tif err := dec.Decode(input); err != nil {\n\t\tt.Fatalf(\"Decode error: %v\", err)\n\t}\n\n\tif result.Known != \"ok\" {\n\t\tt.Fatalf(\"expected Known=ok, got %q\", result.Known)\n\t}\n\tif result.Extra == nil || len(result.Extra) != 2 {\n\t\tt.Fatalf(\"expected Extra to contain 2 items, got %v\", result.Extra)\n\t}\n\tif result.Extra[\"extra1\"] != \"v1\" {\n\t\tt.Fatalf(\"expected extra1=v1, got %v\", result.Extra[\"extra1\"])\n\t}\n}\n\nfunc TestDecoder_MultiTagBasic(t *testing.T) {\n\ttype Person struct {\n\t\tName  string `yaml:\"name\"`\n\t\tAge   int    `json:\"age\"`\n\t\tEmail string `config:\"email_address\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"name\":          \"Alice\",\n\t\t\"age\":           30,\n\t\t\"email_address\": \"alice@example.com\",\n\t}\n\tvar result Person\n\n\tdec, err := NewDecoder(&DecoderConfig{\n\t\tTagName: \"yaml,json,config\",\n\t\tResult:  &result,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"NewDecoder error: %v\", err)\n\t}\n\n\tif err := dec.Decode(input); err != nil {\n\t\tt.Fatalf(\"Decode error: %v\", err)\n\t}\n\n\tif result.Name != \"Alice\" {\n\t\tt.Fatalf(\"expected Name=Alice, got %q\", result.Name)\n\t}\n\tif result.Age != 30 {\n\t\tt.Fatalf(\"expected Age=30, got %d\", result.Age)\n\t}\n\tif result.Email != \"alice@example.com\" {\n\t\tt.Fatalf(\"expected Email=alice@example.com, got %q\", result.Email)\n\t}\n}\n\nfunc TestDecoder_MultiTagPriority(t *testing.T) {\n\t// When both tags exist, the first tag name in the list takes precedence\n\ttype Item struct {\n\t\tValue string `yaml:\"yaml_value\" json:\"json_value\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"yaml_value\": \"from_yaml\",\n\t\t\"json_value\": \"from_json\",\n\t}\n\n\t// Test yaml,json order - should use yaml tag\n\tvar result1 Item\n\tdec1, err := NewDecoder(&DecoderConfig{\n\t\tTagName: \"yaml,json\",\n\t\tResult:  &result1,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"NewDecoder error: %v\", err)\n\t}\n\tif err := dec1.Decode(input); err != nil {\n\t\tt.Fatalf(\"Decode error: %v\", err)\n\t}\n\tif result1.Value != \"from_yaml\" {\n\t\tt.Fatalf(\"with yaml,json expected Value=from_yaml, got %q\", result1.Value)\n\t}\n\n\t// Test json,yaml order - should use json tag\n\tvar result2 Item\n\tdec2, err := NewDecoder(&DecoderConfig{\n\t\tTagName: \"json,yaml\",\n\t\tResult:  &result2,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"NewDecoder error: %v\", err)\n\t}\n\tif err := dec2.Decode(input); err != nil {\n\t\tt.Fatalf(\"Decode error: %v\", err)\n\t}\n\tif result2.Value != \"from_json\" {\n\t\tt.Fatalf(\"with json,yaml expected Value=from_json, got %q\", result2.Value)\n\t}\n}\n\nfunc TestDecoder_MultiTagWhitespace(t *testing.T) {\n\ttype Person struct {\n\t\tName string `yaml:\"name\"`\n\t\tAge  int    `json:\"age\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"name\": \"Bob\",\n\t\t\"age\":  25,\n\t}\n\tvar result Person\n\n\t// Test with whitespace around tag names\n\tdec, err := NewDecoder(&DecoderConfig{\n\t\tTagName: \" yaml , json \",\n\t\tResult:  &result,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"NewDecoder error: %v\", err)\n\t}\n\n\tif err := dec.Decode(input); err != nil {\n\t\tt.Fatalf(\"Decode error: %v\", err)\n\t}\n\n\tif result.Name != \"Bob\" {\n\t\tt.Fatalf(\"expected Name=Bob, got %q\", result.Name)\n\t}\n\tif result.Age != 25 {\n\t\tt.Fatalf(\"expected Age=25, got %d\", result.Age)\n\t}\n}\n\nfunc TestDecoder_MultiTagEmptyNames(t *testing.T) {\n\ttype Person struct {\n\t\tName string `mapstructure:\"name\"`\n\t}\n\n\tinput := map[string]any{\n\t\t\"name\": \"Charlie\",\n\t}\n\n\ttests := []struct {\n\t\tname    string\n\t\ttagName string\n\t}{\n\t\t{\"leading comma\", \",yaml\"},\n\t\t{\"trailing comma\", \"yaml,\"},\n\t\t{\"multiple commas\", \",,yaml,,\"},\n\t\t{\"only commas\", \",,,\"},\n\t\t{\"empty with spaces\", \" , , \"},\n\t}\n\n\tfor _, tc := range tests {\n\t\tt.Run(tc.name, func(t *testing.T) {\n\t\t\tvar result Person\n\t\t\tdec, err := NewDecoder(&DecoderConfig{\n\t\t\t\tTagName: tc.tagName,\n\t\t\t\tResult:  &result,\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"NewDecoder error: %v\", err)\n\t\t\t}\n\n\t\t\tif err := dec.Decode(input); err != nil {\n\t\t\t\tt.Fatalf(\"Decode error: %v\", err)\n\t\t\t}\n\n\t\t\t// With invalid/empty tag names, should fall back to mapstructure\n\t\t\tif result.Name != \"Charlie\" {\n\t\t\t\tt.Fatalf(\"expected Name=Charlie (fallback to mapstructure), got %q\", result.Name)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDecoder_DecodeNilOption(t *testing.T) {\n\tt.Parallel()\n\n\ttype Transformed struct {\n\t\tMessage string\n\t\tWhen    string\n\t}\n\n\thelloHook := func(reflect.Type, reflect.Type, any) (any, error) {\n\t\treturn Transformed{Message: \"hello\"}, nil\n\t}\n\tgoodbyeHook := func(reflect.Type, reflect.Type, any) (any, error) {\n\t\treturn Transformed{Message: \"goodbye\"}, nil\n\t}\n\tappendHook := func(from reflect.Value, to reflect.Value) (any, error) {\n\t\tif from.Kind() == reflect.Map {\n\t\t\tstringMap := from.Interface().(map[string]any)\n\t\t\tif stringMap == nil {\n\t\t\t\tstringMap = make(map[string]any)\n\t\t\t}\n\t\t\tstringMap[\"when\"] = \"see you later\"\n\t\t\treturn stringMap, nil\n\t\t}\n\t\treturn from.Interface(), nil\n\t}\n\n\ttests := []struct {\n\t\tname           string\n\t\tdecodeNil      bool\n\t\tinput          any\n\t\tresult         Transformed\n\t\texpectedResult Transformed\n\t\tdecodeHook     DecodeHookFunc\n\t}{\n\t\t{\n\t\t\tname:           \"decodeNil=true for nil input with hook\",\n\t\t\tdecodeNil:      true,\n\t\t\tinput:          nil,\n\t\t\tdecodeHook:     helloHook,\n\t\t\texpectedResult: Transformed{Message: \"hello\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=true for nil input without hook\",\n\t\t\tdecodeNil:      true,\n\t\t\tinput:          nil,\n\t\t\texpectedResult: Transformed{Message: \"\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for nil input with hook\",\n\t\t\tdecodeNil:      false,\n\t\t\tinput:          nil,\n\t\t\tdecodeHook:     helloHook,\n\t\t\texpectedResult: Transformed{Message: \"\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for nil input without hook\",\n\t\t\tdecodeNil:      false,\n\t\t\tinput:          nil,\n\t\t\texpectedResult: Transformed{Message: \"\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=true for non-nil input without hook\",\n\t\t\tdecodeNil:      true,\n\t\t\tinput:          map[string]any{\"message\": \"bar\"},\n\t\t\texpectedResult: Transformed{Message: \"bar\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=true for non-nil input with hook\",\n\t\t\tdecodeNil:      true,\n\t\t\tinput:          map[string]any{\"message\": \"bar\"},\n\t\t\tdecodeHook:     goodbyeHook,\n\t\t\texpectedResult: Transformed{Message: \"goodbye\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for non-nil input without hook\",\n\t\t\tdecodeNil:      false,\n\t\t\tinput:          map[string]any{\"message\": \"bar\"},\n\t\t\texpectedResult: Transformed{Message: \"bar\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for non-nil input with hook\",\n\t\t\tdecodeNil:      false,\n\t\t\tinput:          map[string]any{\"message\": \"bar\"},\n\t\t\tdecodeHook:     goodbyeHook,\n\t\t\texpectedResult: Transformed{Message: \"goodbye\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=true for nil input without hook and non-empty result\",\n\t\t\tdecodeNil:      true,\n\t\t\tinput:          nil,\n\t\t\tresult:         Transformed{Message: \"foo\"},\n\t\t\texpectedResult: Transformed{Message: \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=true for nil input with hook and non-empty result\",\n\t\t\tdecodeNil:      true,\n\t\t\tinput:          nil,\n\t\t\tresult:         Transformed{Message: \"foo\"},\n\t\t\tdecodeHook:     helloHook,\n\t\t\texpectedResult: Transformed{Message: \"hello\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for nil input without hook and non-empty result\",\n\t\t\tdecodeNil:      false,\n\t\t\tinput:          nil,\n\t\t\tresult:         Transformed{Message: \"foo\"},\n\t\t\texpectedResult: Transformed{Message: \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for nil input with hook and non-empty result\",\n\t\t\tdecodeNil:      false,\n\t\t\tinput:          nil,\n\t\t\tresult:         Transformed{Message: \"foo\"},\n\t\t\tdecodeHook:     helloHook,\n\t\t\texpectedResult: Transformed{Message: \"foo\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for non-nil input with hook that appends a value\",\n\t\t\tdecodeNil:      false,\n\t\t\tinput:          map[string]any{\"message\": \"bar\"},\n\t\t\tdecodeHook:     appendHook,\n\t\t\texpectedResult: Transformed{Message: \"bar\", When: \"see you later\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=true for non-nil input with hook that appends a value\",\n\t\t\tdecodeNil:      true,\n\t\t\tinput:          map[string]any{\"message\": \"bar\"},\n\t\t\tdecodeHook:     appendHook,\n\t\t\texpectedResult: Transformed{Message: \"bar\", When: \"see you later\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=true for nil input with hook that appends a value\",\n\t\t\tdecodeNil:      true,\n\t\t\tdecodeHook:     appendHook,\n\t\t\texpectedResult: Transformed{When: \"see you later\"},\n\t\t},\n\t\t{\n\t\t\tname:           \"decodeNil=false for nil input with hook that appends a value\",\n\t\t\tdecodeNil:      false,\n\t\t\tdecodeHook:     appendHook,\n\t\t\texpectedResult: Transformed{},\n\t\t},\n\t}\n\n\tfor _, test := range tests {\n\t\tt.Run(test.name, func(t *testing.T) {\n\t\t\tconfig := &DecoderConfig{\n\t\t\t\tResult:     &test.result,\n\t\t\t\tDecodeNil:  test.decodeNil,\n\t\t\t\tDecodeHook: test.decodeHook,\n\t\t\t}\n\n\t\t\tdecoder, err := NewDecoder(config)\n\t\t\tif err != nil {\n\t\t\t\tt.Fatalf(\"err: %s\", err)\n\t\t\t}\n\n\t\t\tif err := decoder.Decode(test.input); err != nil {\n\t\t\t\tt.Fatalf(\"got an err: %s\", err)\n\t\t\t}\n\n\t\t\tif test.result != test.expectedResult {\n\t\t\t\tt.Errorf(\"result should be: %#v, got %#v\", test.expectedResult, test.result)\n\t\t\t}\n\t\t})\n\t}\n}\n\nfunc TestDecoder_ExpandNilStructPointersHookFunc(t *testing.T) {\n\t// a decoder hook that expands nil pointers in a struct to their zero value\n\t// if the input map contains the corresponding key.\n\tdecodeHook := func(from reflect.Value, to reflect.Value) (any, error) {\n\t\tif from.Kind() == reflect.Map && to.Kind() == reflect.Map {\n\t\t\ttoElem := to.Type().Elem()\n\t\t\tif toElem.Kind() == reflect.Ptr && toElem.Elem().Kind() == reflect.Struct {\n\t\t\t\tfromRange := from.MapRange()\n\t\t\t\tfor fromRange.Next() {\n\t\t\t\t\tfromKey := fromRange.Key()\n\t\t\t\t\tfromValue := fromRange.Value()\n\t\t\t\t\tif fromValue.IsNil() {\n\t\t\t\t\t\tnewFromValue := reflect.New(toElem.Elem())\n\t\t\t\t\t\tfrom.SetMapIndex(fromKey, newFromValue)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn from.Interface(), nil\n\t}\n\ttype Struct struct {\n\t\tName string\n\t}\n\ttype TestConfig struct {\n\t\tBoolean   *bool              `mapstructure:\"boolean\"`\n\t\tStruct    *Struct            `mapstructure:\"struct\"`\n\t\tMapStruct map[string]*Struct `mapstructure:\"map_struct\"`\n\t}\n\tstringMap := map[string]any{\n\t\t\"boolean\": nil,\n\t\t\"struct\":  nil,\n\t\t\"map_struct\": map[string]any{\n\t\t\t\"struct\": nil,\n\t\t},\n\t}\n\tvar result TestConfig\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tResult:     &result,\n\t\tDecodeNil:  true,\n\t\tDecodeHook: decodeHook,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\tif err := decoder.Decode(stringMap); err != nil {\n\t\tt.Fatalf(\"got an err: %s\", err)\n\t}\n\tif result.Boolean != nil {\n\t\tt.Errorf(\"nil Boolean expected, got '%#v'\", result.Boolean)\n\t}\n\tif result.Struct != nil {\n\t\tt.Errorf(\"nil Struct expected, got '%#v'\", result.Struct)\n\t}\n\tif len(result.MapStruct) == 0 {\n\t\tt.Fatalf(\"not-empty MapStruct expected, got '%#v'\", result.MapStruct)\n\t}\n\tif _, ok := result.MapStruct[\"struct\"]; !ok {\n\t\tt.Errorf(\"MapStruct['struct'] expected\")\n\t}\n}\n\nfunc TestErrorLeakageWeakDecode(t *testing.T) {\n\tcases := []struct {\n\t\tvalue         any\n\t\ttarget        any\n\t\tallowNilError bool\n\t}{\n\t\t// case 0\n\t\t{\"testing\", new(bool), false},\n\t\t{\"testing\", new(int8), false},\n\t\t{\"testing\", new(uint8), false},\n\t\t{\"testing\", new(int16), false},\n\t\t{\"testing\", new(uint16), false},\n\t\t// case 5\n\t\t{\"testing\", new(int32), false},\n\t\t{\"testing\", new(uint32), false},\n\t\t{\"testing\", new(int64), false},\n\t\t{\"testing\", new(uint64), false},\n\t\t{\"testing\", new(int), false},\n\t\t// case 10\n\t\t{\"testing\", new(uint), false},\n\t\t{\"testing\", new(float32), false},\n\t\t{\"testing\", new(float64), false},\n\t\t{\"testing\", new(complex64), false},\n\t\t{\"testing\", new(complex128), false},\n\t\t// case 15\n\t\t{\"testing\", new(time.Duration), true},\n\t\t{\"testing\", new(time.Time), true},\n\t\t{map[string]string{\"key\": \"secret-testing\"}, new(map[string]int), false},\n\t\t{map[string]string{\"key\": \"secret-testing\"}, new(struct{ Key int }), false},\n\t\t{\"secret-testing\", new([]int), false},\n\t\t// case 20\n\t\t{\"secret-testing\", new([4]int), false},\n\t}\n\n\tfor i, tc := range cases {\n\t\terr := WeakDecode(tc.value, tc.target)\n\t\tif err == nil {\n\t\t\tif tc.allowNilError {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tt.Fatalf(\"case %d: expected error from input %v:\\n\\toutput (%T): %#v\\n\\toutput (string): %v\", i, tc.value, tc.target, tc.target, tc.target)\n\t\t}\n\n\t\tstrValue := fmt.Sprintf(\"%v\", tc.value)\n\t\tif strings.Contains(strValue, \"secret-testing\") {\n\t\t\tstrValue = \"secret-testing\"\n\t\t}\n\n\t\tif strings.Contains(err.Error(), strValue) {\n\t\t\tt.Errorf(\"case %d: error contains input value\\n\\terr: %v\\n\\tinput: %v\", i, err, strValue)\n\t\t} else {\n\t\t\tt.Logf(\"case %d: got safe error: %v\", i, err)\n\t\t}\n\t}\n}\n\nfunc testSliceInput(t *testing.T, input map[string]any, expected *Slice) {\n\tvar result Slice\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got error: %s\", err)\n\t}\n\n\tif result.Vfoo != expected.Vfoo {\n\t\tt.Errorf(\"Vfoo expected '%s', got '%s'\", expected.Vfoo, result.Vfoo)\n\t}\n\n\tif result.Vbar == nil {\n\t\tt.Fatalf(\"Vbar a slice, got '%#v'\", result.Vbar)\n\t}\n\n\tif len(result.Vbar) != len(expected.Vbar) {\n\t\tt.Errorf(\"Vbar length should be %d, got %d\", len(expected.Vbar), len(result.Vbar))\n\t}\n\n\tfor i, v := range result.Vbar {\n\t\tif v != expected.Vbar[i] {\n\t\t\tt.Errorf(\n\t\t\t\t\"Vbar[%d] should be '%#v', got '%#v'\",\n\t\t\t\ti, expected.Vbar[i], v)\n\t\t}\n\t}\n}\n\nfunc testArrayInput(t *testing.T, input map[string]any, expected *Array) {\n\tvar result Array\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"got error: %s\", err)\n\t}\n\n\tif result.Vfoo != expected.Vfoo {\n\t\tt.Errorf(\"Vfoo expected '%s', got '%s'\", expected.Vfoo, result.Vfoo)\n\t}\n\n\tif result.Vbar == [2]string{} {\n\t\tt.Fatalf(\"Vbar a slice, got '%#v'\", result.Vbar)\n\t}\n\n\tif len(result.Vbar) != len(expected.Vbar) {\n\t\tt.Errorf(\"Vbar length should be %d, got %d\", len(expected.Vbar), len(result.Vbar))\n\t}\n\n\tfor i, v := range result.Vbar {\n\t\tif v != expected.Vbar[i] {\n\t\t\tt.Errorf(\n\t\t\t\t\"Vbar[%d] should be '%#v', got '%#v'\",\n\t\t\t\ti, expected.Vbar[i], v)\n\t\t}\n\t}\n}\n\n// Test struct for embedded error message testing\ntype TestDatabaseConfig struct {\n\tHost     string `mapstructure:\"host\"`\n\tPort     int    `mapstructure:\"port\"`\n\tUsername string `mapstructure:\"username\"`\n}\n\ntype TestServerConfig struct {\n\tTestDatabaseConfig `mapstructure:\",squash\"`\n\tAppName            string `mapstructure:\"app_name\"`\n\tDebug              bool   `mapstructure:\"debug\"`\n}\n\nfunc TestDecoder_ErrorUnused_EmbeddedStruct_QualifiedTypeName(t *testing.T) {\n\tt.Parallel()\n\n\t// Input with an invalid key that should cause an error\n\tinput := map[string]any{\n\t\t\"host\":        \"localhost\",\n\t\t\"port\":        5432,\n\t\t\"username\":    \"admin\",\n\t\t\"app_name\":    \"myapp\",\n\t\t\"debug\":       true,\n\t\t\"invalid_key\": \"this should cause an error\", // This key doesn't exist in the struct\n\t}\n\n\tvar config TestServerConfig\n\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tErrorUnused: true, // Enable error on unused keys\n\t\tResult:      &config,\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err == nil {\n\t\tt.Fatal(\"expected error due to unused keys\")\n\t}\n\n\terrorMessage := err.Error()\n\tt.Logf(\"Error message: %s\", errorMessage)\n\n\t// Check that the error message contains the qualified struct type name\n\tif !strings.Contains(errorMessage, \"'mapstructure.TestServerConfig'\") {\n\t\tt.Errorf(\"Expected error message to contain qualified struct type 'mapstructure.TestServerConfig', got: %s\", errorMessage)\n\t}\n\n\t// Check that unused keys are mentioned\n\tif !strings.Contains(errorMessage, \"invalid_key\") {\n\t\tt.Errorf(\"Expected error message to contain 'invalid_key', got: %s\", errorMessage)\n\t}\n}\n\nfunc TestDecode_structArrayDeepMap(t *testing.T) {\n\ttype SourceChild struct {\n\t\tString string `mapstructure:\"some-string\"`\n\t}\n\n\ttype SourceParent struct {\n\t\tChildrenA []SourceChild  `mapstructure:\"children-a,deep\"`\n\t\tChildrenB *[]SourceChild `mapstructure:\"children-b,deep\"`\n\t}\n\n\tvar target map[string]any\n\n\tsource := SourceParent{\n\t\tChildrenA: []SourceChild{\n\t\t\t{String: \"one\"},\n\t\t\t{String: \"two\"},\n\t\t},\n\t\tChildrenB: &[]SourceChild{\n\t\t\t{String: \"one\"},\n\t\t\t{String: \"two\"},\n\t\t},\n\t}\n\n\tif err := Decode(source, &target); err != nil {\n\t\tt.Fatalf(\"got error: %s\", err)\n\t}\n\n\texpected := map[string]any{\n\t\t\"children-a\": []map[string]any{\n\t\t\t{\"some-string\": \"one\"},\n\t\t\t{\"some-string\": \"two\"},\n\t\t},\n\t\t\"children-b\": []map[string]any{\n\t\t\t{\"some-string\": \"one\"},\n\t\t\t{\"some-string\": \"two\"},\n\t\t},\n\t}\n\n\tif !reflect.DeepEqual(target, expected) {\n\t\tt.Fatalf(\"failed: \\nexpected: %#v\\nresult: %#v\", expected, target)\n\t}\n}\n\nfunc TestDecoder_RootName(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"surname\": \"green\",\n\t\t\"relation\": map[string]any{\n\t\t\t\"surname\": \"black\",\n\t\t},\n\t}\n\n\tvar result struct {\n\t\tName     string `mapstructure:\"name\"`\n\t\tRelation struct {\n\t\t\tName string `mapstructure:\"name\"`\n\t\t} `mapstructure:\"relation\"`\n\t}\n\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tErrorUnset:  true,\n\t\tErrorUnused: true,\n\t\tResult:      &result,\n\t\tRootName:    \"root\",\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err == nil {\n\t\tt.Fatal(\"expected error\")\n\t}\n\n\texpectedErrors := []string{\n\t\t`'root.relation' has invalid keys: surname`,\n\t\t`'root.relation' has unset fields: name`,\n\t\t`'root' has invalid keys: surname`,\n\t\t`'root' has unset fields: name`,\n\t}\n\n\tfailed := false\n\n\tfor _, expectedErr := range expectedErrors {\n\t\tif !strings.Contains(err.Error(), expectedErr) {\n\t\t\tfailed = true\n\t\t}\n\t}\n\n\tif failed {\n\t\tt.Errorf(\"unexpected error message, got: %s\", err.Error())\n\t}\n}\n\nfunc stringPtr(v string) *string  { return &v }\nfunc intPtr(v int) *int           { return &v }\nfunc uintPtr(v uint) *uint        { return &v }\nfunc boolPtr(v bool) *bool        { return &v }\nfunc floatPtr(v float64) *float64 { return &v }\nfunc interfacePtr(v any) *any     { return &v }\n\ntype TestMapFieldName struct {\n\tHostName string\n\tUsername string\n}\n\nfunc TestDecoder_MapFieldNameMapFromStruct(t *testing.T) {\n\tt.Parallel()\n\n\tvar structKeys map[string]any\n\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tErrorUnused: true, // Enable error on unused keys\n\t\tResult:      &structKeys,\n\t\tMapFieldName: func(s string) string {\n\t\t\tif s == \"HostName\" {\n\t\t\t\treturn \"host_name\"\n\t\t\t}\n\t\t\treturn s\n\t\t},\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tvar input TestMapFieldName\n\n\terr = decoder.Decode(&input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\t_, ok := structKeys[\"host_name\"]\n\tif !ok {\n\t\tt.Fatal(\"expected host_name to exist\")\n\t}\n\n\t_, ok = structKeys[\"Username\"]\n\tif !ok {\n\t\tt.Fatal(\"expected Username to exist\")\n\t}\n}\n\nfunc TestDecoder_MapFieldNameStructFromMap(t *testing.T) {\n\tt.Parallel()\n\n\tfoo := TestMapFieldName{}\n\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tResult: &foo,\n\t\tMapFieldName: func(s string) string {\n\t\t\tif s == \"HostName\" {\n\t\t\t\treturn \"host_name\"\n\t\t\t}\n\t\t\tif s == \"Username\" {\n\t\t\t\treturn \"user_name\"\n\t\t\t}\n\t\t\treturn s\n\t\t},\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tstructKeys := map[string]any{\n\t\t\"host_name\": \"foo\",\n\t\t\"user_name\": \"bar\",\n\t}\n\n\terr = decoder.Decode(&structKeys)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tif foo.HostName != \"foo\" {\n\t\tt.Fatal(\"expected HostName to be foo\")\n\t}\n\n\tif foo.Username != \"bar\" {\n\t\tt.Fatal(\"expected Username to be bar\")\n\t}\n}\n\nfunc TestDecoder_MapFieldNameWithMatchName(t *testing.T) {\n\tt.Parallel()\n\n\ttype Target struct {\n\t\tHostName string\n\t\tUsername string\n\t}\n\n\tinput := map[string]any{\n\t\t\"HOST_NAME\": \"server1\",\n\t\t\"user_name\": \"admin\",\n\t}\n\n\tvar result Target\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tResult: &result,\n\t\tMapFieldName: func(s string) string {\n\t\t\t// Convert HostName -> host_name, Username -> user_name\n\t\t\tif s == \"HostName\" {\n\t\t\t\treturn \"host_name\"\n\t\t\t}\n\t\t\tif s == \"Username\" {\n\t\t\t\treturn \"user_name\"\n\t\t\t}\n\t\t\treturn s\n\t\t},\n\t\tMatchName: strings.EqualFold, // Case-insensitive fallback\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\t// HOST_NAME should match host_name via case-insensitive MatchName\n\tif result.HostName != \"server1\" {\n\t\tt.Fatalf(\"expected HostName to be 'server1', got '%s'\", result.HostName)\n\t}\n\n\t// user_name matches exactly\n\tif result.Username != \"admin\" {\n\t\tt.Fatalf(\"expected Username to be 'admin', got '%s'\", result.Username)\n\t}\n}\n\nfunc TestDecoder_MapFieldNameWithIgnoreUntaggedFields(t *testing.T) {\n\tt.Parallel()\n\n\ttype Target struct {\n\t\tTaggedField   string `mapstructure:\"tagged_field\"`\n\t\tUntaggedField string\n\t}\n\n\tinput := map[string]any{\n\t\t\"tagged_field\":   \"tagged_value\",\n\t\t\"untagged_field\": \"untagged_value\",\n\t}\n\n\tvar result Target\n\tdecoder, err := NewDecoder(&DecoderConfig{\n\t\tResult:               &result,\n\t\tIgnoreUntaggedFields: true,\n\t\tMapFieldName: func(s string) string {\n\t\t\t// This would convert UntaggedField -> untagged_field,\n\t\t\t// but IgnoreUntaggedFields takes precedence\n\t\t\tif s == \"UntaggedField\" {\n\t\t\t\treturn \"untagged_field\"\n\t\t\t}\n\t\t\treturn s\n\t\t},\n\t})\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\terr = decoder.Decode(input)\n\tif err != nil {\n\t\tt.Fatalf(\"err: %s\", err)\n\t}\n\n\tif result.TaggedField != \"tagged_value\" {\n\t\tt.Fatalf(\"expected TaggedField to be 'tagged_value', got '%s'\", result.TaggedField)\n\t}\n\n\t// UntaggedField should remain empty because IgnoreUntaggedFields is true\n\tif result.UntaggedField != \"\" {\n\t\tt.Fatalf(\"expected UntaggedField to be empty due to IgnoreUntaggedFields, got '%s'\", result.UntaggedField)\n\t}\n}\n\n// Test types for Unmarshaler\ntype PersonWithUnmarshaler struct {\n\tName string\n\tAge  int\n\traw  map[string]any // stores raw data for verification\n}\n\nfunc (p *PersonWithUnmarshaler) UnmarshalMapstructure(data any) error {\n\tm, ok := data.(map[string]any)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected map[string]any, got %T\", data)\n\t}\n\tp.raw = m\n\tif name, ok := m[\"name\"].(string); ok {\n\t\tp.Name = name\n\t}\n\tif age, ok := m[\"age\"].(int); ok {\n\t\tp.Age = age\n\t}\n\treturn nil\n}\n\nfunc TestUnmarshaler_Basic(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"name\": \"Alice\",\n\t\t\"age\":  30,\n\t}\n\n\tvar result PersonWithUnmarshaler\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Name != \"Alice\" {\n\t\tt.Errorf(\"expected Name 'Alice', got %q\", result.Name)\n\t}\n\tif result.Age != 30 {\n\t\tt.Errorf(\"expected Age 30, got %d\", result.Age)\n\t}\n\tif result.raw == nil {\n\t\tt.Error(\"expected raw to be set, but it was nil\")\n\t}\n}\n\nfunc TestUnmarshaler_WithDecodeHook(t *testing.T) {\n\tt.Parallel()\n\n\t// DecodeHook that transforms the data before Unmarshaler receives it\n\thook := func(from reflect.Type, to reflect.Type, data any) (any, error) {\n\t\tif m, ok := data.(map[string]any); ok {\n\t\t\tif name, ok := m[\"name\"].(string); ok {\n\t\t\t\tm[\"name\"] = strings.ToUpper(name)\n\t\t\t}\n\t\t}\n\t\treturn data, nil\n\t}\n\n\tinput := map[string]any{\n\t\t\"name\": \"alice\",\n\t\t\"age\":  30,\n\t}\n\n\tvar result PersonWithUnmarshaler\n\tconfig := &DecoderConfig{\n\t\tDecodeHook: hook,\n\t\tResult:     &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create decoder: %s\", err)\n\t}\n\n\tif err := decoder.Decode(input); err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\t// Unmarshaler should receive transformed data\n\tif result.Name != \"ALICE\" {\n\t\tt.Errorf(\"expected Name 'ALICE' (transformed), got %q\", result.Name)\n\t}\n}\n\nfunc TestUnmarshaler_Disabled(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"name\": \"Alice\",\n\t\t\"age\":  30,\n\t}\n\n\tvar result PersonWithUnmarshaler\n\tconfig := &DecoderConfig{\n\t\tDisableUnmarshaler: true,\n\t\tResult:             &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create decoder: %s\", err)\n\t}\n\n\tif err := decoder.Decode(input); err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\t// With Unmarshaler disabled, standard decoding should be used\n\t// raw should be nil since UnmarshalMapstructure wasn't called\n\tif result.raw != nil {\n\t\tt.Error(\"Unmarshaler should not have been called when disabled\")\n\t}\n\n\t// But the fields should still be decoded via normal path\n\tif result.Name != \"Alice\" {\n\t\tt.Errorf(\"expected Name 'Alice', got %q\", result.Name)\n\t}\n}\n\n// AddressWithUnmarshaler demonstrates nested struct with Unmarshaler\ntype AddressWithUnmarshaler struct {\n\tCity    string\n\tCountry string\n}\n\nfunc (a *AddressWithUnmarshaler) UnmarshalMapstructure(data any) error {\n\tm, ok := data.(map[string]any)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected map, got %T\", data)\n\t}\n\tif city, ok := m[\"city\"].(string); ok {\n\t\ta.City = strings.ToUpper(city)\n\t}\n\tif country, ok := m[\"country\"].(string); ok {\n\t\ta.Country = strings.ToUpper(country)\n\t}\n\treturn nil\n}\n\ntype PersonWithAddress struct {\n\tName    string\n\tAddress AddressWithUnmarshaler\n}\n\nfunc TestUnmarshaler_Nested(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"name\": \"Alice\",\n\t\t\"address\": map[string]any{\n\t\t\t\"city\":    \"new york\",\n\t\t\t\"country\": \"usa\",\n\t\t},\n\t}\n\n\tvar result PersonWithAddress\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Name != \"Alice\" {\n\t\tt.Errorf(\"expected Name 'Alice', got %q\", result.Name)\n\t}\n\t// Address should use its Unmarshaler, uppercasing the values\n\tif result.Address.City != \"NEW YORK\" {\n\t\tt.Errorf(\"expected City 'NEW YORK', got %q\", result.Address.City)\n\t}\n\tif result.Address.Country != \"USA\" {\n\t\tt.Errorf(\"expected Country 'USA', got %q\", result.Address.Country)\n\t}\n}\n\n// SquashInnerNoUnmarshaler is a simple struct without Unmarshaler for squash testing\ntype SquashInnerNoUnmarshaler struct {\n\tCity string\n}\n\n// PersonWithSquashedNoUnmarshaler tests that squash works normally when embedded type\n// doesn't implement Unmarshaler\ntype PersonWithSquashedNoUnmarshaler struct {\n\tName                     string\n\tSquashInnerNoUnmarshaler `mapstructure:\",squash\"`\n}\n\nfunc TestUnmarshaler_SquashWorksNormally(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"name\": \"Alice\",\n\t\t\"city\": \"New York\",\n\t}\n\n\tvar result PersonWithSquashedNoUnmarshaler\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Name != \"Alice\" {\n\t\tt.Errorf(\"expected Name 'Alice', got %q\", result.Name)\n\t}\n\t// Squashed field should be decoded via standard path\n\tif result.City != \"New York\" {\n\t\tt.Errorf(\"expected City 'New York', got %q\", result.City)\n\t}\n}\n\n// EmbeddedWithUnmarshaler tests embedded struct with Unmarshaler\ntype EmbeddedWithUnmarshaler struct {\n\tCity string\n}\n\nvar embeddedUnmarshalerCalled = false\n\nfunc (e *EmbeddedWithUnmarshaler) UnmarshalMapstructure(data any) error {\n\tembeddedUnmarshalerCalled = true\n\tm, ok := data.(map[string]any)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected map, got %T\", data)\n\t}\n\tif city, ok := m[\"city\"].(string); ok {\n\t\te.City = strings.ToUpper(city)\n\t}\n\treturn nil\n}\n\n// Note: When a type embeds another type that implements Unmarshaler,\n// Go's embedding rules cause the parent type to also implement Unmarshaler.\n// This test documents that behavior.\ntype PersonWithSquashedEmbedded struct {\n\tName                    string\n\tEmbeddedWithUnmarshaler `mapstructure:\",squash\"`\n}\n\nfunc TestUnmarshaler_EmbeddingInheritsInterface(t *testing.T) {\n\t// Note: not parallel because we're using a package-level flag\n\tembeddedUnmarshalerCalled = false\n\n\tinput := map[string]any{\n\t\t\"name\": \"Alice\",\n\t\t\"city\": \"New York\",\n\t}\n\n\tvar result PersonWithSquashedEmbedded\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\t// Due to Go's embedding rules, PersonWithSquashedEmbedded implements\n\t// Unmarshaler because EmbeddedWithUnmarshaler does. So the Unmarshaler\n\t// IS called, and it only knows about the \"city\" field.\n\tif !embeddedUnmarshalerCalled {\n\t\tt.Error(\"Unmarshaler should have been called due to embedding inheritance\")\n\t}\n\t// City should be uppercased because Unmarshaler was called\n\tif result.City != \"NEW YORK\" {\n\t\tt.Errorf(\"expected City 'NEW YORK', got %q\", result.City)\n\t}\n}\n\n// FailingUnmarshaler tests error handling\ntype FailingUnmarshaler struct {\n\tValue string\n}\n\nfunc (f *FailingUnmarshaler) UnmarshalMapstructure(data any) error {\n\treturn fmt.Errorf(\"intentional error\")\n}\n\nfunc TestUnmarshaler_ErrorHandling(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"value\": \"test\",\n\t}\n\n\tvar result FailingUnmarshaler\n\terr := Decode(input, &result)\n\tif err == nil {\n\t\tt.Fatal(\"expected error, got nil\")\n\t}\n\n\t// Check that error is wrapped in DecodeError\n\tvar decodeErr *DecodeError\n\tif !errors.As(err, &decodeErr) {\n\t\tt.Errorf(\"expected DecodeError, got %T: %v\", err, err)\n\t}\n}\n\n// PointerReceiverUnmarshaler tests pointer receiver only\ntype PointerReceiverUnmarshaler struct {\n\tValue string\n}\n\nfunc (p *PointerReceiverUnmarshaler) UnmarshalMapstructure(data any) error {\n\tm, ok := data.(map[string]any)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected map, got %T\", data)\n\t}\n\tif v, ok := m[\"value\"].(string); ok {\n\t\tp.Value = v + \"_unmarshaled\"\n\t}\n\treturn nil\n}\n\nfunc TestUnmarshaler_PointerReceiver(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"value\": \"test\",\n\t}\n\n\tvar result PointerReceiverUnmarshaler\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Value != \"test_unmarshaled\" {\n\t\tt.Errorf(\"expected 'test_unmarshaled', got %q\", result.Value)\n\t}\n}\n\nfunc TestUnmarshaler_Metadata(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"name\": \"Alice\",\n\t\t\"age\":  30,\n\t}\n\n\tvar md Metadata\n\tvar result PersonWithUnmarshaler\n\tconfig := &DecoderConfig{\n\t\tMetadata: &md,\n\t\tResult:   &result,\n\t}\n\n\tdecoder, err := NewDecoder(config)\n\tif err != nil {\n\t\tt.Fatalf(\"failed to create decoder: %s\", err)\n\t}\n\n\tif err := decoder.Decode(input); err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\t// Verify Unmarshaler was called\n\tif result.raw == nil {\n\t\tt.Error(\"expected Unmarshaler to be called\")\n\t}\n}\n\n// NonSquashedEmbeddedWithUnmarshaler tests that non-squashed embedded structs DO use Unmarshaler\ntype PersonWithNonSquashedEmbedded struct {\n\tName    string\n\tAddress EmbeddedWithUnmarshaler\n}\n\nfunc TestUnmarshaler_NonSquashedEmbedded(t *testing.T) {\n\t// Note: not parallel because we're using a package-level flag\n\tembeddedUnmarshalerCalled = false\n\n\tinput := map[string]any{\n\t\t\"name\": \"Alice\",\n\t\t\"address\": map[string]any{\n\t\t\t\"city\": \"new york\",\n\t\t},\n\t}\n\n\tvar result PersonWithNonSquashedEmbedded\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Name != \"Alice\" {\n\t\tt.Errorf(\"expected Name 'Alice', got %q\", result.Name)\n\t}\n\t// Non-squashed embedded field SHOULD use Unmarshaler (uppercased)\n\tif result.Address.City != \"NEW YORK\" {\n\t\tt.Errorf(\"expected City 'NEW YORK', got %q\", result.Address.City)\n\t}\n\tif !embeddedUnmarshalerCalled {\n\t\tt.Error(\"Unmarshaler should have been called for non-squashed embedded field\")\n\t}\n}\n\n// CustomString is a non-struct type that implements Unmarshaler\ntype CustomString string\n\nfunc (c *CustomString) UnmarshalMapstructure(data any) error {\n\ts, ok := data.(string)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected string, got %T\", data)\n\t}\n\t*c = CustomString(\"custom:\" + s)\n\treturn nil\n}\n\nfunc TestUnmarshaler_NonStructType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"name\": \"test-value\",\n\t}\n\n\ttype Result struct {\n\t\tName CustomString\n\t}\n\n\tvar result Result\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Name != \"custom:test-value\" {\n\t\tt.Errorf(\"expected 'custom:test-value', got %q\", result.Name)\n\t}\n}\n\n// CustomSlice is a slice type that implements Unmarshaler\ntype CustomSlice []string\n\nfunc (c *CustomSlice) UnmarshalMapstructure(data any) error {\n\tswitch v := data.(type) {\n\tcase []any:\n\t\t*c = make([]string, len(v))\n\t\tfor i, item := range v {\n\t\t\tif s, ok := item.(string); ok {\n\t\t\t\t(*c)[i] = \"item:\" + s\n\t\t\t}\n\t\t}\n\tcase string:\n\t\t// Also accept a single string\n\t\t*c = []string{\"single:\" + v}\n\tdefault:\n\t\treturn fmt.Errorf(\"expected slice or string, got %T\", data)\n\t}\n\treturn nil\n}\n\nfunc TestUnmarshaler_SliceType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"tags\": []any{\"a\", \"b\", \"c\"},\n\t}\n\n\ttype Result struct {\n\t\tTags CustomSlice\n\t}\n\n\tvar result Result\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\texpected := CustomSlice{\"item:a\", \"item:b\", \"item:c\"}\n\tif !reflect.DeepEqual(result.Tags, expected) {\n\t\tt.Errorf(\"expected %v, got %v\", expected, result.Tags)\n\t}\n}\n\n// CustomMap is a map type that implements Unmarshaler\ntype CustomMap map[string]int\n\nfunc (c *CustomMap) UnmarshalMapstructure(data any) error {\n\tm, ok := data.(map[string]any)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected map, got %T\", data)\n\t}\n\t*c = make(map[string]int)\n\tfor k, v := range m {\n\t\tif num, ok := v.(int); ok {\n\t\t\t(*c)[\"key:\"+k] = num * 10\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc TestUnmarshaler_MapType(t *testing.T) {\n\tt.Parallel()\n\n\tinput := map[string]any{\n\t\t\"scores\": map[string]any{\n\t\t\t\"alice\": 5,\n\t\t\t\"bob\":   10,\n\t\t},\n\t}\n\n\ttype Result struct {\n\t\tScores CustomMap\n\t}\n\n\tvar result Result\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\tif result.Scores[\"key:alice\"] != 50 {\n\t\tt.Errorf(\"expected key:alice=50, got %d\", result.Scores[\"key:alice\"])\n\t}\n\tif result.Scores[\"key:bob\"] != 100 {\n\t\tt.Errorf(\"expected key:bob=100, got %d\", result.Scores[\"key:bob\"])\n\t}\n}\n\nfunc TestUnmarshaler_StructToMap(t *testing.T) {\n\tt.Parallel()\n\n\t// Input is a struct that implements Unmarshaler\n\t// Output is a map - Unmarshaler should NOT be involved\n\tinput := PersonWithUnmarshaler{\n\t\tName: \"Alice\",\n\t\tAge:  30,\n\t}\n\n\tvar result map[string]any\n\terr := Decode(input, &result)\n\tif err != nil {\n\t\tt.Fatalf(\"unexpected error: %s\", err)\n\t}\n\n\t// Should use normal struct-to-map decoding\n\tif result[\"Name\"] != \"Alice\" {\n\t\tt.Errorf(\"expected Name 'Alice', got %v\", result[\"Name\"])\n\t}\n\tif result[\"Age\"] != 30 {\n\t\tt.Errorf(\"expected Age 30, got %v\", result[\"Age\"])\n\t}\n}\n"
  },
  {
    "path": "reflect_go1_19.go",
    "content": "//go:build !go1.20\n\npackage mapstructure\n\nimport \"reflect\"\n\nfunc isComparable(v reflect.Value) bool {\n\tk := v.Kind()\n\tswitch k {\n\tcase reflect.Invalid:\n\t\treturn false\n\n\tcase reflect.Array:\n\t\tswitch v.Type().Elem().Kind() {\n\t\tcase reflect.Interface, reflect.Array, reflect.Struct:\n\t\t\tfor i := 0; i < v.Type().Len(); i++ {\n\t\t\t\t// if !v.Index(i).Comparable() {\n\t\t\t\tif !isComparable(v.Index(i)) {\n\t\t\t\t\treturn false\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn true\n\t\t}\n\t\treturn v.Type().Comparable()\n\n\tcase reflect.Interface:\n\t\t// return v.Elem().Comparable()\n\t\treturn isComparable(v.Elem())\n\n\tcase reflect.Struct:\n\t\tfor i := 0; i < v.NumField(); i++ {\n\t\t\treturn false\n\n\t\t\t// if !v.Field(i).Comparable() {\n\t\t\tif !isComparable(v.Field(i)) {\n\t\t\t\treturn false\n\t\t\t}\n\t\t}\n\t\treturn true\n\n\tdefault:\n\t\treturn v.Type().Comparable()\n\t}\n}\n"
  },
  {
    "path": "reflect_go1_20.go",
    "content": "//go:build go1.20\n\npackage mapstructure\n\nimport \"reflect\"\n\n// TODO: remove once we drop support for Go <1.20\nfunc isComparable(v reflect.Value) bool {\n\treturn v.Comparable()\n}\n"
  }
]