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 }