github.com/goki/ki@v1.1.17/kit/convert.go (about)

     1  // Copyright (c) 2018, The GoKi Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package kit
     6  
     7  import (
     8  	"encoding/json"
     9  	"fmt"
    10  	"log"
    11  	"math"
    12  	"reflect"
    13  	"strconv"
    14  	"unicode"
    15  
    16  	"github.com/goki/ki/floats"
    17  	"github.com/goki/ki/ints"
    18  )
    19  
    20  // Sel implements the "mute" function from here
    21  // http://blog.vladimirvivien.com/2014/03/hacking-go-filter-values-from-multi.html
    22  // provides a way to select a particular return value in a single expression,
    23  // without having a separate assignment in between -- I just call it "Sel" as
    24  // I'm unlikely to remember how to type a mu
    25  func Sel(a ...any) []any {
    26  	return a
    27  }
    28  
    29  // IfaceIsNil checks if an interface value is nil -- the interface itself could be
    30  // nil, or the value pointed to by the interface could be nil -- this checks
    31  // both, safely
    32  // gopy:interface=handle
    33  func IfaceIsNil(it any) bool {
    34  	if it == nil {
    35  		return true
    36  	}
    37  	v := reflect.ValueOf(it)
    38  	vk := v.Kind()
    39  	if vk == reflect.Ptr || vk == reflect.Interface || vk == reflect.Map || vk == reflect.Slice || vk == reflect.Func || vk == reflect.Chan {
    40  		return v.IsNil()
    41  	}
    42  	return false
    43  }
    44  
    45  // KindIsBasic returns true if the reflect.Kind is a basic type such as Int, Float, etc
    46  func KindIsBasic(vk reflect.Kind) bool {
    47  	if vk >= reflect.Bool && vk <= reflect.Complex128 {
    48  		return true
    49  	}
    50  	return false
    51  }
    52  
    53  // ValueIsZero returns true if the reflect.Value is Zero or nil or invalid or
    54  // otherwise doesn't have a useful value -- from
    55  // https://github.com/golang/go/issues/7501
    56  func ValueIsZero(v reflect.Value) bool {
    57  	if !v.IsValid() {
    58  		return true
    59  	}
    60  	switch v.Kind() {
    61  	case reflect.Array, reflect.String:
    62  		return v.Len() == 0
    63  	case reflect.Bool:
    64  		return !v.Bool()
    65  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
    66  		return v.Int() == 0
    67  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
    68  		return v.Uint() == 0
    69  	case reflect.Float32, reflect.Float64:
    70  		return v.Float() == 0
    71  	case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
    72  		return v.IsNil()
    73  	case reflect.Func:
    74  		return v == reflect.Zero(v.Type())
    75  	}
    76  	return false
    77  }
    78  
    79  // Convenience functions for converting interface{} (e.g. properties) to given
    80  // types uses the "ok" bool mechanism to report failure -- are as robust and
    81  // general as possible.
    82  //
    83  // WARNING: these violate many of the type-safety features of Go but OTOH give
    84  // maximum robustness, appropriate for the world of end-user settable
    85  // properties, and deal with most common-sense cases, e.g., string <-> number,
    86  // etc.  nil values return !ok
    87  
    88  // ToBool robustly converts anything to a bool
    89  // gopy:interface=handle
    90  func ToBool(it any) (bool, bool) {
    91  	// first check for most likely cases for greatest efficiency
    92  	switch bt := it.(type) {
    93  	case bool:
    94  		return bt, true
    95  	case *bool:
    96  		return *bt, true
    97  	case int:
    98  		return bt != 0, true
    99  	case *int:
   100  		return *bt != 0, true
   101  	case int32:
   102  		return bt != 0, true
   103  	case int64:
   104  		return bt != 0, true
   105  	case byte:
   106  		return bt != 0, true
   107  	case float64:
   108  		return bt != 0, true
   109  	case *float64:
   110  		return *bt != 0, true
   111  	case float32:
   112  		return bt != 0, true
   113  	case *float32:
   114  		return *bt != 0, true
   115  	case string:
   116  		r, err := strconv.ParseBool(bt)
   117  		if err != nil {
   118  			return false, false
   119  		}
   120  		return r, true
   121  	case *string:
   122  		r, err := strconv.ParseBool(*bt)
   123  		if err != nil {
   124  			return false, false
   125  		}
   126  		return r, true
   127  	}
   128  
   129  	// then fall back on reflection
   130  	if IfaceIsNil(it) {
   131  		return false, false
   132  	}
   133  	v := NonPtrValue(reflect.ValueOf(it))
   134  	vk := v.Kind()
   135  	switch {
   136  	case vk >= reflect.Int && vk <= reflect.Int64:
   137  		return (v.Int() != 0), true
   138  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   139  		return (v.Uint() != 0), true
   140  	case vk == reflect.Bool:
   141  		return v.Bool(), true
   142  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   143  		return (v.Float() != 0.0), true
   144  	case vk >= reflect.Complex64 && vk <= reflect.Complex128:
   145  		return (real(v.Complex()) != 0.0), true
   146  	case vk == reflect.String:
   147  		r, err := strconv.ParseBool(v.String())
   148  		if err != nil {
   149  			return false, false
   150  		}
   151  		return r, true
   152  	default:
   153  		return false, false
   154  	}
   155  }
   156  
   157  // ToInt robustly converts anything to an int64 -- uses the ints.Inter ToInt
   158  // interface first if available
   159  // gopy:interface=handle
   160  func ToInt(it any) (int64, bool) {
   161  	// first check for most likely cases for greatest efficiency
   162  	switch it := it.(type) {
   163  	case bool:
   164  		if it {
   165  			return 1, true
   166  		}
   167  		return 0, true
   168  	case *bool:
   169  		if *it {
   170  			return 1, true
   171  		}
   172  		return 0, true
   173  	case int:
   174  		return int64(it), true
   175  	case *int:
   176  		return int64(*it), true
   177  	case int32:
   178  		return int64(it), true
   179  	case *int32:
   180  		return int64(*it), true
   181  	case int64:
   182  		return it, true
   183  	case *int64:
   184  		return *it, true
   185  	case byte:
   186  		return int64(it), true
   187  	case *byte:
   188  		return int64(*it), true
   189  	case float64:
   190  		return int64(it), true
   191  	case *float64:
   192  		return int64(*it), true
   193  	case float32:
   194  		return int64(it), true
   195  	case *float32:
   196  		return int64(*it), true
   197  	case string:
   198  		r, err := strconv.ParseInt(it, 0, 64)
   199  		if err != nil {
   200  			return 0, false
   201  		}
   202  		return r, true
   203  	case *string:
   204  		r, err := strconv.ParseInt(*it, 0, 64)
   205  		if err != nil {
   206  			return 0, false
   207  		}
   208  		return r, true
   209  	}
   210  
   211  	// then fall back on reflection
   212  	if IfaceIsNil(it) {
   213  		return 0, false
   214  	}
   215  	if inter, ok := it.(ints.Inter); ok {
   216  		return inter.Int(), true
   217  	}
   218  	v := NonPtrValue(reflect.ValueOf(it))
   219  	vk := v.Kind()
   220  	switch {
   221  	case vk >= reflect.Int && vk <= reflect.Int64:
   222  		return v.Int(), true
   223  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   224  		return int64(v.Uint()), true
   225  	case vk == reflect.Bool:
   226  		if v.Bool() {
   227  			return 1, true
   228  		}
   229  		return 0, true
   230  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   231  		return int64(v.Float()), true
   232  	case vk >= reflect.Complex64 && vk <= reflect.Complex128:
   233  		return int64(real(v.Complex())), true
   234  	case vk == reflect.String:
   235  		r, err := strconv.ParseInt(v.String(), 0, 64)
   236  		if err != nil {
   237  			return 0, false
   238  		}
   239  		return r, true
   240  	default:
   241  		return 0, false
   242  	}
   243  }
   244  
   245  // ToFloat robustly converts anything to a Float64 -- uses the floats.Floater Float()
   246  // interface first if available
   247  // gopy:interface=handle
   248  func ToFloat(it any) (float64, bool) {
   249  	// first check for most likely cases for greatest efficiency
   250  	switch it := it.(type) {
   251  	case bool:
   252  		if it {
   253  			return 1, true
   254  		}
   255  		return 0, true
   256  	case *bool:
   257  		if *it {
   258  			return 1, true
   259  		}
   260  		return 0, true
   261  	case int:
   262  		return float64(it), true
   263  	case *int:
   264  		return float64(*it), true
   265  	case int32:
   266  		return float64(it), true
   267  	case *int32:
   268  		return float64(*it), true
   269  	case int64:
   270  		return float64(it), true
   271  	case *int64:
   272  		return float64(*it), true
   273  	case byte:
   274  		return float64(it), true
   275  	case *byte:
   276  		return float64(*it), true
   277  	case float64:
   278  		return it, true
   279  	case *float64:
   280  		return *it, true
   281  	case float32:
   282  		return float64(it), true
   283  	case *float32:
   284  		return float64(*it), true
   285  	case string:
   286  		r, err := strconv.ParseFloat(it, 64)
   287  		if err != nil {
   288  			return 0.0, false
   289  		}
   290  		return r, true
   291  	case *string:
   292  		r, err := strconv.ParseFloat(*it, 64)
   293  		if err != nil {
   294  			return 0.0, false
   295  		}
   296  		return r, true
   297  	}
   298  
   299  	if floater, ok := it.(floats.Floater); ok {
   300  		return floater.Float(), true
   301  	}
   302  	// then fall back on reflection
   303  	if IfaceIsNil(it) {
   304  		return 0.0, false
   305  	}
   306  	v := NonPtrValue(reflect.ValueOf(it))
   307  	vk := v.Kind()
   308  	switch {
   309  	case vk >= reflect.Int && vk <= reflect.Int64:
   310  		return float64(v.Int()), true
   311  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   312  		return float64(v.Uint()), true
   313  	case vk == reflect.Bool:
   314  		if v.Bool() {
   315  			return 1.0, true
   316  		}
   317  		return 0.0, true
   318  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   319  		return v.Float(), true
   320  	case vk >= reflect.Complex64 && vk <= reflect.Complex128:
   321  		return real(v.Complex()), true
   322  	case vk == reflect.String:
   323  		r, err := strconv.ParseFloat(v.String(), 64)
   324  		if err != nil {
   325  			return 0.0, false
   326  		}
   327  		return r, true
   328  	default:
   329  		return 0.0, false
   330  	}
   331  }
   332  
   333  // ToFloat32 robustly converts anything to a Float32 -- uses the floats.Floater Float()
   334  // interface first if available
   335  // gopy:interface=handle
   336  func ToFloat32(it any) (float32, bool) {
   337  	// first check for most likely cases for greatest efficiency
   338  	switch it := it.(type) {
   339  	case bool:
   340  		if it {
   341  			return 1, true
   342  		}
   343  		return 0, true
   344  	case *bool:
   345  		if *it {
   346  			return 1, true
   347  		}
   348  		return 0, true
   349  	case int:
   350  		return float32(it), true
   351  	case *int:
   352  		return float32(*it), true
   353  	case int32:
   354  		return float32(it), true
   355  	case *int32:
   356  		return float32(*it), true
   357  	case int64:
   358  		return float32(it), true
   359  	case *int64:
   360  		return float32(*it), true
   361  	case byte:
   362  		return float32(it), true
   363  	case *byte:
   364  		return float32(*it), true
   365  	case float64:
   366  		return float32(it), true
   367  	case *float64:
   368  		return float32(*it), true
   369  	case float32:
   370  		return it, true
   371  	case *float32:
   372  		return *it, true
   373  	case string:
   374  		r, err := strconv.ParseFloat(it, 32)
   375  		if err != nil {
   376  			return 0.0, false
   377  		}
   378  		return float32(r), true
   379  	case *string:
   380  		r, err := strconv.ParseFloat(*it, 32)
   381  		if err != nil {
   382  			return 0.0, false
   383  		}
   384  		return float32(r), true
   385  	}
   386  
   387  	if floater, ok := it.(floats.Floater); ok {
   388  		return float32(floater.Float()), true
   389  	}
   390  	// then fall back on reflection
   391  	if IfaceIsNil(it) {
   392  		return float32(0.0), false
   393  	}
   394  	v := NonPtrValue(reflect.ValueOf(it))
   395  	vk := v.Kind()
   396  	switch {
   397  	case vk >= reflect.Int && vk <= reflect.Int64:
   398  		return float32(v.Int()), true
   399  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   400  		return float32(v.Uint()), true
   401  	case vk == reflect.Bool:
   402  		if v.Bool() {
   403  			return 1.0, true
   404  		}
   405  		return 0.0, true
   406  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   407  		return float32(v.Float()), true
   408  	case vk >= reflect.Complex64 && vk <= reflect.Complex128:
   409  		return float32(real(v.Complex())), true
   410  	case vk == reflect.String:
   411  		r, err := strconv.ParseFloat(v.String(), 32)
   412  		if err != nil {
   413  			return float32(0.0), false
   414  		}
   415  		return float32(r), true
   416  	default:
   417  		return float32(0.0), false
   418  	}
   419  }
   420  
   421  // ToString robustly converts anything to a String -- because Stringer is so
   422  // ubiquitous, and we fall back to fmt.Sprintf(%v) in worst case, this should
   423  // definitely work in all cases, so there is no bool return value
   424  // gopy:interface=handle
   425  func ToString(it any) string {
   426  	// first check for most likely cases for greatest efficiency
   427  	switch it := it.(type) {
   428  	case string:
   429  		return it
   430  	case *string:
   431  		return *it
   432  	case bool:
   433  		if it {
   434  			return "true"
   435  		}
   436  		return "false"
   437  	case *bool:
   438  		if *it {
   439  			return "true"
   440  		}
   441  		return "false"
   442  	case int:
   443  		return strconv.FormatInt(int64(it), 10)
   444  	case *int:
   445  		return strconv.FormatInt(int64(*it), 10)
   446  	case int32:
   447  		return strconv.FormatInt(int64(it), 10)
   448  	case *int32:
   449  		return strconv.FormatInt(int64(*it), 10)
   450  	case int64:
   451  		return strconv.FormatInt(it, 10)
   452  	case *int64:
   453  		return strconv.FormatInt(*it, 10)
   454  	case byte:
   455  		return strconv.FormatInt(int64(it), 10)
   456  	case *byte:
   457  		return strconv.FormatInt(int64(*it), 10)
   458  	case float64:
   459  		return strconv.FormatFloat(it, 'G', -1, 64)
   460  	case *float64:
   461  		return strconv.FormatFloat(*it, 'G', -1, 64)
   462  	case float32:
   463  		return strconv.FormatFloat(float64(it), 'G', -1, 32)
   464  	case *float32:
   465  		return strconv.FormatFloat(float64(*it), 'G', -1, 32)
   466  	case uintptr:
   467  		return fmt.Sprintf("%#x", uintptr(it))
   468  	case *uintptr:
   469  		return fmt.Sprintf("%#x", uintptr(*it))
   470  	}
   471  
   472  	if stringer, ok := it.(fmt.Stringer); ok {
   473  		return stringer.String()
   474  	}
   475  	if IfaceIsNil(it) {
   476  		return "nil"
   477  	}
   478  	v := NonPtrValue(reflect.ValueOf(it))
   479  	vk := v.Kind()
   480  	switch {
   481  	case vk >= reflect.Int && vk <= reflect.Int64:
   482  		return strconv.FormatInt(v.Int(), 10)
   483  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   484  		return strconv.FormatUint(v.Uint(), 10)
   485  	case vk == reflect.Bool:
   486  		return strconv.FormatBool(v.Bool())
   487  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   488  		return strconv.FormatFloat(v.Float(), 'G', -1, 64)
   489  	case vk >= reflect.Complex64 && vk <= reflect.Complex128:
   490  		cv := v.Complex()
   491  		rv := strconv.FormatFloat(real(cv), 'G', -1, 64) + "," + strconv.FormatFloat(imag(cv), 'G', -1, 64)
   492  		return rv
   493  	case vk == reflect.String:
   494  		return v.String()
   495  	case vk == reflect.Slice:
   496  		eltyp := SliceElType(it)
   497  		if eltyp.Kind() == reflect.Uint8 { // []byte
   498  			return string(it.([]byte))
   499  		}
   500  		fallthrough
   501  	default:
   502  		return fmt.Sprintf("%v", it)
   503  	}
   504  }
   505  
   506  // ToStringPrec robustly converts anything to a String using given precision
   507  // for converting floating values -- using a value like 6 truncates the
   508  // nuisance random imprecision of actual floating point values due to the
   509  // fact that they are represented with binary bits.  See ToString
   510  // for more info.
   511  // gopy:interface=handle
   512  func ToStringPrec(it any, prec int) string {
   513  	if IfaceIsNil(it) {
   514  		return "nil"
   515  	}
   516  	if stringer, ok := it.(fmt.Stringer); ok {
   517  		return stringer.String()
   518  	}
   519  	v := NonPtrValue(reflect.ValueOf(it))
   520  	vk := v.Kind()
   521  	switch {
   522  	case vk >= reflect.Int && vk <= reflect.Int64:
   523  		return strconv.FormatInt(v.Int(), 10)
   524  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   525  		return strconv.FormatUint(v.Uint(), 10)
   526  	case vk == reflect.Bool:
   527  		return strconv.FormatBool(v.Bool())
   528  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   529  		return strconv.FormatFloat(v.Float(), 'G', prec, 64)
   530  	case vk >= reflect.Complex64 && vk <= reflect.Complex128:
   531  		cv := v.Complex()
   532  		rv := strconv.FormatFloat(real(cv), 'G', prec, 64) + "," + strconv.FormatFloat(imag(cv), 'G', prec, 64)
   533  		return rv
   534  	case vk == reflect.String:
   535  		return v.String()
   536  	case vk == reflect.Slice:
   537  		eltyp := SliceElType(it)
   538  		if eltyp.Kind() == reflect.Uint8 { // []byte
   539  			return string(it.([]byte))
   540  		}
   541  		fallthrough
   542  	default:
   543  		return fmt.Sprintf("%v", it)
   544  	}
   545  }
   546  
   547  // SetRobust robustly sets the 'to' value from the 'from' value.
   548  // destination must be a pointer-to. Copies slices and maps robustly,
   549  // and can set a struct, slice or map from a JSON-formatted string from value.
   550  // gopy:interface=handle
   551  func SetRobust(to, frm any) bool {
   552  	if IfaceIsNil(to) {
   553  		return false
   554  	}
   555  	v := reflect.ValueOf(to)
   556  	vnp := NonPtrValue(v)
   557  	if !vnp.IsValid() {
   558  		return false
   559  	}
   560  	typ := vnp.Type()
   561  	vp := OnePtrValue(vnp)
   562  	vk := vnp.Kind()
   563  	if !vp.Elem().CanSet() {
   564  		log.Printf("ki.SetRobust 'to' cannot be set -- must be a variable or field, not a const or tmp or other value that cannot be set.  Value info: %v\n", vp)
   565  		return false
   566  	}
   567  	switch {
   568  	case vk >= reflect.Int && vk <= reflect.Int64:
   569  		fm, ok := ToInt(frm)
   570  		if ok {
   571  			vp.Elem().Set(reflect.ValueOf(fm).Convert(typ))
   572  			return true
   573  		}
   574  	case vk >= reflect.Uint && vk <= reflect.Uint64:
   575  		fm, ok := ToInt(frm)
   576  		if ok {
   577  			vp.Elem().Set(reflect.ValueOf(fm).Convert(typ))
   578  			return true
   579  		}
   580  	case vk == reflect.Bool:
   581  		fm, ok := ToBool(frm)
   582  		if ok {
   583  			vp.Elem().Set(reflect.ValueOf(fm).Convert(typ))
   584  			return true
   585  		}
   586  	case vk >= reflect.Float32 && vk <= reflect.Float64:
   587  		fm, ok := ToFloat(frm)
   588  		if ok {
   589  			vp.Elem().Set(reflect.ValueOf(fm).Convert(typ))
   590  			return true
   591  		}
   592  	case vk >= reflect.Complex64 && vk <= reflect.Complex128:
   593  		// cv := v.Complex()
   594  		// rv := strconv.FormatFloat(real(cv), 'G', -1, 64) + "," + strconv.FormatFloat(imag(cv), 'G', -1, 64)
   595  		// return rv, true
   596  	case vk == reflect.String: // todo: what about []byte?
   597  		fm := ToString(frm)
   598  		vp.Elem().Set(reflect.ValueOf(fm).Convert(typ))
   599  		return true
   600  	case vk == reflect.Struct:
   601  		if NonPtrType(reflect.TypeOf(frm)).Kind() == reflect.String {
   602  			err := json.Unmarshal([]byte(ToString(frm)), to) // todo: this is not working -- see what marshal says, etc
   603  			if err != nil {
   604  				marsh, _ := json.Marshal(to)
   605  				log.Println("kit.SetRobust, struct from string:", err, "for example:", string(marsh))
   606  			}
   607  			return err == nil
   608  		}
   609  	case vk == reflect.Slice:
   610  		if NonPtrType(reflect.TypeOf(frm)).Kind() == reflect.String {
   611  			err := json.Unmarshal([]byte(ToString(frm)), to)
   612  			if err != nil {
   613  				marsh, _ := json.Marshal(to)
   614  				log.Println("kit.SetRobust, slice from string:", err, "for example:", string(marsh))
   615  			}
   616  			return err == nil
   617  		}
   618  		err := CopySliceRobust(to, frm)
   619  		return err == nil
   620  	case vk == reflect.Map:
   621  		if NonPtrType(reflect.TypeOf(frm)).Kind() == reflect.String {
   622  			err := json.Unmarshal([]byte(ToString(frm)), to)
   623  			if err != nil {
   624  				marsh, _ := json.Marshal(to)
   625  				log.Println("kit.SetRobust, map from string:", err, "for example:", string(marsh))
   626  			}
   627  			return err == nil
   628  		}
   629  		err := CopyMapRobust(to, frm)
   630  		return err == nil
   631  	}
   632  
   633  	fv := reflect.ValueOf(frm)
   634  	// Just set it if possible to assign
   635  	if fv.Type().AssignableTo(typ) {
   636  		vp.Elem().Set(fv)
   637  		return true
   638  	}
   639  	return false
   640  }
   641  
   642  // SetMapRobust robustly sets a map value using reflect.Value representations
   643  // of the map, key, and value elements, ensuring that the proper types are
   644  // used for the key and value elements using sensible conversions.
   645  // map value must be a valid map value -- that is not checked.
   646  func SetMapRobust(mp, ky, val reflect.Value) bool {
   647  	mtyp := mp.Type()
   648  	if mtyp.Kind() != reflect.Map {
   649  		log.Printf("ki.SetMapRobust: map arg is not map, is: %v\n", mtyp.String())
   650  		return false
   651  	}
   652  	if !mp.CanSet() {
   653  		log.Printf("ki.SetMapRobust: map arg is not settable: %v\n", mtyp.String())
   654  		return false
   655  	}
   656  	ktyp := mtyp.Key()
   657  	etyp := mtyp.Elem()
   658  	if etyp.Kind() == val.Kind() && ky.Kind() == ktyp.Kind() {
   659  		mp.SetMapIndex(ky, val)
   660  		return true
   661  	}
   662  	if ky.Kind() == ktyp.Kind() {
   663  		mp.SetMapIndex(ky, val.Convert(etyp))
   664  		return true
   665  	}
   666  	if etyp.Kind() == val.Kind() {
   667  		mp.SetMapIndex(ky.Convert(ktyp), val)
   668  		return true
   669  	}
   670  	mp.SetMapIndex(ky.Convert(ktyp), val.Convert(etyp))
   671  	return true
   672  }
   673  
   674  // CloneToType creates a new object of given type, and uses SetRobust to copy
   675  // an existing value (of perhaps another type) into it -- only expected to
   676  // work for basic types
   677  func CloneToType(typ reflect.Type, val any) reflect.Value {
   678  	vn := reflect.New(typ)
   679  	evi := vn.Interface()
   680  	SetRobust(evi, val)
   681  	return vn
   682  }
   683  
   684  // MakeOfType creates a new object of given type with appropriate magic foo to
   685  // make it usable
   686  func MakeOfType(typ reflect.Type) reflect.Value {
   687  	if NonPtrType(typ).Kind() == reflect.Map {
   688  		return MakeMap(typ)
   689  	} else if NonPtrType(typ).Kind() == reflect.Slice {
   690  		return MakeSlice(typ, 0, 0)
   691  	}
   692  	vn := reflect.New(typ)
   693  	return vn
   694  }
   695  
   696  ////////////////////////////////////////////////////////////////////////////////////////
   697  //  Min / Max for other types..
   698  
   699  // math provides Max/Min for 64bit -- these are for specific subtypes
   700  
   701  func Max32(a, b float32) float32 {
   702  	if a > b {
   703  		return a
   704  	}
   705  	return b
   706  }
   707  
   708  func Min32(a, b float32) float32 {
   709  	if a < b {
   710  		return a
   711  	}
   712  	return b
   713  }
   714  
   715  // minimum excluding 0
   716  func MinPos(a, b float64) float64 {
   717  	if a > 0.0 && b > 0.0 {
   718  		return math.Min(a, b)
   719  	} else if a > 0.0 {
   720  		return a
   721  	} else if b > 0.0 {
   722  		return b
   723  	}
   724  	return a
   725  }
   726  
   727  // minimum excluding 0
   728  func MinPos32(a, b float32) float32 {
   729  	if a > 0.0 && b > 0.0 {
   730  		return Min32(a, b)
   731  	} else if a > 0.0 {
   732  		return a
   733  	} else if b > 0.0 {
   734  		return b
   735  	}
   736  	return a
   737  }
   738  
   739  // HasUpperCase returns true if string has an upper-case letter
   740  func HasUpperCase(str string) bool {
   741  	for _, r := range str {
   742  		if unicode.IsUpper(r) {
   743  			return true
   744  		}
   745  	}
   746  	return false
   747  }