decode_hooks.go raw

   1  package mapstructure
   2  
   3  import (
   4  	"encoding"
   5  	"errors"
   6  	"fmt"
   7  	"net"
   8  	"net/netip"
   9  	"net/url"
  10  	"reflect"
  11  	"strconv"
  12  	"strings"
  13  	"time"
  14  )
  15  
  16  // typedDecodeHook takes a raw DecodeHookFunc (an any) and turns
  17  // it into the proper DecodeHookFunc type, such as DecodeHookFuncType.
  18  func typedDecodeHook(h DecodeHookFunc) DecodeHookFunc {
  19  	// Create variables here so we can reference them with the reflect pkg
  20  	var f1 DecodeHookFuncType
  21  	var f2 DecodeHookFuncKind
  22  	var f3 DecodeHookFuncValue
  23  
  24  	// Fill in the variables into this interface and the rest is done
  25  	// automatically using the reflect package.
  26  	potential := []any{f1, f2, f3}
  27  
  28  	v := reflect.ValueOf(h)
  29  	vt := v.Type()
  30  	for _, raw := range potential {
  31  		pt := reflect.ValueOf(raw).Type()
  32  		if vt.ConvertibleTo(pt) {
  33  			return v.Convert(pt).Interface()
  34  		}
  35  	}
  36  
  37  	return nil
  38  }
  39  
  40  // cachedDecodeHook takes a raw DecodeHookFunc (an any) and turns
  41  // it into a closure to be used directly
  42  // if the type fails to convert we return a closure always erroring to keep the previous behaviour
  43  func cachedDecodeHook(raw DecodeHookFunc) func(from reflect.Value, to reflect.Value) (any, error) {
  44  	switch f := typedDecodeHook(raw).(type) {
  45  	case DecodeHookFuncType:
  46  		return func(from reflect.Value, to reflect.Value) (any, error) {
  47  			return f(from.Type(), to.Type(), from.Interface())
  48  		}
  49  	case DecodeHookFuncKind:
  50  		return func(from reflect.Value, to reflect.Value) (any, error) {
  51  			return f(from.Kind(), to.Kind(), from.Interface())
  52  		}
  53  	case DecodeHookFuncValue:
  54  		return func(from reflect.Value, to reflect.Value) (any, error) {
  55  			return f(from, to)
  56  		}
  57  	default:
  58  		return func(from reflect.Value, to reflect.Value) (any, error) {
  59  			return nil, errors.New("invalid decode hook signature")
  60  		}
  61  	}
  62  }
  63  
  64  // DecodeHookExec executes the given decode hook. This should be used
  65  // since it'll naturally degrade to the older backwards compatible DecodeHookFunc
  66  // that took reflect.Kind instead of reflect.Type.
  67  func DecodeHookExec(
  68  	raw DecodeHookFunc,
  69  	from reflect.Value, to reflect.Value,
  70  ) (any, error) {
  71  	switch f := typedDecodeHook(raw).(type) {
  72  	case DecodeHookFuncType:
  73  		return f(from.Type(), to.Type(), from.Interface())
  74  	case DecodeHookFuncKind:
  75  		return f(from.Kind(), to.Kind(), from.Interface())
  76  	case DecodeHookFuncValue:
  77  		return f(from, to)
  78  	default:
  79  		return nil, errors.New("invalid decode hook signature")
  80  	}
  81  }
  82  
  83  // ComposeDecodeHookFunc creates a single DecodeHookFunc that
  84  // automatically composes multiple DecodeHookFuncs.
  85  //
  86  // The composed funcs are called in order, with the result of the
  87  // previous transformation.
  88  func ComposeDecodeHookFunc(fs ...DecodeHookFunc) DecodeHookFunc {
  89  	cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(fs))
  90  	for _, f := range fs {
  91  		cached = append(cached, cachedDecodeHook(f))
  92  	}
  93  	return func(f reflect.Value, t reflect.Value) (any, error) {
  94  		var err error
  95  		data := f.Interface()
  96  
  97  		newFrom := f
  98  		for _, c := range cached {
  99  			data, err = c(newFrom, t)
 100  			if err != nil {
 101  				return nil, err
 102  			}
 103  			if v, ok := data.(reflect.Value); ok {
 104  				newFrom = v
 105  			} else {
 106  				newFrom = reflect.ValueOf(data)
 107  			}
 108  		}
 109  
 110  		return data, nil
 111  	}
 112  }
 113  
 114  // OrComposeDecodeHookFunc executes all input hook functions until one of them returns no error. In that case its value is returned.
 115  // If all hooks return an error, OrComposeDecodeHookFunc returns an error concatenating all error messages.
 116  func OrComposeDecodeHookFunc(ff ...DecodeHookFunc) DecodeHookFunc {
 117  	cached := make([]func(from reflect.Value, to reflect.Value) (any, error), 0, len(ff))
 118  	for _, f := range ff {
 119  		cached = append(cached, cachedDecodeHook(f))
 120  	}
 121  	return func(a, b reflect.Value) (any, error) {
 122  		var allErrs string
 123  		var out any
 124  		var err error
 125  
 126  		for _, c := range cached {
 127  			out, err = c(a, b)
 128  			if err != nil {
 129  				allErrs += err.Error() + "\n"
 130  				continue
 131  			}
 132  
 133  			return out, nil
 134  		}
 135  
 136  		return nil, errors.New(allErrs)
 137  	}
 138  }
 139  
 140  // StringToSliceHookFunc returns a DecodeHookFunc that converts
 141  // string to []string by splitting on the given sep.
 142  func StringToSliceHookFunc(sep string) DecodeHookFunc {
 143  	return func(
 144  		f reflect.Type,
 145  		t reflect.Type,
 146  		data any,
 147  	) (any, error) {
 148  		if f.Kind() != reflect.String {
 149  			return data, nil
 150  		}
 151  		if t != reflect.SliceOf(f) {
 152  			return data, nil
 153  		}
 154  
 155  		raw := data.(string)
 156  		if raw == "" {
 157  			return []string{}, nil
 158  		}
 159  
 160  		return strings.Split(raw, sep), nil
 161  	}
 162  }
 163  
 164  // StringToWeakSliceHookFunc brings back the old (pre-v2) behavior of [StringToSliceHookFunc].
 165  //
 166  // As of mapstructure v2.0.0 [StringToSliceHookFunc] checks if the return type is a string slice.
 167  // This function removes that check.
 168  func StringToWeakSliceHookFunc(sep string) DecodeHookFunc {
 169  	return func(
 170  		f reflect.Type,
 171  		t reflect.Type,
 172  		data any,
 173  	) (any, error) {
 174  		if f.Kind() != reflect.String || t.Kind() != reflect.Slice {
 175  			return data, nil
 176  		}
 177  
 178  		raw := data.(string)
 179  		if raw == "" {
 180  			return []string{}, nil
 181  		}
 182  
 183  		return strings.Split(raw, sep), nil
 184  	}
 185  }
 186  
 187  // StringToTimeDurationHookFunc returns a DecodeHookFunc that converts
 188  // strings to time.Duration.
 189  func StringToTimeDurationHookFunc() DecodeHookFunc {
 190  	return func(
 191  		f reflect.Type,
 192  		t reflect.Type,
 193  		data any,
 194  	) (any, error) {
 195  		if f.Kind() != reflect.String {
 196  			return data, nil
 197  		}
 198  		if t != reflect.TypeOf(time.Duration(5)) {
 199  			return data, nil
 200  		}
 201  
 202  		// Convert it by parsing
 203  		d, err := time.ParseDuration(data.(string))
 204  
 205  		return d, wrapTimeParseDurationError(err)
 206  	}
 207  }
 208  
 209  // StringToTimeLocationHookFunc returns a DecodeHookFunc that converts
 210  // strings to *time.Location.
 211  func StringToTimeLocationHookFunc() DecodeHookFunc {
 212  	return func(
 213  		f reflect.Type,
 214  		t reflect.Type,
 215  		data any,
 216  	) (any, error) {
 217  		if f.Kind() != reflect.String {
 218  			return data, nil
 219  		}
 220  		if t != reflect.TypeOf(time.Local) {
 221  			return data, nil
 222  		}
 223  		d, err := time.LoadLocation(data.(string))
 224  
 225  		return d, wrapTimeParseLocationError(err)
 226  	}
 227  }
 228  
 229  // StringToURLHookFunc returns a DecodeHookFunc that converts
 230  // strings to *url.URL.
 231  func StringToURLHookFunc() DecodeHookFunc {
 232  	return func(
 233  		f reflect.Type,
 234  		t reflect.Type,
 235  		data any,
 236  	) (any, error) {
 237  		if f.Kind() != reflect.String {
 238  			return data, nil
 239  		}
 240  		if t != reflect.TypeOf(&url.URL{}) {
 241  			return data, nil
 242  		}
 243  
 244  		// Convert it by parsing
 245  		u, err := url.Parse(data.(string))
 246  
 247  		return u, wrapUrlError(err)
 248  	}
 249  }
 250  
 251  // StringToIPHookFunc returns a DecodeHookFunc that converts
 252  // strings to net.IP
 253  func StringToIPHookFunc() DecodeHookFunc {
 254  	return func(
 255  		f reflect.Type,
 256  		t reflect.Type,
 257  		data any,
 258  	) (any, error) {
 259  		if f.Kind() != reflect.String {
 260  			return data, nil
 261  		}
 262  		if t != reflect.TypeOf(net.IP{}) {
 263  			return data, nil
 264  		}
 265  
 266  		// Convert it by parsing
 267  		ip := net.ParseIP(data.(string))
 268  		if ip == nil {
 269  			return net.IP{}, fmt.Errorf("failed parsing ip")
 270  		}
 271  
 272  		return ip, nil
 273  	}
 274  }
 275  
 276  // StringToIPNetHookFunc returns a DecodeHookFunc that converts
 277  // strings to net.IPNet
 278  func StringToIPNetHookFunc() DecodeHookFunc {
 279  	return func(
 280  		f reflect.Type,
 281  		t reflect.Type,
 282  		data any,
 283  	) (any, error) {
 284  		if f.Kind() != reflect.String {
 285  			return data, nil
 286  		}
 287  		if t != reflect.TypeOf(net.IPNet{}) {
 288  			return data, nil
 289  		}
 290  
 291  		// Convert it by parsing
 292  		_, net, err := net.ParseCIDR(data.(string))
 293  		return net, wrapNetParseError(err)
 294  	}
 295  }
 296  
 297  // StringToTimeHookFunc returns a DecodeHookFunc that converts
 298  // strings to time.Time.
 299  func StringToTimeHookFunc(layout string) DecodeHookFunc {
 300  	return func(
 301  		f reflect.Type,
 302  		t reflect.Type,
 303  		data any,
 304  	) (any, error) {
 305  		if f.Kind() != reflect.String {
 306  			return data, nil
 307  		}
 308  		if t != reflect.TypeOf(time.Time{}) {
 309  			return data, nil
 310  		}
 311  
 312  		// Convert it by parsing
 313  		ti, err := time.Parse(layout, data.(string))
 314  
 315  		return ti, wrapTimeParseError(err)
 316  	}
 317  }
 318  
 319  // WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to
 320  // the decoder.
 321  //
 322  // Note that this is significantly different from the WeaklyTypedInput option
 323  // of the DecoderConfig.
 324  func WeaklyTypedHook(
 325  	f reflect.Kind,
 326  	t reflect.Kind,
 327  	data any,
 328  ) (any, error) {
 329  	dataVal := reflect.ValueOf(data)
 330  	switch t {
 331  	case reflect.String:
 332  		switch f {
 333  		case reflect.Bool:
 334  			if dataVal.Bool() {
 335  				return "1", nil
 336  			}
 337  			return "0", nil
 338  		case reflect.Float32:
 339  			return strconv.FormatFloat(dataVal.Float(), 'f', -1, 64), nil
 340  		case reflect.Int:
 341  			return strconv.FormatInt(dataVal.Int(), 10), nil
 342  		case reflect.Slice:
 343  			dataType := dataVal.Type()
 344  			elemKind := dataType.Elem().Kind()
 345  			if elemKind == reflect.Uint8 {
 346  				return string(dataVal.Interface().([]uint8)), nil
 347  			}
 348  		case reflect.Uint:
 349  			return strconv.FormatUint(dataVal.Uint(), 10), nil
 350  		}
 351  	}
 352  
 353  	return data, nil
 354  }
 355  
 356  func RecursiveStructToMapHookFunc() DecodeHookFunc {
 357  	return func(f reflect.Value, t reflect.Value) (any, error) {
 358  		if f.Kind() != reflect.Struct {
 359  			return f.Interface(), nil
 360  		}
 361  
 362  		var i any = struct{}{}
 363  		if t.Type() != reflect.TypeOf(&i).Elem() {
 364  			return f.Interface(), nil
 365  		}
 366  
 367  		m := make(map[string]any)
 368  		t.Set(reflect.ValueOf(m))
 369  
 370  		return f.Interface(), nil
 371  	}
 372  }
 373  
 374  // TextUnmarshallerHookFunc returns a DecodeHookFunc that applies
 375  // strings to the UnmarshalText function, when the target type
 376  // implements the encoding.TextUnmarshaler interface
 377  func TextUnmarshallerHookFunc() DecodeHookFuncType {
 378  	return func(
 379  		f reflect.Type,
 380  		t reflect.Type,
 381  		data any,
 382  	) (any, error) {
 383  		if f.Kind() != reflect.String {
 384  			return data, nil
 385  		}
 386  		result := reflect.New(t).Interface()
 387  		unmarshaller, ok := result.(encoding.TextUnmarshaler)
 388  		if !ok {
 389  			return data, nil
 390  		}
 391  		str, ok := data.(string)
 392  		if !ok {
 393  			str = reflect.Indirect(reflect.ValueOf(&data)).Elem().String()
 394  		}
 395  		if err := unmarshaller.UnmarshalText([]byte(str)); err != nil {
 396  			return nil, err
 397  		}
 398  		return result, nil
 399  	}
 400  }
 401  
 402  // StringToNetIPAddrHookFunc returns a DecodeHookFunc that converts
 403  // strings to netip.Addr.
 404  func StringToNetIPAddrHookFunc() DecodeHookFunc {
 405  	return func(
 406  		f reflect.Type,
 407  		t reflect.Type,
 408  		data any,
 409  	) (any, error) {
 410  		if f.Kind() != reflect.String {
 411  			return data, nil
 412  		}
 413  		if t != reflect.TypeOf(netip.Addr{}) {
 414  			return data, nil
 415  		}
 416  
 417  		// Convert it by parsing
 418  		addr, err := netip.ParseAddr(data.(string))
 419  
 420  		return addr, wrapNetIPParseAddrError(err)
 421  	}
 422  }
 423  
 424  // StringToNetIPAddrPortHookFunc returns a DecodeHookFunc that converts
 425  // strings to netip.AddrPort.
 426  func StringToNetIPAddrPortHookFunc() DecodeHookFunc {
 427  	return func(
 428  		f reflect.Type,
 429  		t reflect.Type,
 430  		data any,
 431  	) (any, error) {
 432  		if f.Kind() != reflect.String {
 433  			return data, nil
 434  		}
 435  		if t != reflect.TypeOf(netip.AddrPort{}) {
 436  			return data, nil
 437  		}
 438  
 439  		// Convert it by parsing
 440  		addrPort, err := netip.ParseAddrPort(data.(string))
 441  
 442  		return addrPort, wrapNetIPParseAddrPortError(err)
 443  	}
 444  }
 445  
 446  // StringToNetIPPrefixHookFunc returns a DecodeHookFunc that converts
 447  // strings to netip.Prefix.
 448  func StringToNetIPPrefixHookFunc() DecodeHookFunc {
 449  	return func(
 450  		f reflect.Type,
 451  		t reflect.Type,
 452  		data any,
 453  	) (any, error) {
 454  		if f.Kind() != reflect.String {
 455  			return data, nil
 456  		}
 457  		if t != reflect.TypeOf(netip.Prefix{}) {
 458  			return data, nil
 459  		}
 460  
 461  		// Convert it by parsing
 462  		prefix, err := netip.ParsePrefix(data.(string))
 463  
 464  		return prefix, wrapNetIPParsePrefixError(err)
 465  	}
 466  }
 467  
 468  // StringToBasicTypeHookFunc returns a DecodeHookFunc that converts
 469  // strings to basic types.
 470  // int8, uint8, int16, uint16, int32, uint32, int64, uint64, int, uint, float32, float64, bool, byte, rune, complex64, complex128
 471  func StringToBasicTypeHookFunc() DecodeHookFunc {
 472  	return ComposeDecodeHookFunc(
 473  		StringToInt8HookFunc(),
 474  		StringToUint8HookFunc(),
 475  		StringToInt16HookFunc(),
 476  		StringToUint16HookFunc(),
 477  		StringToInt32HookFunc(),
 478  		StringToUint32HookFunc(),
 479  		StringToInt64HookFunc(),
 480  		StringToUint64HookFunc(),
 481  		StringToIntHookFunc(),
 482  		StringToUintHookFunc(),
 483  		StringToFloat32HookFunc(),
 484  		StringToFloat64HookFunc(),
 485  		StringToBoolHookFunc(),
 486  		// byte and rune are aliases for uint8 and int32 respectively
 487  		// StringToByteHookFunc(),
 488  		// StringToRuneHookFunc(),
 489  		StringToComplex64HookFunc(),
 490  		StringToComplex128HookFunc(),
 491  	)
 492  }
 493  
 494  // StringToInt8HookFunc returns a DecodeHookFunc that converts
 495  // strings to int8.
 496  func StringToInt8HookFunc() DecodeHookFunc {
 497  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 498  		if f.Kind() != reflect.String || t.Kind() != reflect.Int8 {
 499  			return data, nil
 500  		}
 501  
 502  		// Convert it by parsing
 503  		i64, err := strconv.ParseInt(data.(string), 0, 8)
 504  		return int8(i64), wrapStrconvNumError(err)
 505  	}
 506  }
 507  
 508  // StringToUint8HookFunc returns a DecodeHookFunc that converts
 509  // strings to uint8.
 510  func StringToUint8HookFunc() DecodeHookFunc {
 511  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 512  		if f.Kind() != reflect.String || t.Kind() != reflect.Uint8 {
 513  			return data, nil
 514  		}
 515  
 516  		// Convert it by parsing
 517  		u64, err := strconv.ParseUint(data.(string), 0, 8)
 518  		return uint8(u64), wrapStrconvNumError(err)
 519  	}
 520  }
 521  
 522  // StringToInt16HookFunc returns a DecodeHookFunc that converts
 523  // strings to int16.
 524  func StringToInt16HookFunc() DecodeHookFunc {
 525  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 526  		if f.Kind() != reflect.String || t.Kind() != reflect.Int16 {
 527  			return data, nil
 528  		}
 529  
 530  		// Convert it by parsing
 531  		i64, err := strconv.ParseInt(data.(string), 0, 16)
 532  		return int16(i64), wrapStrconvNumError(err)
 533  	}
 534  }
 535  
 536  // StringToUint16HookFunc returns a DecodeHookFunc that converts
 537  // strings to uint16.
 538  func StringToUint16HookFunc() DecodeHookFunc {
 539  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 540  		if f.Kind() != reflect.String || t.Kind() != reflect.Uint16 {
 541  			return data, nil
 542  		}
 543  
 544  		// Convert it by parsing
 545  		u64, err := strconv.ParseUint(data.(string), 0, 16)
 546  		return uint16(u64), wrapStrconvNumError(err)
 547  	}
 548  }
 549  
 550  // StringToInt32HookFunc returns a DecodeHookFunc that converts
 551  // strings to int32.
 552  func StringToInt32HookFunc() DecodeHookFunc {
 553  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 554  		if f.Kind() != reflect.String || t.Kind() != reflect.Int32 {
 555  			return data, nil
 556  		}
 557  
 558  		// Convert it by parsing
 559  		i64, err := strconv.ParseInt(data.(string), 0, 32)
 560  		return int32(i64), wrapStrconvNumError(err)
 561  	}
 562  }
 563  
 564  // StringToUint32HookFunc returns a DecodeHookFunc that converts
 565  // strings to uint32.
 566  func StringToUint32HookFunc() DecodeHookFunc {
 567  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 568  		if f.Kind() != reflect.String || t.Kind() != reflect.Uint32 {
 569  			return data, nil
 570  		}
 571  
 572  		// Convert it by parsing
 573  		u64, err := strconv.ParseUint(data.(string), 0, 32)
 574  		return uint32(u64), wrapStrconvNumError(err)
 575  	}
 576  }
 577  
 578  // StringToInt64HookFunc returns a DecodeHookFunc that converts
 579  // strings to int64.
 580  func StringToInt64HookFunc() DecodeHookFunc {
 581  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 582  		if f.Kind() != reflect.String || t.Kind() != reflect.Int64 {
 583  			return data, nil
 584  		}
 585  
 586  		// Convert it by parsing
 587  		i64, err := strconv.ParseInt(data.(string), 0, 64)
 588  		return int64(i64), wrapStrconvNumError(err)
 589  	}
 590  }
 591  
 592  // StringToUint64HookFunc returns a DecodeHookFunc that converts
 593  // strings to uint64.
 594  func StringToUint64HookFunc() DecodeHookFunc {
 595  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 596  		if f.Kind() != reflect.String || t.Kind() != reflect.Uint64 {
 597  			return data, nil
 598  		}
 599  
 600  		// Convert it by parsing
 601  		u64, err := strconv.ParseUint(data.(string), 0, 64)
 602  		return uint64(u64), wrapStrconvNumError(err)
 603  	}
 604  }
 605  
 606  // StringToIntHookFunc returns a DecodeHookFunc that converts
 607  // strings to int.
 608  func StringToIntHookFunc() DecodeHookFunc {
 609  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 610  		if f.Kind() != reflect.String || t.Kind() != reflect.Int {
 611  			return data, nil
 612  		}
 613  
 614  		// Convert it by parsing
 615  		i64, err := strconv.ParseInt(data.(string), 0, 0)
 616  		return int(i64), wrapStrconvNumError(err)
 617  	}
 618  }
 619  
 620  // StringToUintHookFunc returns a DecodeHookFunc that converts
 621  // strings to uint.
 622  func StringToUintHookFunc() DecodeHookFunc {
 623  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 624  		if f.Kind() != reflect.String || t.Kind() != reflect.Uint {
 625  			return data, nil
 626  		}
 627  
 628  		// Convert it by parsing
 629  		u64, err := strconv.ParseUint(data.(string), 0, 0)
 630  		return uint(u64), wrapStrconvNumError(err)
 631  	}
 632  }
 633  
 634  // StringToFloat32HookFunc returns a DecodeHookFunc that converts
 635  // strings to float32.
 636  func StringToFloat32HookFunc() DecodeHookFunc {
 637  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 638  		if f.Kind() != reflect.String || t.Kind() != reflect.Float32 {
 639  			return data, nil
 640  		}
 641  
 642  		// Convert it by parsing
 643  		f64, err := strconv.ParseFloat(data.(string), 32)
 644  		return float32(f64), wrapStrconvNumError(err)
 645  	}
 646  }
 647  
 648  // StringToFloat64HookFunc returns a DecodeHookFunc that converts
 649  // strings to float64.
 650  func StringToFloat64HookFunc() DecodeHookFunc {
 651  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 652  		if f.Kind() != reflect.String || t.Kind() != reflect.Float64 {
 653  			return data, nil
 654  		}
 655  
 656  		// Convert it by parsing
 657  		f64, err := strconv.ParseFloat(data.(string), 64)
 658  		return f64, wrapStrconvNumError(err)
 659  	}
 660  }
 661  
 662  // StringToBoolHookFunc returns a DecodeHookFunc that converts
 663  // strings to bool.
 664  func StringToBoolHookFunc() DecodeHookFunc {
 665  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 666  		if f.Kind() != reflect.String || t.Kind() != reflect.Bool {
 667  			return data, nil
 668  		}
 669  
 670  		// Convert it by parsing
 671  		b, err := strconv.ParseBool(data.(string))
 672  		return b, wrapStrconvNumError(err)
 673  	}
 674  }
 675  
 676  // StringToByteHookFunc returns a DecodeHookFunc that converts
 677  // strings to byte.
 678  func StringToByteHookFunc() DecodeHookFunc {
 679  	return StringToUint8HookFunc()
 680  }
 681  
 682  // StringToRuneHookFunc returns a DecodeHookFunc that converts
 683  // strings to rune.
 684  func StringToRuneHookFunc() DecodeHookFunc {
 685  	return StringToInt32HookFunc()
 686  }
 687  
 688  // StringToComplex64HookFunc returns a DecodeHookFunc that converts
 689  // strings to complex64.
 690  func StringToComplex64HookFunc() DecodeHookFunc {
 691  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 692  		if f.Kind() != reflect.String || t.Kind() != reflect.Complex64 {
 693  			return data, nil
 694  		}
 695  
 696  		// Convert it by parsing
 697  		c128, err := strconv.ParseComplex(data.(string), 64)
 698  		return complex64(c128), wrapStrconvNumError(err)
 699  	}
 700  }
 701  
 702  // StringToComplex128HookFunc returns a DecodeHookFunc that converts
 703  // strings to complex128.
 704  func StringToComplex128HookFunc() DecodeHookFunc {
 705  	return func(f reflect.Type, t reflect.Type, data any) (any, error) {
 706  		if f.Kind() != reflect.String || t.Kind() != reflect.Complex128 {
 707  			return data, nil
 708  		}
 709  
 710  		// Convert it by parsing
 711  		c128, err := strconv.ParseComplex(data.(string), 128)
 712  		return c128, wrapStrconvNumError(err)
 713  	}
 714  }
 715